@agentmemory/agentmemory 0.9.15 → 0.9.16

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.
package/dist/cli.mjs CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import { createRequire } from "node:module";
2
3
  import { execFileSync, spawn, spawnSync } from "node:child_process";
3
- import { closeSync, constants, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, readdirSync, readlinkSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
4
+ import { closeSync, constants, copyFileSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, readdirSync, readlinkSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
4
5
  import { delimiter, dirname, join } from "node:path";
5
6
  import { fileURLToPath } from "node:url";
6
7
  import { homedir, platform } from "node:os";
@@ -8,6 +9,23 @@ import * as p from "@clack/prompts";
8
9
  import { createHash } from "node:crypto";
9
10
  import { copyFile, mkdir } from "node:fs/promises";
10
11
 
12
+ //#region \0rolldown/runtime.js
13
+ var __defProp = Object.defineProperty;
14
+ var __exportAll = (all, no_symbols) => {
15
+ let target = {};
16
+ for (var name in all) {
17
+ __defProp(target, name, {
18
+ get: all[name],
19
+ enumerable: true
20
+ });
21
+ }
22
+ if (!no_symbols) {
23
+ __defProp(target, Symbol.toStringTag, { value: "Module" });
24
+ }
25
+ return target;
26
+ };
27
+
28
+ //#endregion
11
29
  //#region src/state/schema.ts
12
30
  const KV = {
13
31
  sessions: "mem:sessions",
@@ -304,7 +322,7 @@ function envPath(home) {
304
322
  function preferencesPath(home) {
305
323
  return join(home, ".agentmemory", "preferences.json");
306
324
  }
307
- function backupsDir(home) {
325
+ function backupsDir$1(home) {
308
326
  return join(home, ".agentmemory", "backups");
309
327
  }
310
328
  function dataDir(home) {
@@ -380,9 +398,9 @@ function buildRemovePlan(ctx, options) {
380
398
  plan.push({
381
399
  id: "backups",
382
400
  description: "Delete backups/ directory (connect manifest + backups)",
383
- path: backupsDir(home),
401
+ path: backupsDir$1(home),
384
402
  alwaysAsk: false,
385
- applicable: !options.keepData && pathExists(backupsDir(home)),
403
+ applicable: !options.keepData && pathExists(backupsDir$1(home)),
386
404
  sizeBytes: -1
387
405
  });
388
406
  if (connectManifest?.installed?.length) for (const entry of connectManifest.installed) plan.push({
@@ -448,12 +466,12 @@ function getTerminalWidth() {
448
466
  const TAGLINE = "Persistent memory for AI coding agents";
449
467
  function fullBanner(version) {
450
468
  const lines = ["", ...[
451
- " _ ",
452
- " __ _ __ _ ___ _ _ | |_ _ __ ___ _ __ ___ ___ _ __ _ _ ",
453
- " / _` |/ _` |/ _ \\ '_\\| __| ' \\/ -_) ' \\ _ \\ / _ \\| '__| | | | ",
454
- "| (_| | (_| | __/ | || |_| | | \\___| | | | | | (_) | | | |_| | ",
455
- " \\__,_|\\__, |\\___|_| \\__|_| |_| |_| |_| |_|\\___/|_| \\__, | ",
456
- " |___/ |___/ "
469
+ " _ ",
470
+ " __ _ __ _ ___ _ __ | |_ _ __ ___ ___ _ __ ___ ___ _ __ _ _ ",
471
+ " / _` |/ _` |/ _ \\ '_ \\| __| '_ ` _ \\ / _ \\ '_ ` _ \\ / _ \\| '__| | | |",
472
+ "| (_| | (_| | __/ | | | |_| | | | | | __/ | | | | | (_) | | | |_| |",
473
+ " \\__,_|\\__, |\\___|_| |_|\\__|_| |_| |_|\\___|_| |_| |_|\\___/|_| \\__, |",
474
+ " |___/ |___/ "
457
475
  ].map((line) => " " + accent(line))];
458
476
  lines.push("");
459
477
  lines.push(" " + bold(TAGLINE) + " " + dim(`v${version}`));
@@ -489,6 +507,8 @@ const DEFAULTS = {
489
507
  lastProvider: null,
490
508
  skipSplash: false,
491
509
  skipNpxHint: false,
510
+ skipGlobalInstall: false,
511
+ skipConsoleInstall: false,
492
512
  firstRunAt: null
493
513
  };
494
514
  function prefsDir() {
@@ -543,6 +563,541 @@ function isFirstRun() {
543
563
  return readPrefs().firstRunAt === null;
544
564
  }
545
565
 
566
+ //#endregion
567
+ //#region src/cli/connect/util.ts
568
+ const AGENTMEMORY_MCP_BLOCK = {
569
+ command: "npx",
570
+ args: ["-y", "@agentmemory/mcp"],
571
+ env: { AGENTMEMORY_URL: "http://localhost:3111" }
572
+ };
573
+ function backupsDir() {
574
+ return join(homedir(), ".agentmemory", "backups");
575
+ }
576
+ function ensureBackupsDir() {
577
+ const dir = backupsDir();
578
+ mkdirSync(dir, { recursive: true });
579
+ return dir;
580
+ }
581
+ function timestampSlug() {
582
+ return (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
583
+ }
584
+ function backupFile(sourcePath, agent, ext = "json") {
585
+ ensureBackupsDir();
586
+ const stamp = timestampSlug();
587
+ const target = join(backupsDir(), `${agent}-${stamp}.${ext}`);
588
+ copyFileSync(sourcePath, target);
589
+ return target;
590
+ }
591
+ function readJsonSafe(path) {
592
+ if (!existsSync(path)) return null;
593
+ try {
594
+ return JSON.parse(readFileSync(path, "utf-8"));
595
+ } catch {
596
+ return null;
597
+ }
598
+ }
599
+ function writeJsonAtomic(path, value) {
600
+ mkdirSync(dirname(path), { recursive: true });
601
+ const tmp = `${path}.tmp-${process.pid}-${Date.now()}`;
602
+ writeFileSync(tmp, `${JSON.stringify(value, null, 2)}\n`, "utf-8");
603
+ renameSync(tmp, path);
604
+ }
605
+ function logInstalled(label, target) {
606
+ p.log.success(`${label} → wired into ${target}`);
607
+ }
608
+ function logAlreadyWired(label, target) {
609
+ p.log.info(`${label} already wired in ${target} (use --force to re-install)`);
610
+ }
611
+ function logBackup(target) {
612
+ p.log.info(`Backup: ${target}`);
613
+ }
614
+
615
+ //#endregion
616
+ //#region src/cli/connect/claude-code.ts
617
+ const CLAUDE_DIR = join(homedir(), ".claude");
618
+ const CLAUDE_JSON = join(homedir(), ".claude.json");
619
+ function entryMatches$1(entry) {
620
+ if (!entry || typeof entry !== "object") return false;
621
+ const e = entry;
622
+ if (e["command"] !== "npx") return false;
623
+ return (Array.isArray(e["args"]) ? e["args"] : []).includes("@agentmemory/mcp");
624
+ }
625
+ const adapter$7 = {
626
+ name: "claude-code",
627
+ displayName: "Claude Code",
628
+ docs: "https://github.com/rohitg00/agentmemory#claude-code-one-block-paste-it",
629
+ protocolNote: "→ Using MCP. Hooks are also available — see docs/claude-code.md.",
630
+ detect() {
631
+ return existsSync(CLAUDE_DIR);
632
+ },
633
+ async install(opts) {
634
+ const existing = readJsonSafe(CLAUDE_JSON);
635
+ const next = existing ? { ...existing } : {};
636
+ const servers = { ...next.mcpServers ?? {} };
637
+ const alreadyHas = entryMatches$1(servers["agentmemory"]);
638
+ if (alreadyHas && !opts.force) {
639
+ logAlreadyWired("Claude Code", CLAUDE_JSON);
640
+ return {
641
+ kind: "already-wired",
642
+ mutatedPath: CLAUDE_JSON
643
+ };
644
+ }
645
+ if (opts.dryRun) {
646
+ p.log.info(`[dry-run] Would ${alreadyHas ? "overwrite" : "add"} mcpServers.agentmemory in ${CLAUDE_JSON}`);
647
+ return {
648
+ kind: "installed",
649
+ mutatedPath: CLAUDE_JSON
650
+ };
651
+ }
652
+ let backupPath;
653
+ if (existsSync(CLAUDE_JSON)) {
654
+ backupPath = backupFile(CLAUDE_JSON, "claude-code");
655
+ logBackup(backupPath);
656
+ } else {
657
+ mkdirSync(CLAUDE_DIR, { recursive: true });
658
+ writeFileSync(CLAUDE_JSON, "{}\n", "utf-8");
659
+ }
660
+ servers["agentmemory"] = AGENTMEMORY_MCP_BLOCK;
661
+ next.mcpServers = servers;
662
+ writeJsonAtomic(CLAUDE_JSON, next);
663
+ if (!entryMatches$1(readJsonSafe(CLAUDE_JSON)?.mcpServers?.["agentmemory"])) {
664
+ p.log.error(`Verification failed: ${CLAUDE_JSON} did not contain mcpServers.agentmemory after write.`);
665
+ return {
666
+ kind: "skipped",
667
+ reason: "verification-failed"
668
+ };
669
+ }
670
+ logInstalled("Claude Code", CLAUDE_JSON);
671
+ p.log.info("Restart Claude Code (or run `/mcp` inside a session) to pick up the new server.");
672
+ return {
673
+ kind: "installed",
674
+ mutatedPath: CLAUDE_JSON,
675
+ backupPath
676
+ };
677
+ }
678
+ };
679
+
680
+ //#endregion
681
+ //#region src/cli/connect/codex.ts
682
+ const CODEX_DIR = join(homedir(), ".codex");
683
+ const CODEX_TOML = join(CODEX_DIR, "config.toml");
684
+ const TOML_BLOCK = `[mcp_servers.agentmemory]
685
+ command = "npx"
686
+ args = ["-y", "@agentmemory/mcp"]
687
+
688
+ [mcp_servers.agentmemory.env]
689
+ AGENTMEMORY_URL = "http://localhost:3111"
690
+ `;
691
+ const SECTION_HEADER = "[mcp_servers.agentmemory]";
692
+ function isWiredText(toml) {
693
+ return toml.includes(SECTION_HEADER);
694
+ }
695
+ function stripExistingBlock(toml) {
696
+ const lines = toml.split(/\r?\n/);
697
+ const out = [];
698
+ let skipping = false;
699
+ for (const line of lines) {
700
+ const trimmed = line.trim();
701
+ if (trimmed === SECTION_HEADER || trimmed === "[mcp_servers.agentmemory.env]") {
702
+ skipping = true;
703
+ continue;
704
+ }
705
+ if (skipping && trimmed.startsWith("[") && trimmed !== "[mcp_servers.agentmemory.env]") skipping = false;
706
+ if (!skipping) out.push(line);
707
+ }
708
+ return out.join("\n").replace(/\n{3,}$/, "\n\n").trimEnd() + "\n";
709
+ }
710
+ const adapter$6 = {
711
+ name: "codex",
712
+ displayName: "Codex CLI",
713
+ docs: "https://github.com/rohitg00/agentmemory#codex-cli-codex-plugin-platform",
714
+ protocolNote: "→ Using MCP. Hooks are also available — see docs/codex.md.",
715
+ detect() {
716
+ return existsSync(CODEX_DIR);
717
+ },
718
+ async install(opts) {
719
+ const exists = existsSync(CODEX_TOML);
720
+ const current = exists ? readFileSync(CODEX_TOML, "utf-8") : "";
721
+ const wired = isWiredText(current);
722
+ if (wired && !opts.force) {
723
+ logAlreadyWired("Codex CLI", CODEX_TOML);
724
+ return {
725
+ kind: "already-wired",
726
+ mutatedPath: CODEX_TOML
727
+ };
728
+ }
729
+ if (opts.dryRun) {
730
+ p.log.info(`[dry-run] Would ${wired ? "rewrite" : "append"} [mcp_servers.agentmemory] in ${CODEX_TOML}`);
731
+ return {
732
+ kind: "installed",
733
+ mutatedPath: CODEX_TOML
734
+ };
735
+ }
736
+ let backupPath;
737
+ if (exists) {
738
+ backupPath = backupFile(CODEX_TOML, "codex", "toml");
739
+ logBackup(backupPath);
740
+ } else mkdirSync(dirname(CODEX_TOML), { recursive: true });
741
+ const cleaned = wired ? stripExistingBlock(current) : current;
742
+ writeFileSync(CODEX_TOML, `${cleaned}${cleaned.length === 0 || cleaned.endsWith("\n") ? "" : "\n"}${cleaned.length > 0 ? "\n" : ""}${TOML_BLOCK}`, "utf-8");
743
+ if (!isWiredText(readFileSync(CODEX_TOML, "utf-8"))) {
744
+ p.log.error(`Verification failed: ${CODEX_TOML} did not contain ${SECTION_HEADER} after write.`);
745
+ return {
746
+ kind: "skipped",
747
+ reason: "verification-failed"
748
+ };
749
+ }
750
+ logInstalled("Codex CLI", CODEX_TOML);
751
+ p.log.info("Codex picks up MCP servers on next launch. For the deeper plugin install, run: codex plugin marketplace add rohitg00/agentmemory && codex plugin install agentmemory");
752
+ return {
753
+ kind: "installed",
754
+ mutatedPath: CODEX_TOML,
755
+ ...backupPath !== void 0 && { backupPath }
756
+ };
757
+ }
758
+ };
759
+
760
+ //#endregion
761
+ //#region src/cli/connect/json-mcp-adapter.ts
762
+ function entryMatches(entry) {
763
+ if (!entry || typeof entry !== "object") return false;
764
+ const e = entry;
765
+ if (e["command"] !== "npx") return false;
766
+ return (Array.isArray(e["args"]) ? e["args"] : []).includes("@agentmemory/mcp");
767
+ }
768
+ function createJsonMcpAdapter(config) {
769
+ return {
770
+ name: config.name,
771
+ displayName: config.displayName,
772
+ ...config.docs !== void 0 && { docs: config.docs },
773
+ ...config.protocolNote !== void 0 && { protocolNote: config.protocolNote },
774
+ detect() {
775
+ return existsSync(config.detectDir);
776
+ },
777
+ async install(opts) {
778
+ const existing = readJsonSafe(config.configPath);
779
+ const next = existing ? { ...existing } : {};
780
+ const servers = { ...next.mcpServers ?? {} };
781
+ const alreadyHas = entryMatches(servers["agentmemory"]);
782
+ if (alreadyHas && !opts.force) {
783
+ logAlreadyWired(config.displayName, config.configPath);
784
+ return {
785
+ kind: "already-wired",
786
+ mutatedPath: config.configPath
787
+ };
788
+ }
789
+ if (opts.dryRun) {
790
+ p.log.info(`[dry-run] Would ${alreadyHas ? "overwrite" : "add"} mcpServers.agentmemory in ${config.configPath}`);
791
+ return {
792
+ kind: "installed",
793
+ mutatedPath: config.configPath
794
+ };
795
+ }
796
+ let backupPath;
797
+ if (existsSync(config.configPath)) {
798
+ backupPath = backupFile(config.configPath, config.name);
799
+ logBackup(backupPath);
800
+ } else mkdirSync(dirname(config.configPath), { recursive: true });
801
+ servers["agentmemory"] = AGENTMEMORY_MCP_BLOCK;
802
+ next.mcpServers = servers;
803
+ writeJsonAtomic(config.configPath, next);
804
+ if (!entryMatches(readJsonSafe(config.configPath)?.mcpServers?.["agentmemory"])) {
805
+ p.log.error(`Verification failed: ${config.configPath} did not contain mcpServers.agentmemory after write.`);
806
+ return {
807
+ kind: "skipped",
808
+ reason: "verification-failed"
809
+ };
810
+ }
811
+ logInstalled(config.displayName, config.configPath);
812
+ return {
813
+ kind: "installed",
814
+ mutatedPath: config.configPath,
815
+ ...backupPath !== void 0 && { backupPath }
816
+ };
817
+ }
818
+ };
819
+ }
820
+
821
+ //#endregion
822
+ //#region src/cli/connect/cursor.ts
823
+ const adapter$5 = createJsonMcpAdapter({
824
+ name: "cursor",
825
+ displayName: "Cursor",
826
+ detectDir: join(homedir(), ".cursor"),
827
+ configPath: join(homedir(), ".cursor", "mcp.json"),
828
+ docs: "https://github.com/rohitg00/agentmemory#other-agents",
829
+ protocolNote: "→ Using MCP (the only protocol Cursor speaks). Memory bridge runs at :3111 underneath."
830
+ });
831
+
832
+ //#endregion
833
+ //#region src/cli/connect/gemini-cli.ts
834
+ const adapter$4 = createJsonMcpAdapter({
835
+ name: "gemini-cli",
836
+ displayName: "Gemini CLI",
837
+ detectDir: join(homedir(), ".gemini"),
838
+ configPath: join(homedir(), ".gemini", "settings.json"),
839
+ docs: "https://github.com/rohitg00/agentmemory#other-agents",
840
+ protocolNote: "→ Using MCP (the only protocol Gemini CLI speaks). Memory bridge runs at :3111 underneath."
841
+ });
842
+
843
+ //#endregion
844
+ //#region src/cli/connect/hermes.ts
845
+ const HERMES_DIR = join(homedir(), ".hermes");
846
+ const HERMES_CONFIG = join(HERMES_DIR, "config.yaml");
847
+ const DOCS$2 = "https://github.com/rohitg00/agentmemory/tree/main/integrations/hermes";
848
+ const adapter$3 = {
849
+ name: "hermes",
850
+ displayName: "Hermes Agent",
851
+ docs: DOCS$2,
852
+ protocolNote: "→ Using MCP. Hooks are also available — see docs/hermes.md.",
853
+ detect() {
854
+ return existsSync(HERMES_DIR);
855
+ },
856
+ async install(_opts) {
857
+ p.log.warn("Hermes uses YAML config. Automated merge isn't implemented yet — manual install required.");
858
+ p.note([
859
+ `Add to ${HERMES_CONFIG}:`,
860
+ "",
861
+ " mcp_servers:",
862
+ " agentmemory:",
863
+ " command: npx",
864
+ " args: [\"-y\", \"@agentmemory/mcp\"]",
865
+ "",
866
+ " memory:",
867
+ " provider: agentmemory",
868
+ "",
869
+ `Full guide: ${DOCS$2}`
870
+ ].join("\n"), "Hermes manual install");
871
+ return {
872
+ kind: "stub",
873
+ reason: "yaml-merge-not-implemented"
874
+ };
875
+ }
876
+ };
877
+
878
+ //#endregion
879
+ //#region src/cli/connect/openclaw.ts
880
+ const adapter$2 = createJsonMcpAdapter({
881
+ name: "openclaw",
882
+ displayName: "OpenClaw",
883
+ detectDir: join(homedir(), ".openclaw"),
884
+ configPath: join(homedir(), ".openclaw", "openclaw.json"),
885
+ docs: "https://github.com/rohitg00/agentmemory/tree/main/integrations/openclaw",
886
+ protocolNote: "→ Using MCP. Hooks are also available — see docs/openclaw.md."
887
+ });
888
+
889
+ //#endregion
890
+ //#region src/cli/connect/openhuman.ts
891
+ const OPENHUMAN_DIR = join(homedir(), ".openhuman");
892
+ const DOCS$1 = "https://github.com/tinyhumansai/openhuman";
893
+ const adapter$1 = {
894
+ name: "openhuman",
895
+ displayName: "OpenHuman",
896
+ docs: DOCS$1,
897
+ protocolNote: "→ Using native hooks (REST API at :3111). MCP not required.",
898
+ detect() {
899
+ return existsSync(OPENHUMAN_DIR);
900
+ },
901
+ async install(_opts) {
902
+ p.log.warn("OpenHuman integration is not yet automated. No `integrations/openhuman/` folder exists in the agentmemory repo today.");
903
+ p.note([
904
+ "OpenHuman is a Memory-trait host. The expected wiring is the REST",
905
+ "proxy at http://localhost:3111 plus an OpenHuman-side Memory trait",
906
+ "impl. Once integrations/openhuman/ lands in agentmemory we'll wire",
907
+ "this up automatically.",
908
+ "",
909
+ `Tracking: ${DOCS$1}`
910
+ ].join("\n"), "OpenHuman manual install");
911
+ return {
912
+ kind: "stub",
913
+ reason: "no-integration-folder-yet"
914
+ };
915
+ }
916
+ };
917
+
918
+ //#endregion
919
+ //#region src/cli/connect/pi.ts
920
+ const PI_DIR = join(homedir(), ".pi");
921
+ const PI_EXT_DIR = join(PI_DIR, "agent", "extensions", "agentmemory");
922
+ const DOCS = "https://github.com/rohitg00/agentmemory/tree/main/integrations/pi";
923
+ const adapter = {
924
+ name: "pi",
925
+ displayName: "pi",
926
+ docs: DOCS,
927
+ protocolNote: "→ Using native hooks (REST API at :3111). MCP not required.",
928
+ detect() {
929
+ return existsSync(PI_DIR);
930
+ },
931
+ async install(_opts) {
932
+ p.log.warn("pi uses a TypeScript extension file. Automated copy + register isn't implemented yet — manual install required.");
933
+ p.note([
934
+ "Run these from the agentmemory repo root:",
935
+ "",
936
+ ` mkdir -p ${PI_EXT_DIR}`,
937
+ ` cp integrations/pi/index.ts ${PI_EXT_DIR}/index.ts`,
938
+ ` cp integrations/pi/security.ts ${PI_EXT_DIR}/security.ts`,
939
+ "",
940
+ "Then add to ~/.pi/agent/settings.json:",
941
+ " { \"extensions\": [\"~/.pi/agent/extensions/agentmemory\"] }",
942
+ "",
943
+ `Full guide: ${DOCS}`
944
+ ].join("\n"), "pi manual install");
945
+ return {
946
+ kind: "stub",
947
+ reason: "ts-extension-copy-not-implemented"
948
+ };
949
+ }
950
+ };
951
+
952
+ //#endregion
953
+ //#region src/cli/connect/index.ts
954
+ var connect_exports = /* @__PURE__ */ __exportAll({
955
+ ADAPTERS: () => ADAPTERS,
956
+ knownAgents: () => knownAgents,
957
+ resolveAdapter: () => resolveAdapter,
958
+ runAdapter: () => runAdapter,
959
+ runConnect: () => runConnect
960
+ });
961
+ const ADAPTERS = [
962
+ adapter$7,
963
+ adapter$6,
964
+ adapter$5,
965
+ adapter$4,
966
+ adapter$2,
967
+ adapter$3,
968
+ adapter,
969
+ adapter$1
970
+ ];
971
+ function resolveAdapter(name) {
972
+ const lower = name.toLowerCase();
973
+ return ADAPTERS.find((a) => a.name === lower) ?? null;
974
+ }
975
+ function knownAgents() {
976
+ return ADAPTERS.map((a) => a.name);
977
+ }
978
+ function parseFlags(args) {
979
+ const positional = [];
980
+ let dryRun = false;
981
+ let force = false;
982
+ let all = false;
983
+ for (const a of args) if (a === "--dry-run") dryRun = true;
984
+ else if (a === "--force") force = true;
985
+ else if (a === "--all") all = true;
986
+ else if (!a.startsWith("-")) positional.push(a);
987
+ return {
988
+ dryRun,
989
+ force,
990
+ all,
991
+ positional
992
+ };
993
+ }
994
+ async function runAdapter(adapter, opts) {
995
+ if (!adapter.detect()) {
996
+ p.log.warn(`${adapter.displayName}: not detected on this machine (skipping).${adapter.docs ? ` Docs: ${adapter.docs}` : ""}`);
997
+ return {
998
+ kind: "skipped",
999
+ reason: "not-detected"
1000
+ };
1001
+ }
1002
+ p.log.step(`Wiring ${adapter.displayName}…`);
1003
+ if (adapter.protocolNote) p.log.message(adapter.protocolNote);
1004
+ try {
1005
+ return await adapter.install(opts);
1006
+ } catch (err) {
1007
+ p.log.error(`${adapter.displayName}: ${err instanceof Error ? err.message : String(err)}`);
1008
+ return {
1009
+ kind: "skipped",
1010
+ reason: "exception"
1011
+ };
1012
+ }
1013
+ }
1014
+ async function runConnect(args) {
1015
+ if (platform() === "win32") {
1016
+ p.intro("agentmemory connect");
1017
+ p.log.warn("Windows: automated `connect` is not supported yet. See https://github.com/rohitg00/agentmemory#other-agents for manual install steps.");
1018
+ p.outro("Windows: manual install required — see docs");
1019
+ return;
1020
+ }
1021
+ const { dryRun, force, all, positional } = parseFlags(args);
1022
+ const opts = {
1023
+ dryRun,
1024
+ force
1025
+ };
1026
+ p.intro("agentmemory connect");
1027
+ if (positional.length === 0 && !all) {
1028
+ const detected = ADAPTERS.filter((a) => a.detect());
1029
+ if (detected.length === 0) {
1030
+ p.log.error("No supported agents detected on this machine.");
1031
+ p.outro(`Supported: ${knownAgents().join(", ")}`);
1032
+ process.exit(1);
1033
+ }
1034
+ const picked = await p.multiselect({
1035
+ message: "Wire agentmemory into which agents?",
1036
+ options: detected.map((a) => ({
1037
+ value: a.name,
1038
+ label: a.displayName
1039
+ })),
1040
+ required: true
1041
+ });
1042
+ if (p.isCancel(picked)) {
1043
+ p.cancel("Cancelled.");
1044
+ return;
1045
+ }
1046
+ const results = [];
1047
+ for (const name of picked) {
1048
+ const adapter = resolveAdapter(name);
1049
+ if (!adapter) continue;
1050
+ results.push({
1051
+ name,
1052
+ result: await runAdapter(adapter, opts)
1053
+ });
1054
+ }
1055
+ summarize(results);
1056
+ return;
1057
+ }
1058
+ if (all) {
1059
+ const detected = ADAPTERS.filter((a) => a.detect());
1060
+ if (detected.length === 0) {
1061
+ p.log.error("No supported agents detected on this machine.");
1062
+ process.exit(1);
1063
+ }
1064
+ const results = [];
1065
+ for (const adapter of detected) results.push({
1066
+ name: adapter.name,
1067
+ result: await runAdapter(adapter, opts)
1068
+ });
1069
+ summarize(results);
1070
+ return;
1071
+ }
1072
+ const agentName = positional[0];
1073
+ const adapter = resolveAdapter(agentName);
1074
+ if (!adapter) {
1075
+ p.log.error(`Unknown agent: ${agentName}`);
1076
+ p.outro(`Supported: ${knownAgents().join(", ")}`);
1077
+ process.exit(1);
1078
+ }
1079
+ const result = await runAdapter(adapter, opts);
1080
+ summarize([{
1081
+ name: agentName,
1082
+ result
1083
+ }]);
1084
+ if (result.kind === "skipped" && result.reason !== "not-detected") process.exit(1);
1085
+ }
1086
+ function summarize(results) {
1087
+ const lines = results.map(({ name, result }) => {
1088
+ switch (result.kind) {
1089
+ case "installed": return ` ✓ ${name}${result.mutatedPath ? ` → ${result.mutatedPath}` : ""}`;
1090
+ case "already-wired": return ` ✓ ${name} (already wired)`;
1091
+ case "stub": return ` ⚠ ${name} (manual install required: ${result.reason})`;
1092
+ case "skipped": return ` ✗ ${name} (skipped: ${result.reason})`;
1093
+ }
1094
+ });
1095
+ p.note(lines.join("\n"), "summary");
1096
+ const stubs = results.filter((r) => r.result.kind === "stub");
1097
+ if (stubs.length > 0) p.log.info(`${stubs.length} agent(s) require manual install — see docs links above.`);
1098
+ p.outro("Restart any wired agent (or open a new session) to pick up agentmemory.");
1099
+ }
1100
+
546
1101
  //#endregion
547
1102
  //#region src/cli/onboarding.ts
548
1103
  const __dirname$1 = dirname(fileURLToPath(import.meta.url));
@@ -722,6 +1277,12 @@ async function runOnboarding() {
722
1277
  p.cancel("Setup cancelled. Re-run any time with: agentmemory --reset");
723
1278
  process.exit(0);
724
1279
  }
1280
+ if ((agentsPicked ?? []).length > 0) p.note([
1281
+ "━ how this works ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━",
1282
+ "All selected agents share the same memory at :3111.",
1283
+ "A memory saved by Claude Code is visible to Codex + Cursor instantly.",
1284
+ "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
1285
+ ].join("\n"));
725
1286
  const providerPicked = await p.select({
726
1287
  message: "Which LLM provider should agentmemory use for compress/consolidate?",
727
1288
  options: PROVIDERS.map(({ value, label }) => ({
@@ -752,11 +1313,82 @@ async function runOnboarding() {
752
1313
  if (envKey) lines.push(` Uncomment ${envKey}= in that file to enable ${provider}.`);
753
1314
  } else lines.push(" No provider chosen — agentmemory will run in BM25-only mode.");
754
1315
  p.note(lines.join("\n"), "ready");
1316
+ if (agents.length > 0) await wireSelectedAgents(agents);
755
1317
  return {
756
1318
  agents,
757
1319
  provider
758
1320
  };
759
1321
  }
1322
+ async function wireSelectedAgents(agents) {
1323
+ p.note("Wire selected agents now?", "next step");
1324
+ const confirmed = await p.confirm({
1325
+ message: "Run `agentmemory connect <agent>` for each selected agent now? [Y/n]",
1326
+ initialValue: true
1327
+ });
1328
+ if (p.isCancel(confirmed) || confirmed === false) {
1329
+ const cmds = agents.map((a) => ` agentmemory connect ${a}`);
1330
+ p.note(["Wire later with:", ...cmds].join("\n"), "later");
1331
+ return;
1332
+ }
1333
+ const wired = [];
1334
+ const manual = [];
1335
+ const failed = [];
1336
+ for (const name of agents) {
1337
+ const adapter = resolveAdapter(name);
1338
+ if (!adapter) {
1339
+ failed.push({
1340
+ name,
1341
+ reason: "no adapter available"
1342
+ });
1343
+ p.log.warn(`Wiring ${name}… no adapter available (skipped).`);
1344
+ continue;
1345
+ }
1346
+ p.log.step(`Wiring ${name}...`);
1347
+ let result;
1348
+ try {
1349
+ result = await runAdapter(adapter, {
1350
+ dryRun: false,
1351
+ force: false
1352
+ });
1353
+ } catch (err) {
1354
+ const reason = err instanceof Error ? err.message : String(err);
1355
+ failed.push({
1356
+ name,
1357
+ reason
1358
+ });
1359
+ p.log.error(`${name}: ${reason}`);
1360
+ continue;
1361
+ }
1362
+ switch (result.kind) {
1363
+ case "installed":
1364
+ case "already-wired":
1365
+ wired.push(name);
1366
+ break;
1367
+ case "stub":
1368
+ manual.push({
1369
+ name,
1370
+ docs: adapter.docs
1371
+ });
1372
+ break;
1373
+ case "skipped":
1374
+ failed.push({
1375
+ name,
1376
+ reason: result.reason
1377
+ });
1378
+ break;
1379
+ }
1380
+ }
1381
+ const summary = [];
1382
+ if (wired.length > 0) summary.push(`Wired: ${wired.join(", ")}.`);
1383
+ if (manual.length > 0 || failed.length > 0) {
1384
+ const parts = [];
1385
+ for (const m of manual) parts.push(`${m.name} (manual install required${m.docs ? ` — see ${m.docs}` : ""})`);
1386
+ for (const f of failed) parts.push(`${f.name} (${f.reason})`);
1387
+ summary.push(`Skipped/failed: ${parts.join(", ")}.`);
1388
+ }
1389
+ if (summary.length === 0) summary.push("No agents were wired.");
1390
+ p.note(summary.join("\n"), "wire summary");
1391
+ }
760
1392
 
761
1393
  //#endregion
762
1394
  //#region src/logger.ts
@@ -801,7 +1433,7 @@ function bootLog(msg) {
801
1433
 
802
1434
  //#endregion
803
1435
  //#region src/version.ts
804
- const VERSION = "0.9.15";
1436
+ const VERSION = "0.9.16";
805
1437
 
806
1438
  //#endregion
807
1439
  //#region src/cli.ts
@@ -857,7 +1489,8 @@ Commands:
857
1489
  --force bypasses the Docker-heuristic guard and signals
858
1490
  whatever pidfile+lsof report on the REST port (use when
859
1491
  the engine was started natively but state file is missing).
860
- mcp Start standalone MCP server (no engine required)
1492
+ mcp Start standalone MCP shim opt-in surface for MCP-only clients
1493
+ (Cursor, Gemini CLI, etc). REST always available at :3111.
861
1494
  import-jsonl [p] Import Claude Code JSONL transcripts (default: ~/.claude/projects)
862
1495
  --max-files <N> | --max-files=<N>: override scan cap (default 200, max 1000;
863
1496
  out-of-range is rejected; for trees >1000 files, batch by subdirectory)
@@ -911,12 +1544,25 @@ function getViewerUrl() {
911
1544
  if (envUrl) return envUrl.replace(/\/+$/, "");
912
1545
  try {
913
1546
  const u = new URL(getBaseUrl());
914
- const vPort = (parseInt(u.port || "3111", 10) || 3111) + 2;
1547
+ const vPort = parseInt(process.env["III_VIEWER_PORT"] || "", 10) || (parseInt(u.port || "3111", 10) || 3111) + 2;
915
1548
  return `${u.protocol}//${u.hostname}:${vPort}`;
916
1549
  } catch {
917
- return `http://localhost:${getRestPort() + 2}`;
1550
+ return `http://localhost:${parseInt(process.env["III_VIEWER_PORT"] || "", 10) || getRestPort() + 2}`;
918
1551
  }
919
1552
  }
1553
+ function getStreamPort() {
1554
+ return parseInt(process.env["III_STREAM_PORT"] || "", 10) || parseInt(process.env["III_STREAMS_PORT"] || "", 10) || 3112;
1555
+ }
1556
+ function getEnginePort() {
1557
+ const explicit = parseInt(process.env["III_ENGINE_PORT"] || "", 10);
1558
+ if (explicit) return explicit;
1559
+ const url = process.env["III_ENGINE_URL"];
1560
+ if (url) try {
1561
+ const parsed = new URL(url).port;
1562
+ if (parsed) return parseInt(parsed, 10);
1563
+ } catch {}
1564
+ return 49134;
1565
+ }
920
1566
  async function isEngineRunning() {
921
1567
  try {
922
1568
  await fetch(`${getBaseUrl()}/`, { signal: AbortSignal.timeout(2e3) });
@@ -990,7 +1636,7 @@ function warnIfEngineVersionMismatch(iiiBinPath) {
990
1636
  warnedVersionMismatch = true;
991
1637
  const asset = iiiReleaseAsset();
992
1638
  const downloadHint = asset ? `curl -fsSL https://github.com/iii-hq/iii/releases/download/iii/v${IIPINNED_VERSION}/${asset} | tar -xz -C ~/.local/bin` : `download v${IIPINNED_VERSION} from https://github.com/iii-hq/iii/releases/tag/iii%2Fv${IIPINNED_VERSION}`;
993
- p.log.warn(`iii-engine on PATH is v${detected} but agentmemory v0.9.14+ pins v${IIPINNED_VERSION}. Set AGENTMEMORY_III_VERSION=${detected} to silence, or downgrade with: \`${downloadHint}\``);
1639
+ p.log.warn(`iii-engine on PATH is v${detected} but agentmemory v${VERSION} pins v${IIPINNED_VERSION}. Set AGENTMEMORY_III_VERSION=${detected} to silence, or downgrade with: \`${downloadHint}\``);
994
1640
  }
995
1641
  function enginePidfilePath() {
996
1642
  return join(homedir(), ".agentmemory", "iii.pid");
@@ -1059,20 +1705,75 @@ function isInvokedViaNpx() {
1059
1705
  if (ua.startsWith("npm/") || ua.includes(" npm/")) return true;
1060
1706
  return false;
1061
1707
  }
1062
- function shouldSkipNpxHint() {
1063
- try {
1064
- const prefsPath = join(homedir(), ".agentmemory", "preferences.json");
1065
- if (!existsSync(prefsPath)) return false;
1066
- const raw = readFileSync(prefsPath, "utf-8");
1067
- return JSON.parse(raw)?.skipNpxHint === true;
1068
- } catch {
1069
- return false;
1070
- }
1071
- }
1072
- function maybeEmitNpxHint() {
1708
+ async function maybeOfferGlobalInstall() {
1073
1709
  if (!isInvokedViaNpx()) return;
1074
- if (shouldSkipNpxHint()) return;
1075
- p.log.info("Tip: install globally for the bare `agentmemory` command:\n npm install -g @agentmemory/agentmemory");
1710
+ if (!process.stdin.isTTY) return;
1711
+ if (process.env["CI"]) return;
1712
+ const prefs = readPrefs();
1713
+ if (prefs.skipGlobalInstall || prefs.skipNpxHint) return;
1714
+ const answer = await p.confirm({
1715
+ message: "Install agentmemory globally so the bare `agentmemory` command works in any shell? [Y/n]",
1716
+ initialValue: true
1717
+ });
1718
+ if (p.isCancel(answer)) return;
1719
+ if (answer === false) {
1720
+ writePrefs({ skipGlobalInstall: true });
1721
+ p.log.info("Skipped. Re-run via `npx @agentmemory/agentmemory` or install later with: npm install -g @agentmemory/agentmemory");
1722
+ return;
1723
+ }
1724
+ const npmBin = whichBinary("npm");
1725
+ if (!npmBin) {
1726
+ p.log.warn("npm not found on PATH. Install manually: npm install -g @agentmemory/agentmemory");
1727
+ return;
1728
+ }
1729
+ if (runCommand(npmBin, [
1730
+ "install",
1731
+ "-g",
1732
+ `@agentmemory/agentmemory@${VERSION}`
1733
+ ], { label: `Installing @agentmemory/agentmemory@${VERSION} globally` })) {
1734
+ p.log.success("Installed globally. `agentmemory stop` etc. will now work in new shells.");
1735
+ writePrefs({ skipGlobalInstall: true });
1736
+ } else p.log.warn("Global install failed. Try manually: npm install -g @agentmemory/agentmemory");
1737
+ }
1738
+ function detectIiiConsole() {
1739
+ const onPath = whichBinary("iii-console");
1740
+ if (onPath) return {
1741
+ kind: "installed",
1742
+ binPath: onPath
1743
+ };
1744
+ const fallback = IS_WINDOWS ? join(process.env["USERPROFILE"] ?? "", ".local", "bin", "iii-console.exe") : join(homedir(), ".local", "bin", "iii-console");
1745
+ if (fallback && existsSync(fallback)) return {
1746
+ kind: "installed",
1747
+ binPath: fallback
1748
+ };
1749
+ return { kind: "missing" };
1750
+ }
1751
+ const III_CONSOLE_INSTALL_CMD = "curl -fsSL https://install.iii.dev/console/main/install.sh | sh";
1752
+ async function ensureIiiConsole() {
1753
+ const state = detectIiiConsole();
1754
+ if (state.kind === "installed") return state;
1755
+ if (!process.stdin.isTTY || process.env["CI"]) return state;
1756
+ if (readPrefs().skipConsoleInstall) return state;
1757
+ const answer = await p.confirm({
1758
+ message: "iii console gives engine-level visibility (workers, functions, queues, traces). Install now?",
1759
+ initialValue: true
1760
+ });
1761
+ if (p.isCancel(answer)) return state;
1762
+ if (answer === false) {
1763
+ writePrefs({ skipConsoleInstall: true });
1764
+ return state;
1765
+ }
1766
+ const shBin = whichBinary("sh");
1767
+ const curlBin = whichBinary("curl");
1768
+ if (!shBin || !curlBin) {
1769
+ p.log.warn(`curl or sh not found. Install manually:\n ${III_CONSOLE_INSTALL_CMD}`);
1770
+ return state;
1771
+ }
1772
+ if (!runCommand(shBin, ["-c", III_CONSOLE_INSTALL_CMD], { label: "Installing iii console" })) {
1773
+ p.log.warn(`iii console install failed. Re-run manually:\n ${III_CONSOLE_INSTALL_CMD}`);
1774
+ return state;
1775
+ }
1776
+ return detectIiiConsole();
1076
1777
  }
1077
1778
  function adoptRunningEngine() {
1078
1779
  try {
@@ -1350,9 +2051,34 @@ async function waitForAgentmemoryReady(timeoutMs) {
1350
2051
  }
1351
2052
  return false;
1352
2053
  }
1353
- function printReadyHint() {
1354
- const hint = `Memory ready on :${getRestPort()} · viewer on ${getViewerUrl()} · try: agentmemory demo`;
1355
- process.stdout.write("\n" + hint + "\n");
2054
+ function getEngineHost() {
2055
+ for (const envKey of ["III_ENGINE_URL", "AGENTMEMORY_URL"]) {
2056
+ const raw = process.env[envKey];
2057
+ if (!raw) continue;
2058
+ try {
2059
+ const parsed = new URL(raw);
2060
+ if (parsed.hostname) return parsed.hostname;
2061
+ } catch {}
2062
+ }
2063
+ return "localhost";
2064
+ }
2065
+ function printReadyHint(consoleState) {
2066
+ const restUrl = getBaseUrl();
2067
+ const viewerUrl = getViewerUrl();
2068
+ const engineHost = getEngineHost();
2069
+ const streamUrl = `ws://${engineHost}:${getStreamPort()}`;
2070
+ const engineUrl = `ws://${engineHost}:${getEnginePort()}`;
2071
+ const consoleLine = consoleState.kind === "installed" ? `iii console ${consoleState.binPath} (run: ${consoleState.binPath} -p <port>)` : `iii console (install: ${III_CONSOLE_INSTALL_CMD})`;
2072
+ const lines = [
2073
+ `REST API ${restUrl}`,
2074
+ `Viewer ${viewerUrl}`,
2075
+ `Streams ${streamUrl}`,
2076
+ `Engine ${engineUrl}`,
2077
+ consoleLine
2078
+ ];
2079
+ p.note(lines.join("\n"), `agentmemory v${VERSION}`);
2080
+ const demoCommand = isInvokedViaNpx() ? "npx @agentmemory/agentmemory demo" : "agentmemory demo";
2081
+ process.stdout.write(`\nTry: ${demoCommand}\n`);
1356
2082
  }
1357
2083
  async function main() {
1358
2084
  if (IS_RESET) resetPrefs();
@@ -1362,17 +2088,24 @@ async function main() {
1362
2088
  if (firstRun || IS_RESET) await runOnboarding();
1363
2089
  if (skipEngine) {
1364
2090
  if (IS_VERBOSE) p.log.info("Skipping engine check (--no-engine)");
1365
- await import("./src-BGcqJR1a.mjs");
1366
- if (await waitForAgentmemoryReady(15e3)) printReadyHint();
2091
+ await import("./src-3Oy_OOlF.mjs");
2092
+ if (await waitForAgentmemoryReady(15e3)) {
2093
+ const consoleState = await ensureIiiConsole();
2094
+ await maybeOfferGlobalInstall();
2095
+ printReadyHint(consoleState);
2096
+ }
1367
2097
  return;
1368
2098
  }
1369
2099
  if (await isEngineRunning()) {
1370
2100
  if (IS_VERBOSE) p.log.success("iii-engine is running");
1371
2101
  warnIfEngineVersionMismatch(whichBinary("iii") ?? fallbackIiiPaths().find((p) => existsSync(p)) ?? null);
1372
2102
  adoptRunningEngine();
1373
- maybeEmitNpxHint();
1374
- await import("./src-BGcqJR1a.mjs");
1375
- if (await waitForAgentmemoryReady(15e3)) printReadyHint();
2103
+ await import("./src-3Oy_OOlF.mjs");
2104
+ if (await waitForAgentmemoryReady(15e3)) {
2105
+ const consoleState = await ensureIiiConsole();
2106
+ await maybeOfferGlobalInstall();
2107
+ printReadyHint(consoleState);
2108
+ }
1376
2109
  return;
1377
2110
  }
1378
2111
  if (!await startEngine()) {
@@ -1416,9 +2149,12 @@ async function main() {
1416
2149
  process.exit(1);
1417
2150
  }
1418
2151
  s.stop("iii-engine is ready");
1419
- maybeEmitNpxHint();
1420
- await import("./src-BGcqJR1a.mjs");
1421
- if (await waitForAgentmemoryReady(15e3)) printReadyHint();
2152
+ await import("./src-3Oy_OOlF.mjs");
2153
+ if (await waitForAgentmemoryReady(15e3)) {
2154
+ const consoleState = await ensureIiiConsole();
2155
+ await maybeOfferGlobalInstall();
2156
+ printReadyHint(consoleState);
2157
+ }
1422
2158
  writePrefs({ skipSplash: true });
1423
2159
  }
1424
2160
  async function apiFetch(base, path, timeoutMs = 5e3) {
@@ -2301,7 +3037,7 @@ async function runMcp() {
2301
3037
  await import("./standalone-BQOaGF4z.mjs");
2302
3038
  }
2303
3039
  async function runConnectCmd() {
2304
- const { runConnect } = await import("./connect-hRTF7E2c.mjs");
3040
+ const { runConnect } = await Promise.resolve().then(() => connect_exports);
2305
3041
  await runConnect(args.slice(1));
2306
3042
  }
2307
3043
  async function runImportJsonl() {