@agentmemory/agentmemory 0.9.26 → 0.9.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/AGENTS.md +6 -6
  2. package/README.md +104 -42
  3. package/dist/cli.d.mts.map +1 -1
  4. package/dist/cli.mjs +239 -170
  5. package/dist/cli.mjs.map +1 -1
  6. package/dist/config-ChC9EtgV.mjs +259 -0
  7. package/dist/config-ChC9EtgV.mjs.map +1 -0
  8. package/dist/{connect-bmZ5eqYN.mjs → connect-JnsJXc68.mjs} +136 -42
  9. package/dist/connect-JnsJXc68.mjs.map +1 -0
  10. package/dist/hooks/notification.mjs +2 -1
  11. package/dist/hooks/notification.mjs.map +1 -1
  12. package/dist/hooks/post-commit.mjs +2 -1
  13. package/dist/hooks/post-commit.mjs.map +1 -1
  14. package/dist/hooks/post-tool-failure.mjs +2 -1
  15. package/dist/hooks/post-tool-failure.mjs.map +1 -1
  16. package/dist/hooks/post-tool-use.mjs +2 -1
  17. package/dist/hooks/post-tool-use.mjs.map +1 -1
  18. package/dist/hooks/pre-compact.mjs +2 -1
  19. package/dist/hooks/pre-compact.mjs.map +1 -1
  20. package/dist/hooks/pre-tool-use.mjs +2 -1
  21. package/dist/hooks/pre-tool-use.mjs.map +1 -1
  22. package/dist/hooks/prompt-submit.mjs +2 -1
  23. package/dist/hooks/prompt-submit.mjs.map +1 -1
  24. package/dist/hooks/session-end.mjs +2 -1
  25. package/dist/hooks/session-end.mjs.map +1 -1
  26. package/dist/hooks/session-start.mjs +2 -1
  27. package/dist/hooks/session-start.mjs.map +1 -1
  28. package/dist/hooks/stop.mjs +2 -1
  29. package/dist/hooks/stop.mjs.map +1 -1
  30. package/dist/hooks/subagent-start.mjs +2 -1
  31. package/dist/hooks/subagent-start.mjs.map +1 -1
  32. package/dist/hooks/subagent-stop.mjs +2 -1
  33. package/dist/hooks/subagent-stop.mjs.map +1 -1
  34. package/dist/hooks/task-completed.mjs +2 -1
  35. package/dist/hooks/task-completed.mjs.map +1 -1
  36. package/dist/{image-refs-C7h9L5wx.mjs → image-refs-BKLmp_sD.mjs} +4 -22
  37. package/dist/image-refs-BKLmp_sD.mjs.map +1 -0
  38. package/dist/image-refs-C2YU7BIm.mjs +34 -0
  39. package/dist/image-refs-C2YU7BIm.mjs.map +1 -0
  40. package/dist/index.mjs +559 -205
  41. package/dist/index.mjs.map +1 -1
  42. package/dist/{image-store-Gpo2mgM9.mjs → keyed-mutex-DTHtcZrt.mjs} +14 -11
  43. package/dist/keyed-mutex-DTHtcZrt.mjs.map +1 -0
  44. package/dist/{logger-yHTcEBAI.mjs → logger-BEB7pCI9.mjs} +1 -1
  45. package/dist/{logger-yHTcEBAI.mjs.map → logger-BEB7pCI9.mjs.map} +1 -1
  46. package/dist/{schema-Dsr_V2Wp.mjs → schema-CNiCWzV9.mjs} +5 -1
  47. package/dist/schema-CNiCWzV9.mjs.map +1 -0
  48. package/dist/{src-u7kAEUC0.mjs → src-CzgoepGU.mjs} +482 -83
  49. package/dist/src-CzgoepGU.mjs.map +1 -0
  50. package/dist/{standalone-C1yPO519.mjs → standalone-YsZFFQBM.mjs} +8 -5
  51. package/dist/standalone-YsZFFQBM.mjs.map +1 -0
  52. package/dist/standalone.d.mts.map +1 -1
  53. package/dist/standalone.mjs +6 -2
  54. package/dist/standalone.mjs.map +1 -1
  55. package/dist/{tools-registry-Dzxv9iUu.mjs → tools-registry-D3NEoe5m.mjs} +4 -254
  56. package/dist/tools-registry-D3NEoe5m.mjs.map +1 -0
  57. package/package.json +4 -1
  58. package/plugin/.claude-plugin/plugin.json +1 -1
  59. package/plugin/.codex-plugin/plugin.json +1 -1
  60. package/plugin/plugin.json +2 -2
  61. package/plugin/scripts/notification.mjs +2 -1
  62. package/plugin/scripts/notification.mjs.map +1 -1
  63. package/plugin/scripts/post-commit.mjs +2 -1
  64. package/plugin/scripts/post-commit.mjs.map +1 -1
  65. package/plugin/scripts/post-tool-failure.mjs +2 -1
  66. package/plugin/scripts/post-tool-failure.mjs.map +1 -1
  67. package/plugin/scripts/post-tool-use.mjs +2 -1
  68. package/plugin/scripts/post-tool-use.mjs.map +1 -1
  69. package/plugin/scripts/pre-compact.mjs +2 -1
  70. package/plugin/scripts/pre-compact.mjs.map +1 -1
  71. package/plugin/scripts/pre-tool-use.mjs +2 -1
  72. package/plugin/scripts/pre-tool-use.mjs.map +1 -1
  73. package/plugin/scripts/prompt-submit.mjs +2 -1
  74. package/plugin/scripts/prompt-submit.mjs.map +1 -1
  75. package/plugin/scripts/session-end.mjs +2 -1
  76. package/plugin/scripts/session-end.mjs.map +1 -1
  77. package/plugin/scripts/session-start.mjs +2 -1
  78. package/plugin/scripts/session-start.mjs.map +1 -1
  79. package/plugin/scripts/stop.mjs +2 -1
  80. package/plugin/scripts/stop.mjs.map +1 -1
  81. package/plugin/scripts/subagent-start.mjs +2 -1
  82. package/plugin/scripts/subagent-start.mjs.map +1 -1
  83. package/plugin/scripts/subagent-stop.mjs +2 -1
  84. package/plugin/scripts/subagent-stop.mjs.map +1 -1
  85. package/plugin/scripts/task-completed.mjs +2 -1
  86. package/plugin/scripts/task-completed.mjs.map +1 -1
  87. package/plugin/skills/_shared/TROUBLESHOOTING.md +38 -0
  88. package/plugin/skills/agentmemory-agents/REFERENCE.md +28 -0
  89. package/plugin/skills/agentmemory-agents/SKILL.md +34 -0
  90. package/plugin/skills/agentmemory-architecture/SKILL.md +33 -0
  91. package/plugin/skills/agentmemory-config/REFERENCE.md +42 -0
  92. package/plugin/skills/agentmemory-config/SKILL.md +37 -0
  93. package/plugin/skills/agentmemory-hooks/REFERENCE.md +20 -0
  94. package/plugin/skills/agentmemory-hooks/SKILL.md +39 -0
  95. package/plugin/skills/agentmemory-mcp-tools/REFERENCE.md +65 -0
  96. package/plugin/skills/agentmemory-mcp-tools/SKILL.md +39 -0
  97. package/plugin/skills/agentmemory-rest-api/REFERENCE.md +129 -0
  98. package/plugin/skills/agentmemory-rest-api/SKILL.md +43 -0
  99. package/plugin/skills/commit-context/EXAMPLES.md +71 -0
  100. package/plugin/skills/commit-context/SKILL.md +53 -8
  101. package/plugin/skills/commit-history/EXAMPLES.md +71 -0
  102. package/plugin/skills/commit-history/SKILL.md +51 -9
  103. package/plugin/skills/forget/EXAMPLES.md +75 -0
  104. package/plugin/skills/forget/SKILL.md +54 -14
  105. package/plugin/skills/handoff/EXAMPLES.md +56 -0
  106. package/plugin/skills/handoff/SKILL.md +56 -9
  107. package/plugin/skills/recall/EXAMPLES.md +74 -0
  108. package/plugin/skills/recall/SKILL.md +50 -11
  109. package/plugin/skills/recap/EXAMPLES.md +60 -0
  110. package/plugin/skills/recap/SKILL.md +51 -13
  111. package/plugin/skills/remember/EXAMPLES.md +67 -0
  112. package/plugin/skills/remember/SKILL.md +53 -17
  113. package/plugin/skills/session-history/EXAMPLES.md +59 -0
  114. package/plugin/skills/session-history/SKILL.md +54 -11
  115. package/plugin/skills/write-agentmemory-skill/SKILL.md +40 -0
  116. package/dist/connect-bmZ5eqYN.mjs.map +0 -1
  117. package/dist/image-refs-C7h9L5wx.mjs.map +0 -1
  118. package/dist/image-store-Gpo2mgM9.mjs.map +0 -1
  119. package/dist/rolldown-runtime-twds-ZHy.mjs +0 -14
  120. package/dist/schema-Dsr_V2Wp.mjs.map +0 -1
  121. package/dist/src-u7kAEUC0.mjs.map +0 -1
  122. package/dist/standalone-C1yPO519.mjs.map +0 -1
  123. package/dist/tools-registry-Dzxv9iUu.mjs.map +0 -1
  124. package/dist/version-BMFYFFut.mjs +0 -6
  125. package/dist/version-BMFYFFut.mjs.map +0 -1
package/dist/cli.mjs CHANGED
@@ -1,14 +1,15 @@
1
1
  #!/usr/bin/env node
2
- import { i as generateId } from "./schema-Dsr_V2Wp.mjs";
3
- import { n as resolveAdapter, r as runAdapter } from "./connect-bmZ5eqYN.mjs";
4
- import { r as setBootVerbose } from "./logger-yHTcEBAI.mjs";
5
- import { t as VERSION } from "./version-BMFYFFut.mjs";
2
+ import { a as runAdapter, i as resolveAdapter, r as knownAgents, t as ADAPTERS } from "./connect-JnsJXc68.mjs";
3
+ import { i as generateId } from "./schema-CNiCWzV9.mjs";
4
+ import { r as setBootVerbose } from "./logger-BEB7pCI9.mjs";
5
+ import { i as VERSION, n as getAllTools, t as ESSENTIAL_TOOLS } from "./tools-registry-D3NEoe5m.mjs";
6
6
  import { execFileSync, spawn, spawnSync } from "node:child_process";
7
- import { closeSync, constants, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, readdirSync, readlinkSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
7
+ import { appendFileSync, closeSync, constants, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, readdirSync, readlinkSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
8
8
  import { delimiter, dirname, join } from "node:path";
9
9
  import { fileURLToPath } from "node:url";
10
10
  import { homedir, platform } from "node:os";
11
11
  import * as p from "@clack/prompts";
12
+ import pc from "picocolors";
12
13
  import { copyFile, mkdir } from "node:fs/promises";
13
14
  //#region src/cli/doctor-diagnostics.ts
14
15
  /** Common placeholder values shipped in .env.example. */
@@ -436,7 +437,8 @@ const DEFAULTS = {
436
437
  skipNpxHint: false,
437
438
  skipGlobalInstall: false,
438
439
  skipConsoleInstall: false,
439
- firstRunAt: null
440
+ firstRunAt: null,
441
+ injectContextChosen: false
440
442
  };
441
443
  function prefsDir() {
442
444
  return join(homedir(), ".agentmemory");
@@ -492,95 +494,14 @@ function isFirstRun() {
492
494
  //#endregion
493
495
  //#region src/cli/onboarding.ts
494
496
  const __dirname$1 = dirname(fileURLToPath(import.meta.url));
495
- const NATIVE_AGENTS = [
496
- {
497
- value: "claude-code",
498
- label: "Claude Code",
499
- glyph: "⟁"
500
- },
501
- {
502
- value: "copilot-cli",
503
- label: "GitHub Copilot CLI",
504
- glyph: "◈"
505
- },
506
- {
507
- value: "codex",
508
- label: "Codex",
509
- glyph: "◎"
510
- },
511
- {
512
- value: "openhuman",
513
- label: "OpenHuman",
514
- glyph: "◇"
515
- },
516
- {
517
- value: "openclaw",
518
- label: "OpenClaw",
519
- glyph: "◇"
520
- },
521
- {
522
- value: "hermes",
523
- label: "Hermes",
524
- glyph: "◇"
525
- },
526
- {
527
- value: "pi",
528
- label: "Pi",
529
- glyph: "◇"
530
- },
531
- {
532
- value: "cursor",
533
- label: "Cursor",
534
- glyph: "◫"
535
- },
536
- {
537
- value: "gemini-cli",
538
- label: "Gemini CLI",
539
- glyph: "✦"
540
- }
541
- ];
542
- const MCP_AGENTS = [
543
- {
544
- value: "opencode",
545
- label: "OpenCode",
546
- glyph: "⬡"
547
- },
548
- {
549
- value: "cline",
550
- label: "Cline",
551
- glyph: "◇"
552
- },
553
- {
554
- value: "goose",
555
- label: "Goose",
556
- glyph: "◇"
557
- },
558
- {
559
- value: "kilo",
560
- label: "Kilo",
561
- glyph: "◇"
562
- },
563
- {
564
- value: "aider",
565
- label: "Aider",
566
- glyph: "◇"
567
- },
568
- {
569
- value: "claude-desktop",
570
- label: "Claude Desktop",
571
- glyph: "⟁"
572
- },
573
- {
574
- value: "windsurf",
575
- label: "Windsurf",
576
- glyph: "◇"
577
- },
578
- {
579
- value: "roo",
580
- label: "Roo",
581
- glyph: "◇"
582
- }
583
- ];
497
+ const AGENT_GLYPH = {
498
+ "claude-code": "⟁",
499
+ "copilot-cli": "◈",
500
+ codex: "◎",
501
+ cursor: "◫",
502
+ "gemini-cli": "✦",
503
+ opencode: "⬡"
504
+ };
584
505
  const PROVIDERS = [
585
506
  {
586
507
  value: "anthropic",
@@ -613,16 +534,20 @@ const PROVIDERS = [
613
534
  envKey: null
614
535
  }
615
536
  ];
537
+ const PROVIDER_COST_HINTS = {
538
+ anthropic: "rough cost: a fast Haiku-class model keeps compress/consolidate at fractions of a cent per session.",
539
+ openai: "rough cost: a mini-class model keeps compress/consolidate at fractions of a cent per session.",
540
+ gemini: "rough cost: a Flash-class model keeps compress/consolidate at fractions of a cent per session.",
541
+ openrouter: "rough cost: pick a small model; spend tracks your chosen model's per-token price.",
542
+ minimax: "rough cost: scales with the MiniMax model price per token."
543
+ };
616
544
  function buildAgentOptions() {
617
- return [...NATIVE_AGENTS.map((a) => ({
618
- value: a.value,
619
- label: `${a.glyph} ${a.label}`,
620
- hint: "native plugin"
621
- })), ...MCP_AGENTS.map((a) => ({
622
- value: a.value,
623
- label: `${a.glyph} ${a.label}`,
624
- hint: "MCP server"
625
- }))];
545
+ const options = ADAPTERS.map((a) => ({
546
+ value: a.name,
547
+ label: `${AGENT_GLYPH[a.name] ?? "◇"} ${a.displayName}`,
548
+ hint: a.category === "native" ? "native plugin" : "MCP server"
549
+ }));
550
+ return [...options.filter((o) => o.hint === "native plugin"), ...options.filter((o) => o.hint === "MCP server")];
626
551
  }
627
552
  function getInitialAgentValues(env = process.env) {
628
553
  if (env["COPILOT_CLI"] === "1" || env["COPILOT_AGENT_SESSION_ID"]) return ["copilot-cli"];
@@ -715,7 +640,12 @@ async function runOnboarding() {
715
640
  }
716
641
  const provider = providerPicked === "skip" ? null : providerPicked;
717
642
  const agents = agentsPicked ?? [];
643
+ if (provider) {
644
+ const hint = PROVIDER_COST_HINTS[provider];
645
+ if (hint) p.log.info(hint);
646
+ }
718
647
  const envPath = await seedEnvFile(provider);
648
+ await maybePromptContextInjection(envPath);
719
649
  writePrefs({
720
650
  lastAgent: agents[0] ?? null,
721
651
  lastAgents: agents,
@@ -737,6 +667,33 @@ async function runOnboarding() {
737
667
  provider
738
668
  };
739
669
  }
670
+ function enableInjectContextInEnv(envPath) {
671
+ if (!envPath || !existsSync(envPath)) return false;
672
+ try {
673
+ const current = readFileSync(envPath, "utf-8");
674
+ if (/^\s*AGENTMEMORY_INJECT_CONTEXT\s*=\s*true\b/m.test(current)) return true;
675
+ appendFileSync(envPath, `${current.length > 0 && !current.endsWith("\n") ? "\n" : ""}AGENTMEMORY_INJECT_CONTEXT=true\n`, { mode: 384 });
676
+ return true;
677
+ } catch {
678
+ return false;
679
+ }
680
+ }
681
+ async function maybePromptContextInjection(envPath) {
682
+ if (readPrefs().injectContextChosen) return;
683
+ const enable = await p.confirm({
684
+ message: "Enable automatic context injection so the agent recalls past sessions without being asked? [y/N]",
685
+ initialValue: false
686
+ });
687
+ if (p.isCancel(enable)) {
688
+ p.cancel("Setup cancelled. Re-run any time with: agentmemory --reset");
689
+ process.exit(0);
690
+ }
691
+ p.log.info("Cost note: injection spends session tokens proportional to tool-call frequency. Default is off.");
692
+ writePrefs({ injectContextChosen: true });
693
+ if (enable === true) if (enableInjectContextInEnv(envPath)) p.log.success("Context injection enabled (AGENTMEMORY_INJECT_CONTEXT=true).");
694
+ else p.log.warn("Could not update ~/.agentmemory/.env. Set AGENTMEMORY_INJECT_CONTEXT=true there to enable it.");
695
+ else p.log.info("Context injection left off. Set AGENTMEMORY_INJECT_CONTEXT=true later to enable.");
696
+ }
740
697
  async function wireSelectedAgents(agents) {
741
698
  p.note("Wire selected agents now?", "next step");
742
699
  const confirmed = await p.confirm({
@@ -809,6 +766,18 @@ async function wireSelectedAgents(agents) {
809
766
  }
810
767
  //#endregion
811
768
  //#region src/cli.ts
769
+ const c = {
770
+ url: pc.cyan,
771
+ ok: pc.green,
772
+ warn: pc.yellow,
773
+ err: pc.red,
774
+ cmd: (s) => pc.bold(pc.cyan(s)),
775
+ label: pc.bold,
776
+ dim: pc.dim,
777
+ accent: (s) => pc.bold(pc.yellow(s))
778
+ };
779
+ const ALL_TOOLS_COUNT = getAllTools().length;
780
+ const CORE_TOOLS_COUNT = getAllTools().filter((t) => ESSENTIAL_TOOLS.has(t.name)).length;
812
781
  const __dirname = dirname(fileURLToPath(import.meta.url));
813
782
  const args = process.argv.slice(2);
814
783
  const IS_WINDOWS = platform() === "win32";
@@ -840,6 +809,19 @@ function iiiReleaseUrl() {
840
809
  function vlog(msg) {
841
810
  if (IS_VERBOSE) p.log.info(`[verbose] ${msg}`);
842
811
  }
812
+ function wrapList(items, indent, width = 78) {
813
+ const lines = [];
814
+ let line = "";
815
+ for (const item of items) {
816
+ const joined = line ? `${line}, ${item}` : item;
817
+ if (line && indent + joined.length > width) {
818
+ lines.push(`${line},`);
819
+ line = item;
820
+ } else line = joined;
821
+ }
822
+ lines.push(line);
823
+ return lines.join(`\n${" ".repeat(indent)}`);
824
+ }
843
825
  if (args.includes("--help") || args.includes("-h")) {
844
826
  console.log(`
845
827
  agentmemory — persistent memory for AI coding agents
@@ -849,9 +831,8 @@ Usage: agentmemory [command] [options]
849
831
  Commands:
850
832
  (default) Start agentmemory worker
851
833
  init Copy bundled .env.example to ~/.agentmemory/.env if absent
852
- connect [agent] Wire agentmemory into an installed agent (claude-code,
853
- copilot-cli, codex, cursor, gemini-cli, openclaw,
854
- hermes, pi, openhuman).
834
+ connect [agent] Wire agentmemory into an installed agent
835
+ (${wrapList(knownAgents(), 21)}).
855
836
  No arg = interactive picker. --all wires every detected agent.
856
837
  --dry-run shows what would change. --force re-installs.
857
838
  status Show connection status, memory count, flags, and health
@@ -860,7 +841,9 @@ Commands:
860
841
  --dry-run: show what each fix would do, don't execute
861
842
  remove Cleanly uninstall agentmemory (pidfile, state, .env, binaries).
862
843
  --force: skip confirmations · --keep-data: keep memory data
863
- demo Seed sample sessions and show recall in action
844
+ demo [--serve] Seed sample sessions and show recall in action.
845
+ --serve boots the server, runs the demo, and stops it
846
+ in one command (no second terminal).
864
847
  upgrade Upgrade local deps + iii runtime (best effort)
865
848
  stop [--force] Stop the running iii-engine started by this CLI.
866
849
  --force bypasses the Docker-heuristic guard and signals
@@ -876,9 +859,14 @@ Options:
876
859
  --help, -h Show this help
877
860
  --verbose, -v Show engine stderr, boot log, and diagnostic info
878
861
  --reset Wipe ~/.agentmemory/preferences.json and re-run onboarding
879
- --tools all|core Tool visibility (default: all = 51 tools; core = 8 essentials)
862
+ --tools all|core Tool visibility (default: all = ${ALL_TOOLS_COUNT} tools; core = ${CORE_TOOLS_COUNT} essentials)
880
863
  --no-engine Skip auto-starting iii-engine
881
- --port <N> Override REST port (default: 3111)
864
+ --port <N> Override REST port (default: 3111). Streams (N+1), viewer
865
+ (N+2), and iii engine (N+46023) auto-derive from N so a
866
+ single flag relocates the whole quartet.
867
+ --instance <N> Shortcut for --port (3111 + N*100) to run multiple
868
+ daemons side-by-side without env gymnastics.
869
+ --instance 1 -> 3211/3212/3213/49234, etc. (max N=50)
882
870
 
883
871
  Environment:
884
872
  AGENTMEMORY_URL Full REST base URL (e.g. http://localhost:3111).
@@ -902,9 +890,21 @@ Quick start:
902
890
  process.exit(0);
903
891
  }
904
892
  const toolsIdx = args.indexOf("--tools");
905
- if (toolsIdx !== -1 && args[toolsIdx + 1]) process.env["AGENTMEMORY_TOOLS"] = args[toolsIdx + 1];
893
+ if (toolsIdx !== -1 && args[toolsIdx + 1]) {
894
+ const toolsMode = args[toolsIdx + 1];
895
+ if (toolsMode !== "all" && toolsMode !== "core") p.log.warn(`Unknown --tools value "${toolsMode}" (valid: all, core); falling back to all.`);
896
+ process.env["AGENTMEMORY_TOOLS"] = toolsMode;
897
+ }
906
898
  const portIdx = args.indexOf("--port");
907
899
  if (portIdx !== -1 && args[portIdx + 1]) process.env["III_REST_PORT"] = args[portIdx + 1];
900
+ const instanceIdx = args.indexOf("--instance");
901
+ if (instanceIdx !== -1 && args[instanceIdx + 1]) {
902
+ const n = parseInt(args[instanceIdx + 1] || "", 10);
903
+ if (Number.isFinite(n) && n >= 0 && n <= 50) {
904
+ const base = 3111 + n * 100;
905
+ if (!process.env["III_REST_PORT"]) process.env["III_REST_PORT"] = String(base);
906
+ }
907
+ }
908
908
  const skipEngine = args.includes("--no-engine");
909
909
  function getRestPort() {
910
910
  const url = process.env["AGENTMEMORY_URL"];
@@ -948,7 +948,7 @@ function getViewerUrl() {
948
948
  }
949
949
  }
950
950
  function getStreamPort() {
951
- return parseInt(process.env["III_STREAM_PORT"] || "", 10) || parseInt(process.env["III_STREAMS_PORT"] || "", 10) || 3112;
951
+ return parseInt(process.env["III_STREAM_PORT"] || "", 10) || parseInt(process.env["III_STREAMS_PORT"] || "", 10) || getRestPort() + 1;
952
952
  }
953
953
  function getEnginePort() {
954
954
  const explicit = parseInt(process.env["III_ENGINE_PORT"] || "", 10);
@@ -958,7 +958,7 @@ function getEnginePort() {
958
958
  const parsed = new URL(url).port;
959
959
  if (parsed) return parseInt(parsed, 10);
960
960
  } catch {}
961
- return 49134;
961
+ return getRestPort() + 46023;
962
962
  }
963
963
  async function isEngineRunning() {
964
964
  try {
@@ -1175,8 +1175,8 @@ async function maybeOfferGlobalInstall() {
1175
1175
  if (runCommand(npmBin, [
1176
1176
  "install",
1177
1177
  "-g",
1178
- `@agentmemory/agentmemory@0.9.26`
1179
- ], { label: `Installing @agentmemory/agentmemory@0.9.26 globally` })) {
1178
+ `@agentmemory/agentmemory@0.9.28`
1179
+ ], { label: `Installing @agentmemory/agentmemory@0.9.28 globally` })) {
1180
1180
  p.log.success("Installed globally. `agentmemory stop` etc. will now work in new shells.");
1181
1181
  writePrefs({ skipGlobalInstall: true });
1182
1182
  } else p.log.warn("Global install failed. Try manually: npm install -g @agentmemory/agentmemory");
@@ -1194,7 +1194,11 @@ function detectIiiConsole() {
1194
1194
  };
1195
1195
  return { kind: "missing" };
1196
1196
  }
1197
- const III_CONSOLE_INSTALL_CMD = "curl -fsSL https://install.iii.dev/iii/main/install.sh | sh";
1197
+ const III_CONSOLE_INSTALL_CMD = `curl -fsSL https://install.iii.dev/iii/main/install.sh | VERSION=${IIPINNED_VERSION} sh`;
1198
+ function iiiConsoleInstallHint() {
1199
+ if (!IS_WINDOWS) return III_CONSOLE_INSTALL_CMD;
1200
+ return `# PowerShell:\n $env:VERSION = "${IIPINNED_VERSION}"\n iwr -useb https://install.iii.dev/iii/main/install.sh -OutFile install.sh\n bash install.sh # WSL or Git Bash required\n# Or grab the pinned release directly:\n https://github.com/iii-hq/iii/releases/tag/iii%2Fv${IIPINNED_VERSION}`;
1201
+ }
1198
1202
  async function ensureIiiConsole() {
1199
1203
  const state = detectIiiConsole();
1200
1204
  if (state.kind === "installed") return state;
@@ -1212,11 +1216,11 @@ async function ensureIiiConsole() {
1212
1216
  const shBin = whichBinary("sh");
1213
1217
  const curlBin = whichBinary("curl");
1214
1218
  if (!shBin || !curlBin) {
1215
- p.log.warn(`curl or sh not found. Install manually:\n ${III_CONSOLE_INSTALL_CMD}`);
1219
+ p.log.warn(`curl or sh not found. Install manually:\n ${iiiConsoleInstallHint()}`);
1216
1220
  return state;
1217
1221
  }
1218
1222
  if (!runCommand(shBin, ["-c", III_CONSOLE_INSTALL_CMD], { label: "Installing iii console" })) {
1219
- p.log.warn(`iii console install failed. Re-run manually:\n ${III_CONSOLE_INSTALL_CMD}`);
1223
+ p.log.warn(`iii console install failed. Re-run manually:\n ${iiiConsoleInstallHint()}`);
1220
1224
  return state;
1221
1225
  }
1222
1226
  return detectIiiConsole();
@@ -1233,7 +1237,7 @@ function adoptRunningEngine() {
1233
1237
  configPath: findIiiConfig() || "",
1234
1238
  attached: true
1235
1239
  });
1236
- if (enginePid && !existingPid) p.log.info(`Attached to existing iii-engine (pid ${enginePid})`);
1240
+ if (enginePid && !existingPid) p.log.info(c.ok(`Attached to existing iii-engine (pid ${enginePid})`));
1237
1241
  } catch (err) {
1238
1242
  vlog(`adoptRunningEngine: ${err instanceof Error ? err.message : String(err)}`);
1239
1243
  }
@@ -1335,7 +1339,7 @@ function startIiiBin(iiiBin, configPath) {
1335
1339
  binPath: iiiBin
1336
1340
  });
1337
1341
  spawnEngineBackground(iiiBin, ["--config", configPath], "iii-engine");
1338
- s.stop("iii-engine process started");
1342
+ s.stop(c.ok("iii-engine process started"));
1339
1343
  return true;
1340
1344
  }
1341
1345
  function pickCompatibleIii(candidates) {
@@ -1355,7 +1359,7 @@ async function startEngine() {
1355
1359
  let iiiBin = pickCompatibleIii([pathIii, ...fallbacks]);
1356
1360
  if (iiiBin && configPath) {
1357
1361
  if (iiiBin !== pathIii) {
1358
- p.log.info(`Using iii at: ${iiiBin} (v${IIPINNED_VERSION})`);
1362
+ p.log.info(`Using iii at: ${c.dim(iiiBin)} (v${c.accent(IIPINNED_VERSION)})`);
1359
1363
  process.env["PATH"] = `${dirname(iiiBin)}${delimiter}${process.env["PATH"] ?? ""}`;
1360
1364
  }
1361
1365
  return startIiiBin(iiiBin, configPath);
@@ -1528,17 +1532,17 @@ function printReadyHint(consoleState) {
1528
1532
  const engineHost = getEngineHost();
1529
1533
  const streamUrl = `ws://${engineHost}:${getStreamPort()}`;
1530
1534
  const engineUrl = `ws://${engineHost}:${getEnginePort()}`;
1531
- const consoleLine = consoleState.kind === "installed" ? `iii console ${consoleState.binPath} (run: ${consoleState.binPath} -p <port>)` : `iii console (install: ${III_CONSOLE_INSTALL_CMD})`;
1535
+ const consoleLine = consoleState.kind === "installed" ? `${c.label("iii console")} ${c.dim(consoleState.binPath)} ${c.dim(`(run: ${consoleState.binPath} -p <port>)`)}` : `${c.label("iii console")} ${c.dim(`(install: ${iiiConsoleInstallHint()})`)}`;
1532
1536
  const lines = [
1533
- `REST API ${restUrl}`,
1534
- `Viewer ${viewerUrl}`,
1535
- `Streams ${streamUrl}`,
1536
- `Engine ${engineUrl}`,
1537
+ `${c.label("REST API")} ${c.url(restUrl)}`,
1538
+ `${c.label("Viewer")} ${c.url(viewerUrl)}`,
1539
+ `${c.label("Streams")} ${c.url(streamUrl)}`,
1540
+ `${c.label("Engine")} ${c.url(engineUrl)}`,
1537
1541
  consoleLine
1538
1542
  ];
1539
- p.note(lines.join("\n"), `agentmemory v${VERSION}`);
1543
+ p.note(lines.join("\n"), `agentmemory v${c.accent(VERSION)}`);
1540
1544
  const demoCommand = isInvokedViaNpx() ? "npx @agentmemory/agentmemory demo" : "agentmemory demo";
1541
- process.stdout.write(`\nTry: ${demoCommand}\n`);
1545
+ process.stdout.write(`\n${c.dim("Try:")} ${c.cmd(demoCommand)}\n`);
1542
1546
  }
1543
1547
  async function main() {
1544
1548
  if (IS_RESET) resetPrefs();
@@ -1548,7 +1552,7 @@ async function main() {
1548
1552
  if (firstRun || IS_RESET) await runOnboarding();
1549
1553
  if (skipEngine) {
1550
1554
  if (IS_VERBOSE) p.log.info("Skipping engine check (--no-engine)");
1551
- await import("./src-u7kAEUC0.mjs");
1555
+ await import("./src-CzgoepGU.mjs");
1552
1556
  if (await waitForAgentmemoryReady(15e3)) {
1553
1557
  const consoleState = await ensureIiiConsole();
1554
1558
  await maybeOfferGlobalInstall();
@@ -1560,21 +1564,38 @@ async function main() {
1560
1564
  if (IS_VERBOSE) p.log.success("iii-engine is running");
1561
1565
  const persisted = readEngineState();
1562
1566
  const attachedBin = (persisted?.kind === "native" && persisted.binPath && existsSync(persisted.binPath) ? persisted.binPath : null) ?? whichBinary("iii") ?? fallbackIiiPaths().find((p) => existsSync(p)) ?? null;
1563
- if (attachedBin) {
1564
- const detected = iiiBinVersion(attachedBin);
1565
- if (detected && detected !== IIPINNED_VERSION) {
1566
- p.log.error(`Attached iii-engine appears to be v${detected} (from ${attachedBin}) but agentmemory v${VERSION} hard-pins v${IIPINNED_VERSION}. Engine API drift causes runtime failures (e.g. state::list-not-found on v0.13.0+). Stop the running engine (\`agentmemory stop --force\`) and re-run \`agentmemory\` to install the pinned engine into ~/.agentmemory/bin without touching ${attachedBin}. Or set AGENTMEMORY_III_VERSION=${detected} to override at your own risk.`);
1567
- process.exit(1);
1567
+ const detected = attachedBin ? iiiBinVersion(attachedBin) : null;
1568
+ if (detected === IIPINNED_VERSION) {
1569
+ adoptRunningEngine();
1570
+ await import("./src-CzgoepGU.mjs");
1571
+ if (await waitForAgentmemoryReady(15e3)) {
1572
+ const consoleState = await ensureIiiConsole();
1573
+ await maybeOfferGlobalInstall();
1574
+ printReadyHint(consoleState);
1568
1575
  }
1576
+ return;
1569
1577
  }
1570
- adoptRunningEngine();
1571
- await import("./src-u7kAEUC0.mjs");
1572
- if (await waitForAgentmemoryReady(15e3)) {
1573
- const consoleState = await ensureIiiConsole();
1574
- await maybeOfferGlobalInstall();
1575
- printReadyHint(consoleState);
1576
- }
1577
- return;
1578
+ const detectedLabel = detected ? `v${detected}` : "an unverified version";
1579
+ const base = isInvokedViaNpx() ? "npx @agentmemory/agentmemory" : "agentmemory";
1580
+ p.log.error(`Another iii-engine (${detectedLabel}) is running on port ${getEnginePort()}, and agentmemory needs its own pinned v${IIPINNED_VERSION}.`);
1581
+ p.note([
1582
+ `agentmemory only supports iii-engine v${IIPINNED_VERSION}. It will not adopt or change the running engine (${detectedLabel}).`,
1583
+ "",
1584
+ c.label("Switch to the pinned engine in two steps:"),
1585
+ "",
1586
+ ` 1. Stop the running engine:`,
1587
+ ` ${c.cmd(`${base} stop --force`)}`,
1588
+ ` ${c.dim(`(or stop your own iii however you started it — agentmemory leaves your global iii untouched)`)}`,
1589
+ "",
1590
+ ` 2. Start agentmemory. It downloads and runs the pinned`,
1591
+ ` v${IIPINNED_VERSION} into ~/.agentmemory/bin automatically:`,
1592
+ ` ${c.cmd(base)}`,
1593
+ "",
1594
+ c.dim(`Step 2 needs no manual install. To install iii v${IIPINNED_VERSION} yourself (replaces your global iii), curl:`),
1595
+ ` ${c.cmd(III_CONSOLE_INSTALL_CMD)}`,
1596
+ ` ${c.dim("or download the release:")} ${c.url(`https://github.com/iii-hq/iii/releases/tag/iii%2Fv${IIPINNED_VERSION}`)}`
1597
+ ].join("\n"), "engine conflict");
1598
+ process.exit(1);
1578
1599
  }
1579
1600
  if (!await startEngine()) {
1580
1601
  p.log.error("Could not start iii-engine.");
@@ -1595,7 +1616,7 @@ async function main() {
1595
1616
  else p.log.info("No stderr was captured. Re-run with --verbose for more detail.");
1596
1617
  p.note([
1597
1618
  "Common causes:",
1598
- " - iii-engine version mismatch — reinstall the latest binary",
1619
+ ` - iii-engine version mismatch — reinstall the pinned v${IIPINNED_VERSION} binary`,
1599
1620
  " (sh script on macOS/Linux, GitHub release zip on Windows)",
1600
1621
  " - Docker Desktop not running (if you're using the Docker path)",
1601
1622
  " - Port already in use (see below)",
@@ -1616,8 +1637,8 @@ async function main() {
1616
1637
  }
1617
1638
  process.exit(1);
1618
1639
  }
1619
- s.stop("iii-engine is ready");
1620
- await import("./src-u7kAEUC0.mjs");
1640
+ s.stop(c.ok("iii-engine is ready"));
1641
+ await import("./src-CzgoepGU.mjs");
1621
1642
  if (await waitForAgentmemoryReady(15e3)) {
1622
1643
  const consoleState = await ensureIiiConsole();
1623
1644
  await maybeOfferGlobalInstall();
@@ -1675,7 +1696,7 @@ async function runStatus() {
1675
1696
  const pctSaved = estFullTokens > 0 ? Math.round(tokensSaved / estFullTokens * 100) : 0;
1676
1697
  p.log.success(`Connected — v${version} at ${base}`);
1677
1698
  const lines = [
1678
- `Health: ${status === "healthy" ? "✓ healthy" : status}`,
1699
+ `Health: ${status === "healthy" ? pc.green("✓ healthy") : pc.yellow(status)}`,
1679
1700
  `Sessions: ${sessions}`,
1680
1701
  `Observations: ${obsCount}`,
1681
1702
  `Memories: ${memCount}`,
@@ -1683,7 +1704,7 @@ async function runStatus() {
1683
1704
  `Circuit: ${cb}`,
1684
1705
  `Heap: ${heapMB} MB`,
1685
1706
  `Uptime: ${uptime}s`,
1686
- `Viewer: ${getViewerUrl()}`
1707
+ `Viewer: ${c.url(getViewerUrl())}`
1687
1708
  ];
1688
1709
  if (obsCount > 0) {
1689
1710
  lines.push("");
@@ -1692,9 +1713,9 @@ async function runStatus() {
1692
1713
  lines.push(` Injected: ~${estInjectedTokens.toLocaleString()} tokens`);
1693
1714
  }
1694
1715
  if (flagsRes) {
1695
- const provider = flagsRes.provider === "llm" ? "✓ llm" : "✗ noop (no key)";
1696
- const embed = flagsRes.embeddingProvider === "embeddings" ? "✓ embeddings" : "bm25-only";
1697
- const flagRows = (flagsRes.flags || []).map((f) => ` ${f.enabled ? "✓" : "✗"} ${f.key.padEnd(32)} ${f.label}`);
1716
+ const provider = flagsRes.provider === "llm" ? pc.green("✓ llm") : pc.yellow("✗ noop (no key)");
1717
+ const embed = flagsRes.embeddingProvider === "embeddings" ? pc.green("✓ embeddings") : pc.dim("bm25-only");
1718
+ const flagRows = (flagsRes.flags || []).map((f) => ` ${f.enabled ? pc.green("✓") : pc.dim("✗")} ${pc.bold(f.key.padEnd(32))} ${f.label}`);
1698
1719
  lines.push("");
1699
1720
  lines.push(`Provider: ${provider}`);
1700
1721
  lines.push(`Embeddings: ${embed}`);
@@ -1715,7 +1736,7 @@ async function runStatus() {
1715
1736
  }
1716
1737
  }
1717
1738
  function formatChecks(checks) {
1718
- return checks.map((c) => `${c.ok ? "✓" : "✗"} ${c.name}${c.hint ? `\n ${c.hint}` : ""}`).join("\n");
1739
+ return checks.map((c) => `${c.ok ? pc.green("✓") : pc.red("✗")} ${c.name}${c.hint ? `\n ${c.hint}` : ""}`).join("\n");
1719
1740
  }
1720
1741
  function findLatestDebugLog(debugDir) {
1721
1742
  const latestLink = join(debugDir, "latest");
@@ -2251,15 +2272,63 @@ async function runInit() {
2251
2272
  ].join("\n"), "Next steps");
2252
2273
  p.outro(`Edit ${target} and you're set.`);
2253
2274
  }
2275
+ async function startServerForDemo() {
2276
+ if (await isAgentmemoryReady()) return async () => {};
2277
+ const startedEngine = !await isEngineRunning();
2278
+ if (startedEngine) {
2279
+ if (!await startEngine()) {
2280
+ p.log.error("Could not start iii-engine for the demo.");
2281
+ p.note(installInstructions().join("\n"), "Setup required");
2282
+ process.exit(1);
2283
+ }
2284
+ if (!await waitForEngine(15e3)) {
2285
+ p.log.error("iii-engine did not become ready within 15s.");
2286
+ process.exit(1);
2287
+ }
2288
+ }
2289
+ await import("./src-CzgoepGU.mjs");
2290
+ if (!await waitForAgentmemoryReady(15e3)) {
2291
+ p.log.error("agentmemory worker did not become ready within 15s.");
2292
+ process.exit(1);
2293
+ }
2294
+ return async () => {
2295
+ if (!startedEngine) return;
2296
+ const port = getRestPort();
2297
+ const state = readEngineState();
2298
+ if (state?.kind === "docker") {
2299
+ await stopDockerEngine(state.composeFile, port).catch(() => {});
2300
+ return;
2301
+ }
2302
+ const pids = new Set(findEnginePidsByPort(port));
2303
+ const pidfilePid = readEnginePidfile();
2304
+ if (pidfilePid) pids.add(pidfilePid);
2305
+ for (const pid of pids) await signalAndWait(pid, "SIGTERM", 3e3).catch(() => {});
2306
+ clearEnginePidfile();
2307
+ clearEngineState();
2308
+ clearWorkerPidfile();
2309
+ };
2310
+ }
2254
2311
  async function runDemo() {
2255
2312
  const port = getRestPort();
2256
2313
  const base = `http://localhost:${port}`;
2257
2314
  p.intro("agentmemory demo");
2258
- if (!await isAgentmemoryReady()) {
2315
+ const serve = args.includes("--serve");
2316
+ let teardown = async () => {};
2317
+ if (serve) teardown = await startServerForDemo();
2318
+ else if (!await isAgentmemoryReady()) {
2259
2319
  p.log.error(`agentmemory worker not reachable on port ${port} (livez probe failed). Something may be on the port but it isn't serving /agentmemory/*.`);
2260
2320
  p.log.info("Start it with: npx @agentmemory/agentmemory");
2321
+ p.log.info("Or run a one-command demo with: npx @agentmemory/agentmemory demo --serve");
2261
2322
  process.exit(1);
2262
2323
  }
2324
+ try {
2325
+ await runDemoBody(base);
2326
+ } finally {
2327
+ await teardown();
2328
+ }
2329
+ if (serve) process.exit(0);
2330
+ }
2331
+ async function runDemoBody(base) {
2263
2332
  const demoProject = "/tmp/agentmemory-demo";
2264
2333
  const sessions = buildDemoSessions();
2265
2334
  const sSeed = p.spinner();
@@ -2281,14 +2350,14 @@ async function runDemo() {
2281
2350
  `Project: ${demoProject}`,
2282
2351
  `Sessions: ${sessions.length} seeded (${totalObs} observations)`,
2283
2352
  "",
2284
- "Search results:",
2285
- ...results.flatMap((r) => [` "${r.query}"`, ` → ${r.hits} hit(s), top: ${r.topTitle.slice(0, 60)}`]),
2353
+ c.label("Search results:"),
2354
+ ...results.flatMap((r) => [` ${c.label(`"${r.query}"`)}`, ` ${c.dim("→")} ${c.ok(`${r.hits} hit(s)`)}, top: ${r.topTitle.slice(0, 60)}`]),
2286
2355
  "",
2287
- `Notice: searching "database performance optimization"`,
2288
- `found the N+1 query fix — keyword matching can't do that.`,
2356
+ c.accent(`Notice: searching "database performance optimization"`),
2357
+ c.accent(`found the N+1 query fix — keyword matching can't do that.`),
2289
2358
  "",
2290
- `Viewer: ${getViewerUrl()}`,
2291
- `Clean up with: curl -X DELETE "${base}/agentmemory/sessions?project=${demoProject}"`
2359
+ `Viewer: ${c.url(getViewerUrl())}`,
2360
+ `Clean up with: ${c.dim(`curl -X DELETE "${base}/agentmemory/sessions?project=${demoProject}"`)}`
2292
2361
  ];
2293
2362
  p.note(lines.join("\n"), "demo complete");
2294
2363
  p.log.success("agentmemory is working. Point your agent at it and get back to coding.");
@@ -2302,7 +2371,7 @@ function runCommand(command, commandArgs, options = { label: "command" }) {
2302
2371
  encoding: "utf-8"
2303
2372
  });
2304
2373
  if (result.status === 0) {
2305
- spinner.stop(`${options.label} ✓`);
2374
+ spinner.stop(`${options.label} ${pc.green("✓")}`);
2306
2375
  return true;
2307
2376
  }
2308
2377
  const stderr = (result.stderr || "").toString().trim();
@@ -2313,7 +2382,7 @@ function runCommand(command, commandArgs, options = { label: "command" }) {
2313
2382
  p.log.warn(msg.slice(0, 300));
2314
2383
  return false;
2315
2384
  }
2316
- spinner.stop(`${options.label} ✗`);
2385
+ spinner.stop(`${options.label} ${pc.red("✗")}`);
2317
2386
  p.log.error(msg.slice(0, 300));
2318
2387
  return false;
2319
2388
  }
@@ -2525,19 +2594,19 @@ async function runStop() {
2525
2594
  process.exit(1);
2526
2595
  }
2527
2596
  let allStopped = true;
2528
- for (const pid of candidates) {
2597
+ for (const pid of workerCandidates) {
2529
2598
  const s = p.spinner();
2530
- s.start(`Stopping iii-engine (pid ${pid})...`);
2531
- const ok = await signalAndWait(pid, "SIGTERM", 3e3);
2532
- s.stop(ok ? `Stopped pid ${pid}` : `Failed to stop pid ${pid}`);
2599
+ s.start(`Stopping agentmemory worker (pid ${pid})... [flushing state]`);
2600
+ const ok = await signalAndWait(pid, "SIGTERM", 5e3);
2601
+ s.stop(ok ? `Stopped worker pid ${pid}` : `Failed to stop worker pid ${pid}`);
2533
2602
  if (!ok) allStopped = false;
2534
2603
  }
2535
- for (const pid of workerCandidates) {
2536
- if (candidates.has(pid)) continue;
2604
+ for (const pid of candidates) {
2605
+ if (workerCandidates.has(pid)) continue;
2537
2606
  const s = p.spinner();
2538
- s.start(`Stopping agentmemory worker (pid ${pid})...`);
2607
+ s.start(`Stopping iii-engine (pid ${pid})...`);
2539
2608
  const ok = await signalAndWait(pid, "SIGTERM", 3e3);
2540
- s.stop(ok ? `Stopped worker pid ${pid}` : `Failed to stop worker pid ${pid}`);
2609
+ s.stop(ok ? `Stopped pid ${pid}` : `Failed to stop pid ${pid}`);
2541
2610
  if (!ok) allStopped = false;
2542
2611
  }
2543
2612
  clearEnginePidfile();
@@ -2550,10 +2619,10 @@ async function runStop() {
2550
2619
  p.outro("Stopped. Memories persisted to disk; restart anytime with: npx @agentmemory/agentmemory");
2551
2620
  }
2552
2621
  async function runMcp() {
2553
- await import("./standalone-C1yPO519.mjs");
2622
+ await import("./standalone-YsZFFQBM.mjs");
2554
2623
  }
2555
2624
  async function runConnectCmd() {
2556
- const { runConnect } = await import("./connect-bmZ5eqYN.mjs").then((n) => n.t);
2625
+ const { runConnect } = await import("./connect-JnsJXc68.mjs").then((n) => n.n);
2557
2626
  await runConnect(args.slice(1));
2558
2627
  }
2559
2628
  async function runImportJsonl() {