@agentmemory/agentmemory 0.9.15 → 0.9.17
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/AGENTS.md +5 -5
- package/README.md +71 -6
- package/dist/cli.mjs +777 -41
- package/dist/cli.mjs.map +1 -1
- package/dist/index.mjs +157 -6
- package/dist/index.mjs.map +1 -1
- package/dist/{src-BGcqJR1a.mjs → src-TiNuQ3Ub.mjs} +148 -4
- package/dist/src-TiNuQ3Ub.mjs.map +1 -0
- package/dist/{standalone-BQOaGF4z.mjs → standalone-BIXq6S80.mjs} +3 -3
- package/dist/standalone-BIXq6S80.mjs.map +1 -0
- package/dist/standalone.mjs +2 -2
- package/dist/standalone.mjs.map +1 -1
- package/dist/{tools-registry-BF0pgZmI.mjs → tools-registry-BFKFKmYh.mjs} +11 -4
- package/dist/tools-registry-BFKFKmYh.mjs.map +1 -0
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/dist/connect-hRTF7E2c.mjs +0 -525
- package/dist/connect-hRTF7E2c.mjs.map +0 -1
- package/dist/src-BGcqJR1a.mjs.map +0 -1
- package/dist/standalone-BQOaGF4z.mjs.map +0 -1
- package/dist/tools-registry-BF0pgZmI.mjs.map +0 -1
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.
|
|
1436
|
+
const VERSION = "0.9.17";
|
|
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
|
|
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
|
|
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
|
|
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 (
|
|
1075
|
-
|
|
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
|
|
1354
|
-
const
|
|
1355
|
-
|
|
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-
|
|
1366
|
-
if (await waitForAgentmemoryReady(15e3))
|
|
2091
|
+
await import("./src-TiNuQ3Ub.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
|
-
|
|
1374
|
-
await
|
|
1375
|
-
|
|
2103
|
+
await import("./src-TiNuQ3Ub.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
|
-
|
|
1420
|
-
await
|
|
1421
|
-
|
|
2152
|
+
await import("./src-TiNuQ3Ub.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) {
|
|
@@ -2298,10 +3034,10 @@ async function runStop() {
|
|
|
2298
3034
|
p.outro("Stopped. Memories persisted to disk; restart anytime with: npx @agentmemory/agentmemory");
|
|
2299
3035
|
}
|
|
2300
3036
|
async function runMcp() {
|
|
2301
|
-
await import("./standalone-
|
|
3037
|
+
await import("./standalone-BIXq6S80.mjs");
|
|
2302
3038
|
}
|
|
2303
3039
|
async function runConnectCmd() {
|
|
2304
|
-
const { runConnect } = await
|
|
3040
|
+
const { runConnect } = await Promise.resolve().then(() => connect_exports);
|
|
2305
3041
|
await runConnect(args.slice(1));
|
|
2306
3042
|
}
|
|
2307
3043
|
async function runImportJsonl() {
|