Skip to content

fix(cli): install pinned iii to private dir, fall back on PATH mismatch#774

Merged
rohitg00 merged 2 commits into
mainfrom
fix/private-iii-install-pin
Jun 2, 2026
Merged

fix(cli): install pinned iii to private dir, fall back on PATH mismatch#774
rohitg00 merged 2 commits into
mainfrom
fix/private-iii-install-pin

Conversation

@rohitg00
Copy link
Copy Markdown
Owner

@rohitg00 rohitg00 commented Jun 1, 2026

Problem

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:

■  iii-engine on PATH is v0.16.1 but agentmemory v0.9.24 hard-pins v0.11.2.
   Downgrade with: curl -fsSL .../v0.11.2/iii-aarch64-unknown-linux-gnu.tar.gz | tar -xz -C ~/.local/bin

Two follow-on traps the reporter flagged:

  • The pinned v0.11.2 release ships only the iii binary on aarch64; no iii-init, no iii-worker. Following the downgrade hint leaves a v0.11.2 iii next to leftover v0.16.1 iii-worker — a split set that's arguably worse than the original mismatch.
  • AGENTMEMORY_III_VERSION=0.16.1 boots 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.

Before After
Install location: ~/.local/bin/iii ~/.agentmemory/bin/iii
Wrong-version iii on PATH → exit 1 Auto-install pinned to private dir
Fallback order: PATH → ~/.local/bin/usr/local/bin private → PATH → ~/.local/bin/usr/local/bin
Downgrade hint overwrites user's iii Hint points at private path, leaves PATH iii untouched

Code

  • pickCompatibleIii walks candidate iii paths and returns the first one whose --version matches IIPINNED_VERSION, or null. Replaces the old enforceEngineVersionPin which used process.exit(1).
  • startEngine auto-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.
  • runIiiInstaller writes to ~/.agentmemory/bin/iii.
  • The "attach to running engine" path still hard-fails on wrong-version engine (can't reinstall under a running engine without killing it). Error message now suggests agentmemory stop --force + re-run instead of manual curl.
  • agentmemory remove plans 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-sdk pin: still 0.11.2
  • IIPINNED_VERSION: still 0.11.2
  • AGENTMEMORY_III_VERSION override: still works

No engine API drift is introduced by this PR.

Tests

  • 1292/1292 pass (added 1 case for the new private-bin-iii cleanup item).
  • agentmemory remove plan now includes a private-bin-iii entry when ~/.agentmemory/bin/iii exists.

Migration

Existing users with ~/.local/bin/iii still work — it remains in the fallback chain. New installs go to the private dir. The remove command cleans up both locations.

Closes #752.

Summary by CodeRabbit

  • New Features

    • Engine binary is now managed in a private ~/.agentmemory/bin location and preferred over PATH when appropriate.
    • Startup will auto-select or auto-install the pinned engine to that private location when needed.
  • Bug Fixes

    • Improved detection and handling of version mismatches; avoids interactive traps and gives clear next steps.
  • Chores

    • Updated diagnostics, install hints, and uninstall/remove flows to reference and handle the private install location.
  • Tests

    • Updated remove-flow tests to reflect legacy vs. private binary behavior.

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.
@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 1, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agentmemory Ready Ready Preview, Comment Jun 2, 2026 7:55am

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 1, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fa95f276-283a-41c4-b889-f991da933bdb

📥 Commits

Reviewing files that changed from the base of the PR and between 5b5d698 and ae31759.

📒 Files selected for processing (2)
  • src/cli.ts
  • src/cli/remove-plan.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/cli/remove-plan.ts
  • src/cli.ts

📝 Walkthrough

Walkthrough

Moves 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.

Changes

Private install directory and version-mismatch handling

Layer / File(s) Summary
Path helpers and removal exports
src/cli.ts, src/cli/remove-plan.ts
Adds platform-aware iii filename helper, legacyLocalBinIii and privateIiiBin exports, and makes localBinIii a back-compat alias; CLI imports updated to use legacy probe where appropriate.
Version compatibility resolver
src/cli.ts
Implements resolveCompatibleIii to validate candidate iii --version against IIPINNED_VERSION, preferring a compatible private install and returning null when no compatible candidate exists.
Engine startup and state wiring
src/cli.ts
Refactors startup to pickCompatibleIii from PATH + fallbacks, update PATH when selecting a binary directory, write selected binPath into persisted EngineState, change installer destination to the private bin dir, and bias interactive install toward the private pinned engine on PATH mismatches.
Doctor diagnostics integration
src/cli/doctor-diagnostics.ts, src/cli.ts
Updates DoctorEffects documentation and iii-on-path-not-local-bin diagnostic messages and success text to reference ~/.agentmemory/bin/iii.
Binary removal plan and tests
src/cli/remove-plan.ts, test/cli-remove.test.ts
buildRemovePlan now includes an always-removable private-bin-iii item and a legacy-local-bin-iii item (prompt behavior depends on version match). Tests updated to assert the renamed plan item IDs and the new private removal behavior.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐇 In a snug little bin where the carrots don't roam,
I hide our iii bolts and call them my home.
If PATH brings the wrong one, I patch with a hop—install,
Pin the right version, persist its small stall.
Hooray for private bins! 🥕✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main change: installing the pinned iii binary to a private directory (~/.agentmemory/bin) and implementing fallback behavior when PATH contains a mismatched version.
Linked Issues check ✅ Passed All coding objectives from issue #752 are met: prevents non-bootable behavior by auto-installing the pinned version to a private location, avoids overwriting user-managed iii on PATH via fallback resolution, preserves the AGENTMEMORY_III_VERSION override, and implements compatible version selection via pickCompatibleIii.
Out of Scope Changes check ✅ Passed All changes align with the PR's stated objectives: core engine startup logic (cli.ts), diagnostic messaging (doctor-diagnostics.ts), remove-plan implementation (remove-plan.ts), and corresponding test updates (cli-remove.test.ts). No extraneous modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/private-iii-install-pin

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 win

Probe the legacy path here, not the back-compat alias.

localBinIii() now aliases the private install path, but buildRemovePlan() still interprets localBinIiiVersion as the version of legacy ~/.local/bin/iii. With both binaries present, agentmemory remove --force can classify a user-managed legacy binary as "matches pinned" just because the private copy does. Use legacyLocalBinIii(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

📥 Commits

Reviewing files that changed from the base of the PR and between a35de80 and 5b5d698.

📒 Files selected for processing (4)
  • src/cli.ts
  • src/cli/doctor-diagnostics.ts
  • src/cli/remove-plan.ts
  • test/cli-remove.test.ts

Comment thread src/cli.ts
Comment thread src/cli.ts
Comment thread src/cli/remove-plan.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.
@rohitg00 rohitg00 merged commit 4b593e0 into main Jun 2, 2026
7 checks passed
@rohitg00 rohitg00 deleted the fix/private-iii-install-pin branch June 2, 2026 08:13
rohitg00 added a commit that referenced this pull request Jun 2, 2026
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fresh global install fetches iii-engine 0.16.1 but runtime hard-pins 0.11.2 — agentmemory/npx refuses to boot (aarch64 Linux)

1 participant