Repository navigation
fix(installer): upgrade over any earlier install without --force - #31
Merged
Merged
Conversation
Re-running the installer after any change raised FileExistsError, after part of the install had been written, and neither hosted one-liner passes --force. Even with --force, `ix mcp install` ran without it, unbounded and unchecked, so a 2.4.1 `ix-memory` entry pointing at the deleted mcp/server.py was never replaced. The installer now plans every change, checks it, stages the new files beside their destinations and swaps them in together, restoring the previous files if any swap fails: - files the plugin owns are overwritten, and ones it no longer ships are removed; ownership is recorded in ix-plugin-version.json (`files`), with the historical file list for installs that predate it. The plugin tree is replaced whole, so dropped skills go too. - hooks.json is merged: plugin handlers from any version (`-lc`, `-c`, `Bash` matchers, the 2.4.x Windows launcher form) are replaced where the first one was, and every other hook is kept in place. - the marketplace entry is replaced when it points at the plugin's own path; another ix-memory entry still needs --force. - `ix mcp install --host codex --format json` runs with a timeout; its exit status and per-host outcome are reported as warnings, never a crash. A registration of the old mcp/server.py is replaced with --force (or, for a CLI without it, by rewriting that one table in a checked copy of config.toml), and the old server files are removed once nothing launches them. - the pre-2.4.2 /tmp/ix-codex-hooks cache is removed when it is the user's own and holds only cache files. - the hook-trust notice is printed only when hooks.json changed. Windows: Codex 0.155 runs hook commands through the session shell, which on Windows is `powershell.exe -NoProfile -Command`. The 2.4.x command `"python" "launcher" name` is a parse error there. Each hook now gets a `commandWindows` of `& '<python>' '<launcher>' <name>`, and `command` keeps the POSIX form. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Re-running the installer over an earlier version crashed. Reproduced by installing 2.4.2 into a temp HOME, then running main's installer:
None of the hosted one-line installers pass
--force, so upgrading meant a traceback with some files already written.Related problems:
ix mcp install --host codexran without--force, with no timeout, and its exit code was ignored. So a pre-feat(mcp): serve tools from the Ix CLI instead of shipping a server #24ix-memoryregistration pointing at the deletedmcp/server.pywas never replaced./tmp/ix-codex-hookscache was never cleaned up.powershell.exe -NoProfile -Command, where the hook command"python" "launcher" nameis a parse error.What changes
fileslist inix-plugin-version.json; installs without the list are matched against the names earlier versions shipped.hooks.jsonis merged, not copied. Old plugin entries (-lc,Bash-only matchers, the 2.4.x Windows form) are replaced in place, other tools' hooks keep their positions, and nothing is duplicated. The hook-trust notice prints only whenhooks.jsonactually changed.ix-memoryentry still needs--force.ix mcp install --host codex --format jsonwith a 120s timeout. The exit code and the per-host outcome are reported; the real CLI exits 0 on a conflict, so the JSON outcome is what catches it.mcp/server.pyregistration gets--force(available since ix 0.9.3, the minimum). If--forceis ever rejected, the[mcp_servers.ix-memory]table is rewritten in a checked copy ofconfig.toml.ix-memoryis left alone unless--forceis passed..codex/mcp/*.pyfiles are deleted only once the config no longer namesmcp/server.py.$TMPDIR/ix-codex-hooksis removed only if it belongs to the user, is not a symlink, and holds only the old cache files.codex_hooks:config.tomlis left alone; a leftovercodex_hooksflag gets a hint that it can be deleted.commandWindowsof& '<python>' '<launcher>' <name>, andcommandkeeps the POSIX form.Tests
unittest: 112 → 135 (1 Windows-only skip). The new
tests/test_installer_upgrade.py(23 tests) covers:mcp/server.pyregistration,codex_hooksflag,-lchooks, a dropped hook file);ixmissing, andix mcp installfailing or timing out;20 of them fail on main for the intended reason; the other 3 are guards that pass there by design.
test-local.sh, the header check and shellcheck pass.Against the real CLI, only
ix mcp install --dry-runwas run, against a tempCODEX_HOME.Not verified
&is invalid.🤖 Generated with Claude Code