feat(install): same-version replace path for every emitted installer (#400) - #420
Conversation
🦋 Changeset detectedLatest commit: 05a826b The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e034b02f93
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
commit: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f6d03a04ce
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…eset (#400) - Refuse any owned or incoming path whose ancestor directory is a symlink before hashing or writing (development installs re-point top-level dirs). - Decide unowned-file collisions by inode identity so a case-only rename of an owned path is not a collision on case-insensitive filesystems. - Standalone install.mjs validates the full receipt shape like the core reader. - Changeset: patch (pre-1.0 features are patch), summary ends with (#420).
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6101a31658
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c1b6c3faa0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0f5ea07d79
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a3fda8c1fd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a398f5174d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 41e9096635
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: abf888aa64
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a3dd5f3845
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ab2f91f9ed
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: abfdcba1f9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c49a42678c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 650830e506
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…O receipts, state-claiming receipts, doctor scope rows (#400)
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a07303293c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…y those are pruned (#400)
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9bf12701a7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…d, hashed, or owned (#400)
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 92736f707d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fa611bbf8f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ec29c9780f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a56791eecd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
|
Codex Review: Didn't find any major issues. You're on a roll. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
main (#420) adds --replace/--force to every emitted installer, automatic same-version replacement, Cursor install receipts, and Doctor's current / stale / version-mismatch / foreign / not-installed verdicts. main (#425) reports every canonical component kind from inspect and exports AgentComponentKind and componentKindCapability from agent-bundle/api. The CLI reference, installation guide, and API overview cover both, in both locales.
Summary
Closes #400. Rebuilding a plugin without bumping
versionand re-running the emitted installers used to fail (Refusing content collision at ~/.cursor/plugins/local/<name>) or silently leave a stale copy (Claude'splugin updateis version-gated). Every installer now shares one host-agnostic replace policy in the install core:--replace(alias--force) onagent-bundle install <host>, the package-relative installer bin, and the emitted standaloneinstall.mjs.already-installedno-op that says so, even with--replace..agent-bundle-install.json: plugin, version, host, content hash, installedAt, owned file list) written beside the plugin manifest for Cursor copies. Cursor replacement is in place and touches owned files only — stale owned files removed, staged files renamed over predecessors, receipt written last — so unowned entries such as workspace-durablestate/stores survive.claude plugin uninstall <id> --scope <scope> --keep-databeforemarketplace add+install(verified against a realclaude2.1.x: re-installandmarketplace update+updateboth leave the cache stale; uninstall + install refreshes it). Codex:codex plugin removebeforeaddso removed files do not linger. Both are located through the host's ownplugin list --json; an unusable inventory keeps plain install behaviour and fails--replaceclosed rather than guessing.AB7005), now with an installed-versus-artifact content-hash comparison (installed <name>@<v> content <hash> vs artifact <name>@<v> content <hash> (same version, different content)), even with--replace. A pre-receipt legacy copy (emittedINSTALL.md+install.mjs, matching manifest name) needs--replaceonce to be adopted.agent-bundle doctor --fromreports per host the installed version + content hash vs the built artifact ascurrent,stale (same version, different content)(AB7308),version-mismatch(AB7309),foreign(newAB7321),not-installed(AB7307), orunknown; Claude and Codex comparisons use the sameplugin list --jsoninventory.INSTALL.mddocuments the reinstall recipe per host, including Claude's version-gatedplugin update.Concurrency note (#407): the change lives in the host-agnostic core (
install/receipt.tsnew,install/install.ts,install/doctor.ts,install-entry.ts,install/surface.ts,cli.ts); Cursor-specific code is touched only where the collision guard already lived. No overlap with the four commits that landed on main during this lane (rebased cleanly).Evidence
Real-CLI experiment (isolated
CLAUDE_CONFIG_DIR/CODEX_HOME) reproducing the issue and confirming the recipe:marketplace add ./→ "already on disk";plugin install→ "already installed (scope: user)";marketplace update+plugin update→ "already at the latest version (1.0.0)" with the cache still at v1.plugin uninstall … --keep-data+plugin install→ cache at v2.plugin addre-copies on re-add (does not delete removed files);plugin remove+addyields a clean copy.codex plugin list --jsonreturns{ installed: [{ pluginId, version, installed, … }] }(0.147.0).Gates (worktree, logs under
/tmp/lane-400/):pnpm typecheck✅,pnpm lint✅ (0 errors, 1047 files)pnpm test:unit✅ 2738 passed / 5 skipped (a second run hit twoEvent runtime endpoint already has a live servercollisions inevent-ipc/inspect-statefrom concurrent lanes sharing/tmp; both pass in isolation)pnpm test:route-unit✅ (one 5 s timeout inlifecycle-replayon the loaded machine; passes in isolation, unrelated to install)pnpm test:projection✅ 66/66pnpm build && pnpm test:integration:run✅ 946 passed / 32 skipped after updating thecli.test.tsinstall-dispatch expectation (replace: false)pnpm build && pnpm test:host-install✅ 19 passed / 2 pre-existing opt-in skips — includes the new same-version rebuild round trip against realclaude,codex, Cursor home, and portableinstall.mjs(replaced→ cache carries the new file →already-installed)pnpm test:host-install:packed:build✅ 3/3 (same round trip through the packed tarball installer)Test plan
tests/install.test.ts: receipt written on install; identical rerun no-op; receipt-managed same-version drift replaced in place leaving only owned files (+state/and operator files preserved, stale owned file removed, empty dir pruned); legacy pre-receipt copy refused with hash comparison then adopted by--replace; foreign directory refused even with--replace(hand-made dir and another plugin's receipt); version collision gated behind--replace; Claude auto-replace sequence (list→uninstall --keep-data→marketplace add→install) and identical no-op; Codex plain vs--replace(remove+add) and fail-closed on unusable inventory; CLI--forceparsed toreplace: true.tests/doctor.test.ts: Cursornot-installed/current/stale(receipt and legacy, with recovery text) /foreign(AB7321) with both hashes; Claudenot-installed/current/stale/version-mismatchfromplugin list --jsonrows; Codexunknown(AB7313) when inventory unusable,missing/installed+stalewhen usable; pinned command lists updated (read-onlyplugin list --jsononly).tests/install-surface.test.ts: INSTALL.md recipes per host; emittedinstall.mjsexecuted against a fake home:--help, unknown arg, install, no-op, forced no-op, owned-only replace preservingstate/, legacy gate +--forceadoption, foreign refusal; receipt byte-compatible with the core reader.tests/installer-entry.test.ts: usage string,--replaceand--forceparsed, auto-replace through the packaged bin, unknown flag rejected.tests/support/host-install.ts+ proof tests: same-version rebuild round trip for Claude, Codex, Cursor, portable (source and packed).packages/agent-bundle/README.md(install/doctor, "Reinstall after a same-version rebuild"),docs/framework-mode.md,docs/diagnostics.md(receipt format, policy matrix,AB7005, newAB7321), changeset.changeset/400-install-replace.md(minor).