Skip to content

fix(cli): harden import-jsonl + use curl installer for iii-engine upgrade#174

Merged
rohitg00 merged 2 commits intomainfrom
fix/cli-import-upgrade-errors
Apr 20, 2026
Merged

fix(cli): harden import-jsonl + use curl installer for iii-engine upgrade#174
rohitg00 merged 2 commits intomainfrom
fix/cli-import-upgrade-errors

Conversation

@rohitg00
Copy link
Copy Markdown
Owner

@rohitg00 rohitg00 commented Apr 20, 2026

Summary

Two hard-fails reported from a fresh `npx @agentmemory/agentmemory` session:

  1. `import-jsonl` crashed with `Unexpected end of JSON input` when anything other than a 2xx-with-JSON came back from the server — including the server simply not being up.
  2. `upgrade` prompted `cargo install iii-engine --force`, which 404s because the crate isn't on crates.io, then aborted the whole upgrade before Docker pull ran.

Changes

`runImportJsonl` — src/cli.ts

  • Livez probe now checks `res.ok`, not just `fetch` success. A stray service on port 3111 used to pass silently, then the POST would 404 with an empty body and explode at `res.json()`.
  • Response handling reads body as text, parses only if non-empty, and maps 401 → "set AGENTMEMORY_SECRET" and 404 → "upgrade server to v0.8.13+".

`runUpgrade` — src/cli.ts

  • Replaced `cargo install iii-engine --force` with the same installer used in the README, demo command, and docs:

    ```sh
    curl -fsSL https://install.iii.dev/iii/main/install.sh | sh
    ```

  • Installer marked optional — failure no longer kills the Docker pull that follows. Warn points at `iiidev/iii:latest` and GitHub releases as fallbacks.

  • Dropped the unused `cargoBin` lookup.

Test plan

  • `npm run build` — clean
  • `npm test` — 777 pass
  • Manual: `agentmemory import-jsonl` with server stopped → clear "not running" error (not JSON parse crash)
  • Manual: `agentmemory upgrade` → installer runs, failure degrades gracefully, Docker pull still proceeds

Reported in-session by @rohitg00 testing v0.9.0.

Summary by CodeRabbit

  • New Features

    • Upgrade flow now uses a network installer script (sh + curl) for broader compatibility.
    • Added a preflight health check before importing data to ensure the service is reachable.
  • Bug Fixes

    • Improved error handling with clearer guidance for authorization/endpoint issues.
    • Enhanced response parsing to handle empty or non-JSON responses and report HTTP status/snippets.
    • Safer success reporting with defaults when import counts are missing.

…rade

## import-jsonl

Two failure modes surfaced as "Unexpected end of JSON input":

- Livez probe only caught fetch throws, not non-OK responses. A stray
  service on port 3111 would pass the probe silently, then POST would
  404 with an empty body and crash on res.json().
- res.json() is unforgiving: an empty body, HTML error page, or proxy
  response exits with a cryptic parse error instead of the actual HTTP
  status.

Now:
- Probe checks res.ok before continuing, with a start-the-server hint.
- Import reads body as text, parses only if non-empty, and surfaces
  HTTP 401 (secret mismatch) and 404 (old server predating v0.8.13)
  with actionable guidance.

## upgrade

cargo install iii-engine fails because iii-engine isn't on crates.io,
and requireSuccess exited the whole upgrade before Docker ever ran.

Switch to the official installer used everywhere else in the docs and
demo command:

  curl -fsSL https://install.iii.dev/iii/main/install.sh | sh

Installer failure is treated as optional — Docker pull still runs and
the final note points at the Docker + release-binary fallbacks.
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 20, 2026

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

Project Deployment Actions Updated (UTC)
agentmemory Ready Ready Preview, Comment Apr 20, 2026 11:04pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 20, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: be5c9867-765f-4124-8504-2b90538ada8d

📥 Commits

Reviewing files that changed from the base of the PR and between ecf9c21 and baac252.

📒 Files selected for processing (1)
  • src/cli.ts

📝 Walkthrough
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the two main changes: hardening import-jsonl error handling and switching to curl installer for iii-engine upgrade.

✏️ 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/cli-import-upgrade-errors

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

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/cli.ts`:
- Around line 815-828: The current probe block swallows the HTTP response
details and exceptions; update the probe logic around the fetch to preserve and
surface the failure reason: when calling fetch(`${base}/agentmemory/livez`) (the
probe variable), capture probe.status and a short probe body (e.g., await
probe.text() or first 200 chars) when probe.ok is false and include those
details in the p.log.error message (instead of treating all non-2xx as “not
running”); also catch and include the caught exception message when fetch throws
so the final error printed (before process.exit(1)) clearly distinguishes
“server unreachable” (network/error message) from “reachable but unhealthy”
(HTTP status and response body) while keeping probeOk boolean semantics.
- Around line 849-885: The response handling treats missing success as success
because json defaults to {}, so change the success check to require json.success
=== true (i.e., replace the current if (!res.ok || json.success === false) with
a condition that treats json.success !== true as failure). Ensure the code path
that logs failure (using spinner.stop("failed") and p.log.error with the
computed detail) also runs when json.success is absent/non-true, and only run
the final spinner.stop(success message) and use
json.imported/json.observations/json.sessionIds when json.success === true.
- Around line 771-774: The fallback warning uses a broken releases URL; update
the message string passed to p.log.warn (the branch guarded by installerOk
false) to replace "https://github.com/iii-dev/iii-engine/releases" with the
correct repository URL "https://github.com/iii-hq/iii/releases/latest" so the
warning points to the working releases page (locate the p.log.warn call near the
installerOk check).
🪄 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: 2c613785-0573-403f-80bf-e5d805d57f54

📥 Commits

Reviewing files that changed from the base of the PR and between 4f8c4ca and ecf9c21.

📒 Files selected for processing (1)
  • src/cli.ts

Comment thread src/cli.ts
Comment thread src/cli.ts
Comment on lines +815 to 828
let probeOk = false;
try {
await fetch(`${base}/agentmemory/livez`, {
const probe = await fetch(`${base}/agentmemory/livez`, {
signal: AbortSignal.timeout(2000),
});
probeOk = probe.ok;
} catch {
p.log.error(`agentmemory is not running on port ${port}. Start it first.`);
probeOk = false;
}
if (!probeOk) {
p.log.error(
`agentmemory is not running on port ${port}. Start it with \`npx @agentmemory/agentmemory\` in another terminal, then re-run this command.`,
);
process.exit(1);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Preserve the probe failure reason.

Line 820 treats every non-2xx /livez response as “not running”, but the livez endpoint can return 503 when the server is reachable but unhealthy. Include the HTTP status/body in the error so users can distinguish “down” from “running but not healthy.”

🛠️ Suggested adjustment
-  let probeOk = false;
+  let probeOk = false;
+  let probeFailure = "";
   try {
     const probe = await fetch(`${base}/agentmemory/livez`, {
       signal: AbortSignal.timeout(2000),
     });
     probeOk = probe.ok;
-  } catch {
+    if (!probe.ok) {
+      const probeBody = await probe.text().catch(() => "");
+      probeFailure = `HTTP ${probe.status} ${probe.statusText}${probeBody ? ` — ${probeBody.slice(0, 160)}` : ""}`;
+    }
+  } catch (err) {
     probeOk = false;
+    probeFailure = err instanceof Error ? err.message : String(err);
   }
   if (!probeOk) {
     p.log.error(
-      `agentmemory is not running on port ${port}. Start it with \`npx `@agentmemory/agentmemory`\` in another terminal, then re-run this command.`,
+      `agentmemory is not healthy on port ${port}${probeFailure ? ` (${probeFailure})` : ""}. Start it with \`npx `@agentmemory/agentmemory`\` in another terminal, then re-run this command.`,
     );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let probeOk = false;
try {
await fetch(`${base}/agentmemory/livez`, {
const probe = await fetch(`${base}/agentmemory/livez`, {
signal: AbortSignal.timeout(2000),
});
probeOk = probe.ok;
} catch {
p.log.error(`agentmemory is not running on port ${port}. Start it first.`);
probeOk = false;
}
if (!probeOk) {
p.log.error(
`agentmemory is not running on port ${port}. Start it with \`npx @agentmemory/agentmemory\` in another terminal, then re-run this command.`,
);
process.exit(1);
let probeOk = false;
let probeFailure = "";
try {
const probe = await fetch(`${base}/agentmemory/livez`, {
signal: AbortSignal.timeout(2000),
});
probeOk = probe.ok;
if (!probe.ok) {
const probeBody = await probe.text().catch(() => "");
probeFailure = `HTTP ${probe.status} ${probe.statusText}${probeBody ? ` — ${probeBody.slice(0, 160)}` : ""}`;
}
} catch (err) {
probeOk = false;
probeFailure = err instanceof Error ? err.message : String(err);
}
if (!probeOk) {
p.log.error(
`agentmemory is not healthy on port ${port}${probeFailure ? ` (${probeFailure})` : ""}. Start it with \`npx `@agentmemory/agentmemory`\` in another terminal, then re-run this command.`,
);
process.exit(1);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/cli.ts` around lines 815 - 828, The current probe block swallows the HTTP
response details and exceptions; update the probe logic around the fetch to
preserve and surface the failure reason: when calling
fetch(`${base}/agentmemory/livez`) (the probe variable), capture probe.status
and a short probe body (e.g., await probe.text() or first 200 chars) when
probe.ok is false and include those details in the p.log.error message (instead
of treating all non-2xx as “not running”); also catch and include the caught
exception message when fetch throws so the final error printed (before
process.exit(1)) clearly distinguishes “server unreachable” (network/error
message) from “reachable but unhealthy” (HTTP status and response body) while
keeping probeOk boolean semantics.

Comment thread src/cli.ts
…ct releases URL

Addresses review findings on #174:

- Livez probe now captures probe.status + body snippet on non-OK
  responses and the exception message on fetch throws, then prints the
  distinct reason: "unreachable (...)" vs "reachable but unhealthy
  (HTTP 503: ...)". No more flat "not running" for every failure mode.

- Import success check now requires json.success === true instead of
  treating a missing success field as success. A 2xx empty body used
  to fall through and print "imported 0 file(s)" — it now reports
  "response missing success field" and exits non-zero.

- Fallback releases URL pointed at iii-dev/iii-engine, which doesn't
  exist. Corrected to iii-hq/iii/releases/latest — the same URL used
  in README and the demo command.
@rohitg00 rohitg00 merged commit ea01290 into main Apr 20, 2026
4 of 5 checks passed
@rohitg00 rohitg00 deleted the fix/cli-import-upgrade-errors branch April 20, 2026 23:04
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.

1 participant