fix(cli): install pinned iii to private dir, fall back on PATH mismatch#774
Conversation
Reported in #752: fresh global install of @agentmemory/agentmemory on a box that already has iii-engine v0.16.1 on PATH refuses to boot because agentmemory hard-pins v0.11.2. The downgrade hint tells the user to overwrite their global iii install with v0.11.2, but the v0.11.2 release ships only the 'iii' binary so any consumer of 'iii-init' / 'iii-worker' breaks. AGENTMEMORY_III_VERSION=0.16.1 boots cleanly per the reporter, but agentmemory's pin doesn't follow. This change isolates agentmemory's pinned engine from the user's PATH. Install location: ~/.agentmemory/bin/iii (was: ~/.local/bin/iii) Fallback order: private -> PATH -> ~/.local/bin -> /usr/local/bin PATH mismatch: auto-install pinned to private (was: exit 1) Help / prompts: point at the new private path Behavior: - pickCompatibleIii walks candidate iii paths and returns the first one whose --version matches IIPINNED_VERSION, or null if none match. - When PATH iii mismatches the pin AND the private install doesn't exist, startEngine auto-installs to ~/.agentmemory/bin without prompting (the user's existing iii stays untouched). - The 'attach to running engine' code still hard-fails if the running engine reports a wrong version — we can't reinstall under it without killing it. The error message now points at the private-install fix path instead of a manual curl. - agentmemory remove now plans cleanup of BOTH ~/.agentmemory/bin/iii (always safe, agentmemory owns it) and ~/.local/bin/iii (legacy, version-gated so a user-managed install isn't deleted). iii-sdk and engine version pins both stay at 0.11.2. Closes #752.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughMoves iii-engine handling to a private ~/.agentmemory/bin install, adds a version-compatibility resolver to pick or install the pinned engine, persists chosen binPath in EngineState, and updates removal, diagnostics, and interactive prompts to distinguish legacy vs private installs. ChangesPrivate install directory and version-mismatch handling
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/cli.ts (1)
2636-2639:⚠️ Potential issue | 🟠 Major | ⚡ Quick winProbe the legacy path here, not the back-compat alias.
localBinIii()now aliases the private install path, butbuildRemovePlan()still interpretslocalBinIiiVersionas the version of legacy~/.local/bin/iii. With both binaries present,agentmemory remove --forcecan classify a user-managed legacy binary as "matches pinned" just because the private copy does. UselegacyLocalBinIii(home)for this probe.Suggested fix
import { buildRemovePlan, formatPlan, - localBinIii, + legacyLocalBinIii, type ConnectManifest, type RemoveOptions, } from "./cli/remove-plan.js"; function probeLocalBinIiiVersion(home: string): string | null { - const path = localBinIii(home); + const path = legacyLocalBinIii(home); if (!existsSync(path)) return null; return iiiBinVersion(path); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/cli.ts` around lines 2636 - 2639, The probe currently uses localBinIii(home) which points to the private/alias path; change probeLocalBinIiiVersion to call legacyLocalBinIii(home) instead so it checks the true legacy ~/.local/bin/iii location (this prevents buildRemovePlan from misclassifying a legacy binary when a private copy exists). Update the function probeLocalBinIiiVersion to compute path = legacyLocalBinIii(home), keep the existsSync check and return iiiBinVersion(path) as before so buildRemovePlan sees the legacy binary version.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/cli.ts`:
- Around line 1132-1147: The current check uses whichBinary("iii") before
consulting any persisted engine state, causing false failures when PATH points
to a different global binary; update this logic to first read the persisted
launch info from engine-state.json (the field that stores the actual launched
binary path and version), and if present use that persisted path/version to
compute detected via iiiBinVersion instead of whichBinary/fallbackIiiPaths; only
fall back to whichBinary("iii") or fallbackIiiPaths().find(p => existsSync(p))
when engine-state.json has no valid launch entry, then compare detected against
IIPINNED_VERSION and emit the same processLogger.error/process.exit(1) behavior
if they differ (retain VERSION in the message).
- Around line 419-423: resolveCompatibleIii currently treats a failed or
timed-out iiiBinVersion probe as compatible by returning iiiBinPath when
detected is falsy; change the logic so that only a successful version match
returns iiiBinPath. In the function resolveCompatibleIii, call
iiiBinVersion(iiiBinPath) and return iiiBinPath only if detected is truthy AND
detected === IIPINNED_VERSION; if detected is falsy or doesn't match
IIPINNED_VERSION, return null so the auto-install path is not suppressed.
In `@src/cli/remove-plan.ts`:
- Around line 95-106: The path helper functions legacyLocalBinIii, privateIiiBin
(and the alias localBinIii) currently always return "iii" which breaks Windows;
update these functions to be platform-aware by appending ".exe" when running on
Windows (use process.platform === "win32" or os.platform()), so they return
"iii.exe" on Windows and "iii" on other platforms; keep the same function names
and return type, only change the final filename component construction to
conditionally include the ".exe" suffix.
---
Outside diff comments:
In `@src/cli.ts`:
- Around line 2636-2639: The probe currently uses localBinIii(home) which points
to the private/alias path; change probeLocalBinIiiVersion to call
legacyLocalBinIii(home) instead so it checks the true legacy ~/.local/bin/iii
location (this prevents buildRemovePlan from misclassifying a legacy binary when
a private copy exists). Update the function probeLocalBinIiiVersion to compute
path = legacyLocalBinIii(home), keep the existsSync check and return
iiiBinVersion(path) as before so buildRemovePlan sees the legacy binary version.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: ff0c31b6-c157-420c-801c-c885362cdcea
📒 Files selected for processing (4)
src/cli.tssrc/cli/doctor-diagnostics.tssrc/cli/remove-plan.tstest/cli-remove.test.ts
- Attach path: read launched iii bin from engine-state.json before falling back to whichBinary/fallbackIiiPaths. Persist binPath in writeEngineState. Avoids false failures when PATH iii changed after the engine was started. - resolveCompatibleIii: a failed iiiBinVersion probe (null) was treated as compatible. Require a positive match (detected === IIPINNED_VERSION) so unreadable / chmod-broken / crashed binaries route through the fallback + reinstall path instead of being silently trusted. - remove-plan path helpers: append .exe on Windows. legacyLocalBinIii and privateIiiBin hard-coded 'iii' so existsSync probes missed the install on win32. - probeLocalBinIiiVersion now reads legacyLocalBinIii(home) instead of the alias localBinIii (= privateIiiBin). The 'legacy version matches pin?' gate in buildRemovePlan was checking the private bin (which agentmemory always installs at the pin), so the legacy entry would render with the wrong description / alwaysAsk flag.
Bump to 0.9.25 across 9 files + CHANGELOG. Closes #778 #775 #783 (PR #791), #758 #726 (PR #773), #759 (PR #772), #752 (PR #774), #729 (PR #780), #781 (PR #782), #753 (PR #789), #771 (PR #786), #762 (PR #764). Files bumped: - package.json - packages/mcp/package.json - plugin/.claude-plugin/plugin.json - plugin/.codex-plugin/plugin.json - plugin/plugin.json - src/version.ts - src/types.ts (ExportData.version union) - src/functions/export-import.ts (supportedVersions Set) - test/export-import.test.ts (assertion) 125 test files / 1379 tests pass. npm audit (root + website): 0 vulns.
Problem
Reported in #752. Fresh global install of
@agentmemory/agentmemoryon a box that already hasiii-engine v0.16.1on PATH refuses to boot because agentmemory hard-pins v0.11.2:Two follow-on traps the reporter flagged:
iiibinary on aarch64; noiii-init, noiii-worker. Following the downgrade hint leaves av0.11.2 iiinext to leftoverv0.16.1 iii-worker— a split set that's arguably worse than the original mismatch.AGENTMEMORY_III_VERSION=0.16.1boots cleanly on aarch64, but the pin doesn't follow.Fix
Isolate agentmemory's pinned engine from any user-managed iii on PATH by installing to a private location under
~/.agentmemory/bin/instead of the shared~/.local/bin/. The pinned version stays at v0.11.2.~/.local/bin/iii~/.agentmemory/bin/iiiexit 1~/.local/bin→/usr/local/bin~/.local/bin→/usr/local/binCode
pickCompatibleIiiwalks candidate iii paths and returns the first one whose--versionmatchesIIPINNED_VERSION, or null. Replaces the oldenforceEngineVersionPinwhich usedprocess.exit(1).startEngineauto-installs to private dir when PATH iii is wrong version and there's no private install yet. No prompt — the user has wrong-version iii on PATH, prompting them would just confuse the situation.runIiiInstallerwrites to~/.agentmemory/bin/iii.agentmemory stop --force+ re-run instead of manual curl.agentmemory removeplans cleanup of BOTH~/.agentmemory/bin/iii(agentmemory owns it, safe to delete) AND~/.local/bin/iii(legacy, version-gated so a user-managed install isn't deleted).Pins
iii-sdkpin: still 0.11.2IIPINNED_VERSION: still 0.11.2AGENTMEMORY_III_VERSIONoverride: still worksNo engine API drift is introduced by this PR.
Tests
agentmemory removeplan now includes aprivate-bin-iiientry when~/.agentmemory/bin/iiiexists.Migration
Existing users with
~/.local/bin/iiistill work — it remains in the fallback chain. New installs go to the private dir. Theremovecommand cleans up both locations.Closes #752.
Summary by CodeRabbit
New Features
Bug Fixes
Chores
Tests