update skill, in-place install and update admission gate; resume starts the monitor (Issue #72) #75

Merged
Godopu merged 16 commits from fix/issue-72 into main 2026-10-27 22:50:05 +00:00
3 changed files with 29 additions and 2 deletions
Showing only changes of commit 454b77215f - Show all commits

No files matched your search

@@ -27,4 +27,4 @@ bash .agents/skills/multi-agent-mux-update/scripts/update.sh --yes
| Monitor | stopped first, started again afterwards only if it ran (`MAM_NO_SUBSCRIBER_DAEMON=1`: not started). | | Monitor | stopped first, started again afterwards only if it ran (`MAM_NO_SUBSCRIBER_DAEMON=1`: not started). |
| Install | the installer at `MAM_INSTALLER_URL` (default: Gitea `main`) runs in place; `.mam` is kept. On failure `.agents/`, `.mam_deploy/`, root files, `.venv`, the installer's `.mam` files and the registry are restored from `.mam/update-backup/`. | | Install | the installer at `MAM_INSTALLER_URL` (default: Gitea `main`) runs in place; `.mam` is kept. On failure `.agents/`, `.mam_deploy/`, root files, `.venv`, the installer's `.mam` files and the registry are restored from `.mam/update-backup/`. |
| Registry | converted by the new code (`lib_py.registry_format`); a failed conversion keeps the install and exits nonzero. | | Registry | converted by the new code (`lib_py.registry_format`); a failed conversion keeps the install and exits nonzero. |
| Exit | `0` updated, `1` refused or failed, `2` bad arguments. | | Exit | `0` updated (or cancelled at the prompt), `1` refused or failed, `2` bad arguments; a failed registry conversion after a good install exits with the converter's nonzero code. |
@@ -81,7 +81,14 @@ MON="${3:-0}"
TMPD="${4:-}" TMPD="${4:-}"
trap '[ -z "$TMPD" ] || rm -rf "$TMPD"' EXIT trap '[ -z "$TMPD" ] || rm -rf "$TMPD"' EXIT
set_state installing || { echo "ERROR: cannot write $BK/state" >&2; release_marker; exit 1; } if ! set_state installing; then
# Nothing was installed yet: drop the backup and put the monitor back as phase 1 found it.
echo "ERROR: cannot write $BK/state; nothing was changed" >&2
rm -rf "$BK"
restart_old_monitor "$MON"
release_marker
exit 1
fi
URL="${MAM_INSTALLER_URL:-https://git.godopu.com/tmpl/multi-agent-mux/raw/branch/main/deploy/install.sh}" URL="${MAM_INSTALLER_URL:-https://git.godopu.com/tmpl/multi-agent-mux/raw/branch/main/deploy/install.sh}"
echo "install: $URL" echo "install: $URL"
irc=0 irc=0
+20
View File
@@ -702,6 +702,26 @@ def test_leftover_whose_restore_fails_is_kept_and_nothing_more_changes(box):
assert not (box.mam / "update-in-progress").exists() assert not (box.mam / "update-in-progress").exists()
def test_a_state_write_failure_before_the_install_changes_nothing_and_restarts_the_monitor(box):
real_mv = shutil.which("mv")
fake = box.bin / "mv"
fake.write_text("#!/usr/bin/env bash\n"
"src=\"${@: -2:1}\"\n"
"case \"$src\" in */update-backup/state.tmp) grep -qx installing \"$src\" && exit 1 ;; esac\n"
"exec %s \"$@\"\n" % real_mv)
fake.chmod(0o755)
box.stub_monitor()
box.start_monitor()
box.installer("touch \"$ws/INSTALLER-RAN\"\n")
res = box.update()
assert res.returncode == 1, res.stdout + res.stderr
assert not (box.ws / "INSTALLER-RAN").exists()
assert box.monitor_starts() == 2, "the monitor it stopped is started again"
_until(lambda: bool(box.monitor_pids()))
assert not (box.mam / "update-backup").exists() and not (box.mam / "update-in-progress").exists()
assert "nothing was changed" in res.stderr
def test_the_backup_lives_in_the_workspace_and_is_gone_after_success(box): def test_the_backup_lives_in_the_workspace_and_is_gone_after_success(box):
box.installer("test -f \"$ws/.mam/update-backup/state\" && grep -qx installing \"$ws/.mam/update-backup/state\" " box.installer("test -f \"$ws/.mam/update-backup/state\" && grep -qx installing \"$ws/.mam/update-backup/state\" "
"&& test -f \"$ws/.mam/update-backup/files/.agents/skills/lib.sh\" && touch \"$ws/../saw-backup\"\n") "&& test -f \"$ws/.mam/update-backup/files/.agents/skills/lib.sh\" && touch \"$ws/../saw-backup\"\n")