Skip to content

feat(cli): add mm upgrade for kill-then-reinstall hygiene (#443)#530

Merged
memtomem merged 3 commits intomainfrom
feat/mm-upgrade
Apr 28, 2026
Merged

feat(cli): add mm upgrade for kill-then-reinstall hygiene (#443)#530
memtomem merged 3 commits intomainfrom
feat/mm-upgrade

Conversation

@memtomem
Copy link
Copy Markdown
Owner

Summary

  • New mm upgrade command: probe live server → SIGTERM (escalate to SIGKILL after --grace) → unlink stale pid file → uv tool install --refresh --reinstall memtomem. Closes cli: add mm upgrade to stop running server before reinstall (hygiene wrapper) #443.
  • Liveness helpers extracted from uninstall_cmd.py into a new cli/_liveness.py so both commands share one probe; existing uninstall behavior is unchanged (32 tests still pass).
  • No --skip-pkill opt-out — kill-then-reinstall is the whole reason the command exists. Windows auto-skips the kill stage (no fcntl/signals) and warns.

Why

uv tool install --reinstall memtomem only swaps the on-disk bytes. Any memtomem-server already imported by an MCP client (Claude Code keeps the server alive across prompts) keeps running the previous version until it exits, producing a split-brain where pre-upgrade teardown bugs leak alongside the freshly written disk code. That's exactly the v0.1.25 → v0.1.26 stale .server.pid repro that motivated issue #443.

Surface

mm upgrade [--version X.Y.Z] [--grace SECONDS] [-y/--yes] [--json] [--dry-run]
  • --version pins a release; default is latest on the configured index.
  • --grace (default 5s) is the SIGTERM → SIGKILL window.
  • --dry-run prints the plan without killing or installing.
  • --json emits {ok, killed, removed, reinstalled, version} (or {ok:false, error,…}).

Test plan

  • pytest packages/memtomem/tests/test_upgrade_cmd.py — 9 new tests (no-running-server / SIGTERM / SIGKILL escalation / Windows-skips-kill / version pin / uv failure / dry-run / json shape / non-TTY-no-yes)
  • pytest packages/memtomem/tests/test_uninstall_cmd.py — all 32 existing tests still pass after liveness helper extraction
  • pytest packages/memtomem/tests/ -m "not ollama" — 3010 pass
  • ruff check && ruff format --check clean repo-wide
  • uv run mm upgrade --help / --dry-run smoke (detects real running server, prints plan)
  • Reviewer: manual end-to-end on a worktree (start mm web, run mm upgrade --dry-run, then mm upgrade --yes --grace 3 and verify the pid file is gone and a fresh server spawns clean)

🤖 Generated with Claude Code

pandas-studio and others added 3 commits April 28, 2026 15:07
`uv tool install --reinstall memtomem` only swaps the on-disk bytes;
any `memtomem-server` already imported by an MCP client keeps running
the previous version until it exits. That split-brain is what produced
the v0.1.25 → v0.1.26 stale `.server.pid` repro behind issue #443.

`mm upgrade` wraps the reinstall with the missing process-level
hygiene: probe the server pid lock, send SIGTERM, escalate to SIGKILL
after `--grace` seconds, unlink the stale pid file, then run
`uv tool install --refresh --reinstall memtomem`. `--version` pins a
release, `--dry-run` previews the plan, `--json` emits a structured
result. On Windows the kill stage is skipped automatically (POSIX
advisory flock + signals are unavailable) and the user is told to stop
the server manually if a split-brain shows up.

The kill-then-reinstall ordering is the whole reason the command
exists, so there is no `--skip-pkill` opt-out — advanced users who
manage lifecycle elsewhere can keep calling `uv tool install` directly.

Liveness helpers move from `uninstall_cmd.py` to a new
`cli/_liveness.py` so both commands share one probe; the existing
uninstall test suite (32 cases) stays green to confirm behavior is
unchanged.

Co-Authored-By: Claude <[email protected]>
…eview)

Address review feedback on PR #530:

- **Extras preserved across reinstall** (review issue 1, blocking).
  ``uv tool install --reinstall memtomem`` silently drops extras, so
  ``mm upgrade`` was regressing every ``memtomem[all]`` install down
  to BM25-only. ``_detect_installed_extras()`` now reads
  ``<uv tool dir>/memtomem/uv-receipt.toml`` and re-passes the same
  ``extras`` list on the reinstall command line. Override with
  ``--extras onnx,web`` or suppress with ``--extras none``.
- **Re-probe before pid-file unlink** (review issue 3). After the
  SIGKILL settle window an MCP client could respawn a fresh server at
  the same pid path; we'd then delete its lockfile. ``_stop_server``
  now calls ``probe_pid_file`` immediately before unlink and skips +
  warns when a live writer is detected.
- **Drop ``while/else`` for SIGKILL escalation** (review issue 4) —
  flatten to a separate ``if`` so the control flow reads linearly.
- **Cancel exits 0 with consistent JSON shape** (review issue 5).
  Voluntary ``click.confirm`` decline now returns 0 (was 1) and emits
  ``{ok:true, cancelled:true}`` under ``--json``.
- **Stale comment fix** (review issue 2) — ``_ServerState`` is no
  longer aliased in ``uninstall_cmd.py`` so the comment now lists only
  the symbols actually re-imported.

Adds 6 tests covering extras auto-detect / flag override / ``none`` /
version+extras combo, the unlink-skip-on-respawn race, and the cancel
exit-zero JSON shape.

Co-Authored-By: Claude <[email protected]>
…review)

Final review nit (issue 6). ``mm upgrade --version >=0.1.30`` would
compose to ``memtomem==>=0.1.30`` and uv rejects it with a noisy parser
error. Validate against a bare PEP 440 release pattern up front and
emit a friendly ``BadParameter`` instead. Pre/post/dev/local versions
(``0.1.30rc1``, ``0.1.30.post1``, ``0.1.30+local``) stay allowed.

Co-Authored-By: Claude <[email protected]>
@memtomem memtomem merged commit dd5ab8f into main Apr 28, 2026
7 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 28, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cli: add mm upgrade to stop running server before reinstall (hygiene wrapper)

2 participants