@agentmemory/agentmemory 0.9.13 → 0.9.15
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/README.md +23 -21
- package/dist/cli.mjs +1612 -113
- package/dist/cli.mjs.map +1 -1
- package/dist/connect-hRTF7E2c.mjs +525 -0
- package/dist/connect-hRTF7E2c.mjs.map +1 -0
- package/dist/{image-refs-HVu22rfu.mjs → image-refs-R3tin9MR.mjs} +2 -2
- package/dist/{image-refs-HVu22rfu.mjs.map → image-refs-R3tin9MR.mjs.map} +1 -1
- package/dist/{image-store-BfN1vDbj.mjs → image-store-DyrKZKqZ.mjs} +1 -1
- package/dist/index.mjs +63 -35
- package/dist/index.mjs.map +1 -1
- package/dist/{src-Ca9oX6Hq.mjs → src-BGcqJR1a.mjs} +62 -72
- package/dist/src-BGcqJR1a.mjs.map +1 -0
- package/dist/{standalone-BpbiNqr9.mjs → standalone-BQOaGF4z.mjs} +3 -3
- package/dist/{standalone-BpbiNqr9.mjs.map → standalone-BQOaGF4z.mjs.map} +1 -1
- package/dist/standalone.mjs +1 -1
- package/dist/standalone.mjs.map +1 -1
- package/dist/{tools-registry-D5l632PP.mjs → tools-registry-BF0pgZmI.mjs} +2 -6
- package/dist/tools-registry-BF0pgZmI.mjs.map +1 -0
- package/package.json +6 -6
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/dist/src-Ca9oX6Hq.mjs.map +0 -1
- package/dist/tools-registry-D5l632PP.mjs.map +0 -1
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { homedir, platform } from "node:os";
|
|
4
|
+
import * as p from "@clack/prompts";
|
|
5
|
+
|
|
6
|
+
//#region src/cli/connect/util.ts
|
|
7
|
+
const AGENTMEMORY_MCP_BLOCK = {
|
|
8
|
+
command: "npx",
|
|
9
|
+
args: ["-y", "@agentmemory/mcp"],
|
|
10
|
+
env: { AGENTMEMORY_URL: "http://localhost:3111" }
|
|
11
|
+
};
|
|
12
|
+
function backupsDir() {
|
|
13
|
+
return join(homedir(), ".agentmemory", "backups");
|
|
14
|
+
}
|
|
15
|
+
function ensureBackupsDir() {
|
|
16
|
+
const dir = backupsDir();
|
|
17
|
+
mkdirSync(dir, { recursive: true });
|
|
18
|
+
return dir;
|
|
19
|
+
}
|
|
20
|
+
function timestampSlug() {
|
|
21
|
+
return (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
22
|
+
}
|
|
23
|
+
function backupFile(sourcePath, agent, ext = "json") {
|
|
24
|
+
ensureBackupsDir();
|
|
25
|
+
const stamp = timestampSlug();
|
|
26
|
+
const target = join(backupsDir(), `${agent}-${stamp}.${ext}`);
|
|
27
|
+
copyFileSync(sourcePath, target);
|
|
28
|
+
return target;
|
|
29
|
+
}
|
|
30
|
+
function readJsonSafe(path) {
|
|
31
|
+
if (!existsSync(path)) return null;
|
|
32
|
+
try {
|
|
33
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
34
|
+
} catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function writeJsonAtomic(path, value) {
|
|
39
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
40
|
+
const tmp = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
41
|
+
writeFileSync(tmp, `${JSON.stringify(value, null, 2)}\n`, "utf-8");
|
|
42
|
+
renameSync(tmp, path);
|
|
43
|
+
}
|
|
44
|
+
function logInstalled(label, target) {
|
|
45
|
+
p.log.success(`${label} → wired into ${target}`);
|
|
46
|
+
}
|
|
47
|
+
function logAlreadyWired(label, target) {
|
|
48
|
+
p.log.info(`${label} already wired in ${target} (use --force to re-install)`);
|
|
49
|
+
}
|
|
50
|
+
function logBackup(target) {
|
|
51
|
+
p.log.info(`Backup: ${target}`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/cli/connect/claude-code.ts
|
|
56
|
+
const CLAUDE_DIR = join(homedir(), ".claude");
|
|
57
|
+
const CLAUDE_JSON = join(homedir(), ".claude.json");
|
|
58
|
+
function entryMatches$1(entry) {
|
|
59
|
+
if (!entry || typeof entry !== "object") return false;
|
|
60
|
+
const e = entry;
|
|
61
|
+
if (e["command"] !== "npx") return false;
|
|
62
|
+
return (Array.isArray(e["args"]) ? e["args"] : []).includes("@agentmemory/mcp");
|
|
63
|
+
}
|
|
64
|
+
const adapter$7 = {
|
|
65
|
+
name: "claude-code",
|
|
66
|
+
displayName: "Claude Code",
|
|
67
|
+
docs: "https://github.com/rohitg00/agentmemory#claude-code-one-block-paste-it",
|
|
68
|
+
detect() {
|
|
69
|
+
return existsSync(CLAUDE_DIR);
|
|
70
|
+
},
|
|
71
|
+
async install(opts) {
|
|
72
|
+
const existing = readJsonSafe(CLAUDE_JSON);
|
|
73
|
+
const next = existing ? { ...existing } : {};
|
|
74
|
+
const servers = { ...next.mcpServers ?? {} };
|
|
75
|
+
const alreadyHas = entryMatches$1(servers["agentmemory"]);
|
|
76
|
+
if (alreadyHas && !opts.force) {
|
|
77
|
+
logAlreadyWired("Claude Code", CLAUDE_JSON);
|
|
78
|
+
return {
|
|
79
|
+
kind: "already-wired",
|
|
80
|
+
mutatedPath: CLAUDE_JSON
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
if (opts.dryRun) {
|
|
84
|
+
p.log.info(`[dry-run] Would ${alreadyHas ? "overwrite" : "add"} mcpServers.agentmemory in ${CLAUDE_JSON}`);
|
|
85
|
+
return {
|
|
86
|
+
kind: "installed",
|
|
87
|
+
mutatedPath: CLAUDE_JSON
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
let backupPath;
|
|
91
|
+
if (existsSync(CLAUDE_JSON)) {
|
|
92
|
+
backupPath = backupFile(CLAUDE_JSON, "claude-code");
|
|
93
|
+
logBackup(backupPath);
|
|
94
|
+
} else {
|
|
95
|
+
mkdirSync(CLAUDE_DIR, { recursive: true });
|
|
96
|
+
writeFileSync(CLAUDE_JSON, "{}\n", "utf-8");
|
|
97
|
+
}
|
|
98
|
+
servers["agentmemory"] = AGENTMEMORY_MCP_BLOCK;
|
|
99
|
+
next.mcpServers = servers;
|
|
100
|
+
writeJsonAtomic(CLAUDE_JSON, next);
|
|
101
|
+
if (!entryMatches$1(readJsonSafe(CLAUDE_JSON)?.mcpServers?.["agentmemory"])) {
|
|
102
|
+
p.log.error(`Verification failed: ${CLAUDE_JSON} did not contain mcpServers.agentmemory after write.`);
|
|
103
|
+
return {
|
|
104
|
+
kind: "skipped",
|
|
105
|
+
reason: "verification-failed"
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
logInstalled("Claude Code", CLAUDE_JSON);
|
|
109
|
+
p.log.info("Restart Claude Code (or run `/mcp` inside a session) to pick up the new server.");
|
|
110
|
+
return {
|
|
111
|
+
kind: "installed",
|
|
112
|
+
mutatedPath: CLAUDE_JSON,
|
|
113
|
+
backupPath
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
//#endregion
|
|
119
|
+
//#region src/cli/connect/codex.ts
|
|
120
|
+
const CODEX_DIR = join(homedir(), ".codex");
|
|
121
|
+
const CODEX_TOML = join(CODEX_DIR, "config.toml");
|
|
122
|
+
const TOML_BLOCK = `[mcp_servers.agentmemory]
|
|
123
|
+
command = "npx"
|
|
124
|
+
args = ["-y", "@agentmemory/mcp"]
|
|
125
|
+
|
|
126
|
+
[mcp_servers.agentmemory.env]
|
|
127
|
+
AGENTMEMORY_URL = "http://localhost:3111"
|
|
128
|
+
`;
|
|
129
|
+
const SECTION_HEADER = "[mcp_servers.agentmemory]";
|
|
130
|
+
function isWiredText(toml) {
|
|
131
|
+
return toml.includes(SECTION_HEADER);
|
|
132
|
+
}
|
|
133
|
+
function stripExistingBlock(toml) {
|
|
134
|
+
const lines = toml.split(/\r?\n/);
|
|
135
|
+
const out = [];
|
|
136
|
+
let skipping = false;
|
|
137
|
+
for (const line of lines) {
|
|
138
|
+
const trimmed = line.trim();
|
|
139
|
+
if (trimmed === SECTION_HEADER || trimmed === "[mcp_servers.agentmemory.env]") {
|
|
140
|
+
skipping = true;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (skipping && trimmed.startsWith("[") && trimmed !== "[mcp_servers.agentmemory.env]") skipping = false;
|
|
144
|
+
if (!skipping) out.push(line);
|
|
145
|
+
}
|
|
146
|
+
return out.join("\n").replace(/\n{3,}$/, "\n\n").trimEnd() + "\n";
|
|
147
|
+
}
|
|
148
|
+
const adapter$6 = {
|
|
149
|
+
name: "codex",
|
|
150
|
+
displayName: "Codex CLI",
|
|
151
|
+
docs: "https://github.com/rohitg00/agentmemory#codex-cli-codex-plugin-platform",
|
|
152
|
+
detect() {
|
|
153
|
+
return existsSync(CODEX_DIR);
|
|
154
|
+
},
|
|
155
|
+
async install(opts) {
|
|
156
|
+
const exists = existsSync(CODEX_TOML);
|
|
157
|
+
const current = exists ? readFileSync(CODEX_TOML, "utf-8") : "";
|
|
158
|
+
const wired = isWiredText(current);
|
|
159
|
+
if (wired && !opts.force) {
|
|
160
|
+
logAlreadyWired("Codex CLI", CODEX_TOML);
|
|
161
|
+
return {
|
|
162
|
+
kind: "already-wired",
|
|
163
|
+
mutatedPath: CODEX_TOML
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
if (opts.dryRun) {
|
|
167
|
+
p.log.info(`[dry-run] Would ${wired ? "rewrite" : "append"} [mcp_servers.agentmemory] in ${CODEX_TOML}`);
|
|
168
|
+
return {
|
|
169
|
+
kind: "installed",
|
|
170
|
+
mutatedPath: CODEX_TOML
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
let backupPath;
|
|
174
|
+
if (exists) {
|
|
175
|
+
backupPath = backupFile(CODEX_TOML, "codex", "toml");
|
|
176
|
+
logBackup(backupPath);
|
|
177
|
+
} else mkdirSync(dirname(CODEX_TOML), { recursive: true });
|
|
178
|
+
const cleaned = wired ? stripExistingBlock(current) : current;
|
|
179
|
+
writeFileSync(CODEX_TOML, `${cleaned}${cleaned.length === 0 || cleaned.endsWith("\n") ? "" : "\n"}${cleaned.length > 0 ? "\n" : ""}${TOML_BLOCK}`, "utf-8");
|
|
180
|
+
if (!isWiredText(readFileSync(CODEX_TOML, "utf-8"))) {
|
|
181
|
+
p.log.error(`Verification failed: ${CODEX_TOML} did not contain ${SECTION_HEADER} after write.`);
|
|
182
|
+
return {
|
|
183
|
+
kind: "skipped",
|
|
184
|
+
reason: "verification-failed"
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
logInstalled("Codex CLI", CODEX_TOML);
|
|
188
|
+
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");
|
|
189
|
+
return {
|
|
190
|
+
kind: "installed",
|
|
191
|
+
mutatedPath: CODEX_TOML,
|
|
192
|
+
...backupPath !== void 0 && { backupPath }
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
//#endregion
|
|
198
|
+
//#region src/cli/connect/json-mcp-adapter.ts
|
|
199
|
+
function entryMatches(entry) {
|
|
200
|
+
if (!entry || typeof entry !== "object") return false;
|
|
201
|
+
const e = entry;
|
|
202
|
+
if (e["command"] !== "npx") return false;
|
|
203
|
+
return (Array.isArray(e["args"]) ? e["args"] : []).includes("@agentmemory/mcp");
|
|
204
|
+
}
|
|
205
|
+
function createJsonMcpAdapter(config) {
|
|
206
|
+
return {
|
|
207
|
+
name: config.name,
|
|
208
|
+
displayName: config.displayName,
|
|
209
|
+
...config.docs !== void 0 && { docs: config.docs },
|
|
210
|
+
detect() {
|
|
211
|
+
return existsSync(config.detectDir);
|
|
212
|
+
},
|
|
213
|
+
async install(opts) {
|
|
214
|
+
const existing = readJsonSafe(config.configPath);
|
|
215
|
+
const next = existing ? { ...existing } : {};
|
|
216
|
+
const servers = { ...next.mcpServers ?? {} };
|
|
217
|
+
const alreadyHas = entryMatches(servers["agentmemory"]);
|
|
218
|
+
if (alreadyHas && !opts.force) {
|
|
219
|
+
logAlreadyWired(config.displayName, config.configPath);
|
|
220
|
+
return {
|
|
221
|
+
kind: "already-wired",
|
|
222
|
+
mutatedPath: config.configPath
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
if (opts.dryRun) {
|
|
226
|
+
p.log.info(`[dry-run] Would ${alreadyHas ? "overwrite" : "add"} mcpServers.agentmemory in ${config.configPath}`);
|
|
227
|
+
return {
|
|
228
|
+
kind: "installed",
|
|
229
|
+
mutatedPath: config.configPath
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
let backupPath;
|
|
233
|
+
if (existsSync(config.configPath)) {
|
|
234
|
+
backupPath = backupFile(config.configPath, config.name);
|
|
235
|
+
logBackup(backupPath);
|
|
236
|
+
} else mkdirSync(dirname(config.configPath), { recursive: true });
|
|
237
|
+
servers["agentmemory"] = AGENTMEMORY_MCP_BLOCK;
|
|
238
|
+
next.mcpServers = servers;
|
|
239
|
+
writeJsonAtomic(config.configPath, next);
|
|
240
|
+
if (!entryMatches(readJsonSafe(config.configPath)?.mcpServers?.["agentmemory"])) {
|
|
241
|
+
p.log.error(`Verification failed: ${config.configPath} did not contain mcpServers.agentmemory after write.`);
|
|
242
|
+
return {
|
|
243
|
+
kind: "skipped",
|
|
244
|
+
reason: "verification-failed"
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
logInstalled(config.displayName, config.configPath);
|
|
248
|
+
return {
|
|
249
|
+
kind: "installed",
|
|
250
|
+
mutatedPath: config.configPath,
|
|
251
|
+
...backupPath !== void 0 && { backupPath }
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
//#endregion
|
|
258
|
+
//#region src/cli/connect/cursor.ts
|
|
259
|
+
const adapter$5 = createJsonMcpAdapter({
|
|
260
|
+
name: "cursor",
|
|
261
|
+
displayName: "Cursor",
|
|
262
|
+
detectDir: join(homedir(), ".cursor"),
|
|
263
|
+
configPath: join(homedir(), ".cursor", "mcp.json"),
|
|
264
|
+
docs: "https://github.com/rohitg00/agentmemory#other-agents"
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
//#endregion
|
|
268
|
+
//#region src/cli/connect/gemini-cli.ts
|
|
269
|
+
const adapter$4 = createJsonMcpAdapter({
|
|
270
|
+
name: "gemini-cli",
|
|
271
|
+
displayName: "Gemini CLI",
|
|
272
|
+
detectDir: join(homedir(), ".gemini"),
|
|
273
|
+
configPath: join(homedir(), ".gemini", "settings.json"),
|
|
274
|
+
docs: "https://github.com/rohitg00/agentmemory#other-agents"
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
//#endregion
|
|
278
|
+
//#region src/cli/connect/hermes.ts
|
|
279
|
+
const HERMES_DIR = join(homedir(), ".hermes");
|
|
280
|
+
const HERMES_CONFIG = join(HERMES_DIR, "config.yaml");
|
|
281
|
+
const DOCS$2 = "https://github.com/rohitg00/agentmemory/tree/main/integrations/hermes";
|
|
282
|
+
const adapter$3 = {
|
|
283
|
+
name: "hermes",
|
|
284
|
+
displayName: "Hermes Agent",
|
|
285
|
+
docs: DOCS$2,
|
|
286
|
+
detect() {
|
|
287
|
+
return existsSync(HERMES_DIR);
|
|
288
|
+
},
|
|
289
|
+
async install(_opts) {
|
|
290
|
+
p.log.warn("Hermes uses YAML config. Automated merge isn't implemented yet — manual install required.");
|
|
291
|
+
p.note([
|
|
292
|
+
`Add to ${HERMES_CONFIG}:`,
|
|
293
|
+
"",
|
|
294
|
+
" mcp_servers:",
|
|
295
|
+
" agentmemory:",
|
|
296
|
+
" command: npx",
|
|
297
|
+
" args: [\"-y\", \"@agentmemory/mcp\"]",
|
|
298
|
+
"",
|
|
299
|
+
" memory:",
|
|
300
|
+
" provider: agentmemory",
|
|
301
|
+
"",
|
|
302
|
+
`Full guide: ${DOCS$2}`
|
|
303
|
+
].join("\n"), "Hermes manual install");
|
|
304
|
+
return {
|
|
305
|
+
kind: "stub",
|
|
306
|
+
reason: "yaml-merge-not-implemented"
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
//#endregion
|
|
312
|
+
//#region src/cli/connect/openclaw.ts
|
|
313
|
+
const adapter$2 = createJsonMcpAdapter({
|
|
314
|
+
name: "openclaw",
|
|
315
|
+
displayName: "OpenClaw",
|
|
316
|
+
detectDir: join(homedir(), ".openclaw"),
|
|
317
|
+
configPath: join(homedir(), ".openclaw", "openclaw.json"),
|
|
318
|
+
docs: "https://github.com/rohitg00/agentmemory/tree/main/integrations/openclaw"
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
//#endregion
|
|
322
|
+
//#region src/cli/connect/openhuman.ts
|
|
323
|
+
const OPENHUMAN_DIR = join(homedir(), ".openhuman");
|
|
324
|
+
const DOCS$1 = "https://github.com/tinyhumansai/openhuman";
|
|
325
|
+
const adapter$1 = {
|
|
326
|
+
name: "openhuman",
|
|
327
|
+
displayName: "OpenHuman",
|
|
328
|
+
docs: DOCS$1,
|
|
329
|
+
detect() {
|
|
330
|
+
return existsSync(OPENHUMAN_DIR);
|
|
331
|
+
},
|
|
332
|
+
async install(_opts) {
|
|
333
|
+
p.log.warn("OpenHuman integration is not yet automated. No `integrations/openhuman/` folder exists in the agentmemory repo today.");
|
|
334
|
+
p.note([
|
|
335
|
+
"OpenHuman is a Memory-trait host. The expected wiring is the REST",
|
|
336
|
+
"proxy at http://localhost:3111 plus an OpenHuman-side Memory trait",
|
|
337
|
+
"impl. Once integrations/openhuman/ lands in agentmemory we'll wire",
|
|
338
|
+
"this up automatically.",
|
|
339
|
+
"",
|
|
340
|
+
`Tracking: ${DOCS$1}`
|
|
341
|
+
].join("\n"), "OpenHuman manual install");
|
|
342
|
+
return {
|
|
343
|
+
kind: "stub",
|
|
344
|
+
reason: "no-integration-folder-yet"
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
//#endregion
|
|
350
|
+
//#region src/cli/connect/pi.ts
|
|
351
|
+
const PI_DIR = join(homedir(), ".pi");
|
|
352
|
+
const PI_EXT_DIR = join(PI_DIR, "agent", "extensions", "agentmemory");
|
|
353
|
+
const DOCS = "https://github.com/rohitg00/agentmemory/tree/main/integrations/pi";
|
|
354
|
+
const adapter = {
|
|
355
|
+
name: "pi",
|
|
356
|
+
displayName: "pi",
|
|
357
|
+
docs: DOCS,
|
|
358
|
+
detect() {
|
|
359
|
+
return existsSync(PI_DIR);
|
|
360
|
+
},
|
|
361
|
+
async install(_opts) {
|
|
362
|
+
p.log.warn("pi uses a TypeScript extension file. Automated copy + register isn't implemented yet — manual install required.");
|
|
363
|
+
p.note([
|
|
364
|
+
"Run these from the agentmemory repo root:",
|
|
365
|
+
"",
|
|
366
|
+
` mkdir -p ${PI_EXT_DIR}`,
|
|
367
|
+
` cp integrations/pi/index.ts ${PI_EXT_DIR}/index.ts`,
|
|
368
|
+
` cp integrations/pi/security.ts ${PI_EXT_DIR}/security.ts`,
|
|
369
|
+
"",
|
|
370
|
+
"Then add to ~/.pi/agent/settings.json:",
|
|
371
|
+
" { \"extensions\": [\"~/.pi/agent/extensions/agentmemory\"] }",
|
|
372
|
+
"",
|
|
373
|
+
`Full guide: ${DOCS}`
|
|
374
|
+
].join("\n"), "pi manual install");
|
|
375
|
+
return {
|
|
376
|
+
kind: "stub",
|
|
377
|
+
reason: "ts-extension-copy-not-implemented"
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
//#endregion
|
|
383
|
+
//#region src/cli/connect/index.ts
|
|
384
|
+
const ADAPTERS = [
|
|
385
|
+
adapter$7,
|
|
386
|
+
adapter$6,
|
|
387
|
+
adapter$5,
|
|
388
|
+
adapter$4,
|
|
389
|
+
adapter$2,
|
|
390
|
+
adapter$3,
|
|
391
|
+
adapter,
|
|
392
|
+
adapter$1
|
|
393
|
+
];
|
|
394
|
+
function resolveAdapter(name) {
|
|
395
|
+
const lower = name.toLowerCase();
|
|
396
|
+
return ADAPTERS.find((a) => a.name === lower) ?? null;
|
|
397
|
+
}
|
|
398
|
+
function knownAgents() {
|
|
399
|
+
return ADAPTERS.map((a) => a.name);
|
|
400
|
+
}
|
|
401
|
+
function parseFlags(args) {
|
|
402
|
+
const positional = [];
|
|
403
|
+
let dryRun = false;
|
|
404
|
+
let force = false;
|
|
405
|
+
let all = false;
|
|
406
|
+
for (const a of args) if (a === "--dry-run") dryRun = true;
|
|
407
|
+
else if (a === "--force") force = true;
|
|
408
|
+
else if (a === "--all") all = true;
|
|
409
|
+
else if (!a.startsWith("-")) positional.push(a);
|
|
410
|
+
return {
|
|
411
|
+
dryRun,
|
|
412
|
+
force,
|
|
413
|
+
all,
|
|
414
|
+
positional
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
async function runAdapter(adapter, opts) {
|
|
418
|
+
if (!adapter.detect()) {
|
|
419
|
+
p.log.warn(`${adapter.displayName}: not detected on this machine (skipping).${adapter.docs ? ` Docs: ${adapter.docs}` : ""}`);
|
|
420
|
+
return {
|
|
421
|
+
kind: "skipped",
|
|
422
|
+
reason: "not-detected"
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
p.log.step(`Wiring ${adapter.displayName}…`);
|
|
426
|
+
try {
|
|
427
|
+
return await adapter.install(opts);
|
|
428
|
+
} catch (err) {
|
|
429
|
+
p.log.error(`${adapter.displayName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
430
|
+
return {
|
|
431
|
+
kind: "skipped",
|
|
432
|
+
reason: "exception"
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
async function runConnect(args) {
|
|
437
|
+
if (platform() === "win32") {
|
|
438
|
+
p.intro("agentmemory connect");
|
|
439
|
+
p.log.warn("Windows: automated `connect` is not supported yet. See https://github.com/rohitg00/agentmemory#other-agents for manual install steps.");
|
|
440
|
+
p.outro("Windows: manual install required — see docs");
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
const { dryRun, force, all, positional } = parseFlags(args);
|
|
444
|
+
const opts = {
|
|
445
|
+
dryRun,
|
|
446
|
+
force
|
|
447
|
+
};
|
|
448
|
+
p.intro("agentmemory connect");
|
|
449
|
+
if (positional.length === 0 && !all) {
|
|
450
|
+
const detected = ADAPTERS.filter((a) => a.detect());
|
|
451
|
+
if (detected.length === 0) {
|
|
452
|
+
p.log.error("No supported agents detected on this machine.");
|
|
453
|
+
p.outro(`Supported: ${knownAgents().join(", ")}`);
|
|
454
|
+
process.exit(1);
|
|
455
|
+
}
|
|
456
|
+
const picked = await p.multiselect({
|
|
457
|
+
message: "Wire agentmemory into which agents?",
|
|
458
|
+
options: detected.map((a) => ({
|
|
459
|
+
value: a.name,
|
|
460
|
+
label: a.displayName
|
|
461
|
+
})),
|
|
462
|
+
required: true
|
|
463
|
+
});
|
|
464
|
+
if (p.isCancel(picked)) {
|
|
465
|
+
p.cancel("Cancelled.");
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
const results = [];
|
|
469
|
+
for (const name of picked) {
|
|
470
|
+
const adapter = resolveAdapter(name);
|
|
471
|
+
if (!adapter) continue;
|
|
472
|
+
results.push({
|
|
473
|
+
name,
|
|
474
|
+
result: await runAdapter(adapter, opts)
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
summarize(results);
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
if (all) {
|
|
481
|
+
const detected = ADAPTERS.filter((a) => a.detect());
|
|
482
|
+
if (detected.length === 0) {
|
|
483
|
+
p.log.error("No supported agents detected on this machine.");
|
|
484
|
+
process.exit(1);
|
|
485
|
+
}
|
|
486
|
+
const results = [];
|
|
487
|
+
for (const adapter of detected) results.push({
|
|
488
|
+
name: adapter.name,
|
|
489
|
+
result: await runAdapter(adapter, opts)
|
|
490
|
+
});
|
|
491
|
+
summarize(results);
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
const agentName = positional[0];
|
|
495
|
+
const adapter = resolveAdapter(agentName);
|
|
496
|
+
if (!adapter) {
|
|
497
|
+
p.log.error(`Unknown agent: ${agentName}`);
|
|
498
|
+
p.outro(`Supported: ${knownAgents().join(", ")}`);
|
|
499
|
+
process.exit(1);
|
|
500
|
+
}
|
|
501
|
+
const result = await runAdapter(adapter, opts);
|
|
502
|
+
summarize([{
|
|
503
|
+
name: agentName,
|
|
504
|
+
result
|
|
505
|
+
}]);
|
|
506
|
+
if (result.kind === "skipped" && result.reason !== "not-detected") process.exit(1);
|
|
507
|
+
}
|
|
508
|
+
function summarize(results) {
|
|
509
|
+
const lines = results.map(({ name, result }) => {
|
|
510
|
+
switch (result.kind) {
|
|
511
|
+
case "installed": return ` ✓ ${name}${result.mutatedPath ? ` → ${result.mutatedPath}` : ""}`;
|
|
512
|
+
case "already-wired": return ` ✓ ${name} (already wired)`;
|
|
513
|
+
case "stub": return ` ⚠ ${name} (manual install required: ${result.reason})`;
|
|
514
|
+
case "skipped": return ` ✗ ${name} (skipped: ${result.reason})`;
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
p.note(lines.join("\n"), "summary");
|
|
518
|
+
const stubs = results.filter((r) => r.result.kind === "stub");
|
|
519
|
+
if (stubs.length > 0) p.log.info(`${stubs.length} agent(s) require manual install — see docs links above.`);
|
|
520
|
+
p.outro("Restart any wired agent (or open a new session) to pick up agentmemory.");
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
//#endregion
|
|
524
|
+
export { runConnect };
|
|
525
|
+
//# sourceMappingURL=connect-hRTF7E2c.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connect-hRTF7E2c.mjs","names":["entryMatches","adapter","adapter","adapter","adapter","DOCS","adapter","adapter","DOCS","adapter","claudeCode","codex","cursor","geminiCli","openclaw","hermes","pi","openhuman"],"sources":["../src/cli/connect/util.ts","../src/cli/connect/claude-code.ts","../src/cli/connect/codex.ts","../src/cli/connect/json-mcp-adapter.ts","../src/cli/connect/cursor.ts","../src/cli/connect/gemini-cli.ts","../src/cli/connect/hermes.ts","../src/cli/connect/openclaw.ts","../src/cli/connect/openhuman.ts","../src/cli/connect/pi.ts","../src/cli/connect/index.ts"],"sourcesContent":["import {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n copyFileSync,\n renameSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport * as p from \"@clack/prompts\";\n\nexport const AGENTMEMORY_MCP_BLOCK = {\n command: \"npx\",\n args: [\"-y\", \"@agentmemory/mcp\"],\n env: {\n AGENTMEMORY_URL: \"http://localhost:3111\",\n },\n};\n\nexport function backupsDir(): string {\n return join(homedir(), \".agentmemory\", \"backups\");\n}\n\nexport function ensureBackupsDir(): string {\n const dir = backupsDir();\n mkdirSync(dir, { recursive: true });\n return dir;\n}\n\nexport function timestampSlug(): string {\n return new Date().toISOString().replace(/[:.]/g, \"-\");\n}\n\nexport function backupFile(\n sourcePath: string,\n agent: string,\n ext = \"json\",\n): string {\n ensureBackupsDir();\n const stamp = timestampSlug();\n const target = join(backupsDir(), `${agent}-${stamp}.${ext}`);\n copyFileSync(sourcePath, target);\n return target;\n}\n\nexport function readJsonSafe<T = unknown>(path: string): T | null {\n if (!existsSync(path)) return null;\n try {\n return JSON.parse(readFileSync(path, \"utf-8\")) as T;\n } catch {\n return null;\n }\n}\n\nexport function writeJsonAtomic(path: string, value: unknown): void {\n mkdirSync(dirname(path), { recursive: true });\n const tmp = `${path}.tmp-${process.pid}-${Date.now()}`;\n writeFileSync(tmp, `${JSON.stringify(value, null, 2)}\\n`, \"utf-8\");\n renameSync(tmp, path);\n}\n\nexport function logInstalled(label: string, target: string): void {\n p.log.success(`${label} → wired into ${target}`);\n}\n\nexport function logAlreadyWired(label: string, target: string): void {\n p.log.info(`${label} already wired in ${target} (use --force to re-install)`);\n}\n\nexport function logBackup(target: string): void {\n p.log.info(`Backup: ${target}`);\n}\n","import { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport * as p from \"@clack/prompts\";\nimport type { ConnectAdapter, ConnectOptions, ConnectResult } from \"./types.js\";\nimport {\n AGENTMEMORY_MCP_BLOCK,\n backupFile,\n logAlreadyWired,\n logBackup,\n logInstalled,\n readJsonSafe,\n writeJsonAtomic,\n} from \"./util.js\";\n\nconst CLAUDE_DIR = join(homedir(), \".claude\");\nconst CLAUDE_JSON = join(homedir(), \".claude.json\");\n\ntype ClaudeMcpEntry = typeof AGENTMEMORY_MCP_BLOCK;\ntype ClaudeConfig = {\n mcpServers?: Record<string, ClaudeMcpEntry>;\n [key: string]: unknown;\n};\n\nfunction entryMatches(entry: unknown): boolean {\n if (!entry || typeof entry !== \"object\") return false;\n const e = entry as Record<string, unknown>;\n if (e[\"command\"] !== \"npx\") return false;\n const args = Array.isArray(e[\"args\"]) ? (e[\"args\"] as string[]) : [];\n return args.includes(\"@agentmemory/mcp\");\n}\n\nexport const adapter: ConnectAdapter = {\n name: \"claude-code\",\n displayName: \"Claude Code\",\n docs: \"https://github.com/rohitg00/agentmemory#claude-code-one-block-paste-it\",\n\n detect(): boolean {\n return existsSync(CLAUDE_DIR);\n },\n\n async install(opts: ConnectOptions): Promise<ConnectResult> {\n const existing = readJsonSafe<ClaudeConfig>(CLAUDE_JSON);\n const next: ClaudeConfig = existing ? { ...existing } : {};\n const servers: Record<string, ClaudeMcpEntry> = {\n ...((next.mcpServers as Record<string, ClaudeMcpEntry>) ?? {}),\n };\n\n const alreadyHas = entryMatches(servers[\"agentmemory\"]);\n if (alreadyHas && !opts.force) {\n logAlreadyWired(\"Claude Code\", CLAUDE_JSON);\n return { kind: \"already-wired\", mutatedPath: CLAUDE_JSON };\n }\n\n if (opts.dryRun) {\n p.log.info(\n `[dry-run] Would ${alreadyHas ? \"overwrite\" : \"add\"} mcpServers.agentmemory in ${CLAUDE_JSON}`,\n );\n return { kind: \"installed\", mutatedPath: CLAUDE_JSON };\n }\n\n let backupPath: string | undefined;\n if (existsSync(CLAUDE_JSON)) {\n backupPath = backupFile(CLAUDE_JSON, \"claude-code\");\n logBackup(backupPath);\n } else {\n mkdirSync(CLAUDE_DIR, { recursive: true });\n writeFileSync(CLAUDE_JSON, \"{}\\n\", \"utf-8\");\n }\n\n servers[\"agentmemory\"] = AGENTMEMORY_MCP_BLOCK;\n next.mcpServers = servers;\n writeJsonAtomic(CLAUDE_JSON, next);\n\n const verify = readJsonSafe<ClaudeConfig>(CLAUDE_JSON);\n if (!entryMatches(verify?.mcpServers?.[\"agentmemory\"])) {\n p.log.error(\n `Verification failed: ${CLAUDE_JSON} did not contain mcpServers.agentmemory after write.`,\n );\n return { kind: \"skipped\", reason: \"verification-failed\" };\n }\n\n logInstalled(\"Claude Code\", CLAUDE_JSON);\n p.log.info(\n \"Restart Claude Code (or run `/mcp` inside a session) to pick up the new server.\",\n );\n return { kind: \"installed\", mutatedPath: CLAUDE_JSON, backupPath };\n },\n};\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, dirname } from \"node:path\";\nimport * as p from \"@clack/prompts\";\nimport type { ConnectAdapter, ConnectOptions, ConnectResult } from \"./types.js\";\nimport {\n backupFile,\n logAlreadyWired,\n logBackup,\n logInstalled,\n} from \"./util.js\";\n\nconst CODEX_DIR = join(homedir(), \".codex\");\nconst CODEX_TOML = join(CODEX_DIR, \"config.toml\");\n\nconst TOML_BLOCK = `[mcp_servers.agentmemory]\ncommand = \"npx\"\nargs = [\"-y\", \"@agentmemory/mcp\"]\n\n[mcp_servers.agentmemory.env]\nAGENTMEMORY_URL = \"http://localhost:3111\"\n`;\n\nconst SECTION_HEADER = \"[mcp_servers.agentmemory]\";\n\nfunction isWiredText(toml: string): boolean {\n return toml.includes(SECTION_HEADER);\n}\n\nfunction stripExistingBlock(toml: string): string {\n const lines = toml.split(/\\r?\\n/);\n const out: string[] = [];\n let skipping = false;\n for (const line of lines) {\n const trimmed = line.trim();\n if (\n trimmed === SECTION_HEADER ||\n trimmed === \"[mcp_servers.agentmemory.env]\"\n ) {\n skipping = true;\n continue;\n }\n if (\n skipping &&\n trimmed.startsWith(\"[\") &&\n trimmed !== \"[mcp_servers.agentmemory.env]\"\n ) {\n skipping = false;\n }\n if (!skipping) out.push(line);\n }\n return out.join(\"\\n\").replace(/\\n{3,}$/, \"\\n\\n\").trimEnd() + \"\\n\";\n}\n\nexport const adapter: ConnectAdapter = {\n name: \"codex\",\n displayName: \"Codex CLI\",\n docs: \"https://github.com/rohitg00/agentmemory#codex-cli-codex-plugin-platform\",\n\n detect(): boolean {\n return existsSync(CODEX_DIR);\n },\n\n async install(opts: ConnectOptions): Promise<ConnectResult> {\n const exists = existsSync(CODEX_TOML);\n const current = exists ? readFileSync(CODEX_TOML, \"utf-8\") : \"\";\n const wired = isWiredText(current);\n\n if (wired && !opts.force) {\n logAlreadyWired(\"Codex CLI\", CODEX_TOML);\n return { kind: \"already-wired\", mutatedPath: CODEX_TOML };\n }\n\n if (opts.dryRun) {\n p.log.info(\n `[dry-run] Would ${wired ? \"rewrite\" : \"append\"} [mcp_servers.agentmemory] in ${CODEX_TOML}`,\n );\n return { kind: \"installed\", mutatedPath: CODEX_TOML };\n }\n\n let backupPath: string | undefined;\n if (exists) {\n backupPath = backupFile(CODEX_TOML, \"codex\", \"toml\");\n logBackup(backupPath);\n } else {\n mkdirSync(dirname(CODEX_TOML), { recursive: true });\n }\n\n const cleaned = wired ? stripExistingBlock(current) : current;\n const joiner = cleaned.length === 0 || cleaned.endsWith(\"\\n\") ? \"\" : \"\\n\";\n const next = `${cleaned}${joiner}${cleaned.length > 0 ? \"\\n\" : \"\"}${TOML_BLOCK}`;\n writeFileSync(CODEX_TOML, next, \"utf-8\");\n\n const verify = readFileSync(CODEX_TOML, \"utf-8\");\n if (!isWiredText(verify)) {\n p.log.error(\n `Verification failed: ${CODEX_TOML} did not contain ${SECTION_HEADER} after write.`,\n );\n return { kind: \"skipped\", reason: \"verification-failed\" };\n }\n\n logInstalled(\"Codex CLI\", CODEX_TOML);\n p.log.info(\n \"Codex picks up MCP servers on next launch. For the deeper plugin install, run: codex plugin marketplace add rohitg00/agentmemory && codex plugin install agentmemory\",\n );\n return {\n kind: \"installed\",\n mutatedPath: CODEX_TOML,\n ...(backupPath !== undefined && { backupPath }),\n };\n },\n};\n","import { existsSync, mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport * as p from \"@clack/prompts\";\nimport type { ConnectAdapter, ConnectOptions, ConnectResult } from \"./types.js\";\nimport {\n AGENTMEMORY_MCP_BLOCK,\n backupFile,\n logAlreadyWired,\n logBackup,\n logInstalled,\n readJsonSafe,\n writeJsonAtomic,\n} from \"./util.js\";\n\nexport type JsonMcpAdapterConfig = {\n name: string;\n displayName: string;\n detectDir: string;\n configPath: string;\n docs?: string;\n};\n\ntype McpEntry = typeof AGENTMEMORY_MCP_BLOCK;\ntype McpConfig = {\n mcpServers?: Record<string, McpEntry>;\n [key: string]: unknown;\n};\n\nfunction entryMatches(entry: unknown): boolean {\n if (!entry || typeof entry !== \"object\") return false;\n const e = entry as Record<string, unknown>;\n if (e[\"command\"] !== \"npx\") return false;\n const args = Array.isArray(e[\"args\"]) ? (e[\"args\"] as string[]) : [];\n return args.includes(\"@agentmemory/mcp\");\n}\n\nexport function createJsonMcpAdapter(\n config: JsonMcpAdapterConfig,\n): ConnectAdapter {\n return {\n name: config.name,\n displayName: config.displayName,\n ...(config.docs !== undefined && { docs: config.docs }),\n\n detect(): boolean {\n return existsSync(config.detectDir);\n },\n\n async install(opts: ConnectOptions): Promise<ConnectResult> {\n const existing = readJsonSafe<McpConfig>(config.configPath);\n const next: McpConfig = existing ? { ...existing } : {};\n const servers: Record<string, McpEntry> = {\n ...((next.mcpServers as Record<string, McpEntry>) ?? {}),\n };\n\n const alreadyHas = entryMatches(servers[\"agentmemory\"]);\n if (alreadyHas && !opts.force) {\n logAlreadyWired(config.displayName, config.configPath);\n return { kind: \"already-wired\", mutatedPath: config.configPath };\n }\n\n if (opts.dryRun) {\n p.log.info(\n `[dry-run] Would ${alreadyHas ? \"overwrite\" : \"add\"} mcpServers.agentmemory in ${config.configPath}`,\n );\n return { kind: \"installed\", mutatedPath: config.configPath };\n }\n\n let backupPath: string | undefined;\n if (existsSync(config.configPath)) {\n backupPath = backupFile(config.configPath, config.name);\n logBackup(backupPath);\n } else {\n mkdirSync(dirname(config.configPath), { recursive: true });\n }\n\n servers[\"agentmemory\"] = AGENTMEMORY_MCP_BLOCK;\n next.mcpServers = servers;\n writeJsonAtomic(config.configPath, next);\n\n const verify = readJsonSafe<McpConfig>(config.configPath);\n if (!entryMatches(verify?.mcpServers?.[\"agentmemory\"])) {\n p.log.error(\n `Verification failed: ${config.configPath} did not contain mcpServers.agentmemory after write.`,\n );\n return { kind: \"skipped\", reason: \"verification-failed\" };\n }\n\n logInstalled(config.displayName, config.configPath);\n return {\n kind: \"installed\",\n mutatedPath: config.configPath,\n ...(backupPath !== undefined && { backupPath }),\n };\n },\n };\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { createJsonMcpAdapter } from \"./json-mcp-adapter.js\";\n\nexport const adapter = createJsonMcpAdapter({\n name: \"cursor\",\n displayName: \"Cursor\",\n detectDir: join(homedir(), \".cursor\"),\n configPath: join(homedir(), \".cursor\", \"mcp.json\"),\n docs: \"https://github.com/rohitg00/agentmemory#other-agents\",\n});\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { createJsonMcpAdapter } from \"./json-mcp-adapter.js\";\n\nexport const adapter = createJsonMcpAdapter({\n name: \"gemini-cli\",\n displayName: \"Gemini CLI\",\n detectDir: join(homedir(), \".gemini\"),\n configPath: join(homedir(), \".gemini\", \"settings.json\"),\n docs: \"https://github.com/rohitg00/agentmemory#other-agents\",\n});\n","import { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport * as p from \"@clack/prompts\";\nimport type { ConnectAdapter, ConnectOptions, ConnectResult } from \"./types.js\";\n\nconst HERMES_DIR = join(homedir(), \".hermes\");\nconst HERMES_CONFIG = join(HERMES_DIR, \"config.yaml\");\nconst DOCS = \"https://github.com/rohitg00/agentmemory/tree/main/integrations/hermes\";\n\nexport const adapter: ConnectAdapter = {\n name: \"hermes\",\n displayName: \"Hermes Agent\",\n docs: DOCS,\n\n detect(): boolean {\n return existsSync(HERMES_DIR);\n },\n\n async install(_opts: ConnectOptions): Promise<ConnectResult> {\n p.log.warn(\n \"Hermes uses YAML config. Automated merge isn't implemented yet — manual install required.\",\n );\n p.note(\n [\n `Add to ${HERMES_CONFIG}:`,\n \"\",\n \" mcp_servers:\",\n \" agentmemory:\",\n \" command: npx\",\n ' args: [\"-y\", \"@agentmemory/mcp\"]',\n \"\",\n \" memory:\",\n \" provider: agentmemory\",\n \"\",\n `Full guide: ${DOCS}`,\n ].join(\"\\n\"),\n \"Hermes manual install\",\n );\n return {\n kind: \"stub\",\n reason: \"yaml-merge-not-implemented\",\n };\n },\n};\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { createJsonMcpAdapter } from \"./json-mcp-adapter.js\";\n\nexport const adapter = createJsonMcpAdapter({\n name: \"openclaw\",\n displayName: \"OpenClaw\",\n detectDir: join(homedir(), \".openclaw\"),\n configPath: join(homedir(), \".openclaw\", \"openclaw.json\"),\n docs: \"https://github.com/rohitg00/agentmemory/tree/main/integrations/openclaw\",\n});\n","import { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport * as p from \"@clack/prompts\";\nimport type { ConnectAdapter, ConnectOptions, ConnectResult } from \"./types.js\";\n\nconst OPENHUMAN_DIR = join(homedir(), \".openhuman\");\nconst DOCS = \"https://github.com/tinyhumansai/openhuman\";\n\nexport const adapter: ConnectAdapter = {\n name: \"openhuman\",\n displayName: \"OpenHuman\",\n docs: DOCS,\n\n detect(): boolean {\n return existsSync(OPENHUMAN_DIR);\n },\n\n async install(_opts: ConnectOptions): Promise<ConnectResult> {\n p.log.warn(\n \"OpenHuman integration is not yet automated. No `integrations/openhuman/` folder exists in the agentmemory repo today.\",\n );\n p.note(\n [\n \"OpenHuman is a Memory-trait host. The expected wiring is the REST\",\n \"proxy at http://localhost:3111 plus an OpenHuman-side Memory trait\",\n \"impl. Once integrations/openhuman/ lands in agentmemory we'll wire\",\n \"this up automatically.\",\n \"\",\n `Tracking: ${DOCS}`,\n ].join(\"\\n\"),\n \"OpenHuman manual install\",\n );\n return {\n kind: \"stub\",\n reason: \"no-integration-folder-yet\",\n };\n },\n};\n","import { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport * as p from \"@clack/prompts\";\nimport type { ConnectAdapter, ConnectOptions, ConnectResult } from \"./types.js\";\n\nconst PI_DIR = join(homedir(), \".pi\");\nconst PI_EXT_DIR = join(PI_DIR, \"agent\", \"extensions\", \"agentmemory\");\nconst DOCS = \"https://github.com/rohitg00/agentmemory/tree/main/integrations/pi\";\n\nexport const adapter: ConnectAdapter = {\n name: \"pi\",\n displayName: \"pi\",\n docs: DOCS,\n\n detect(): boolean {\n return existsSync(PI_DIR);\n },\n\n async install(_opts: ConnectOptions): Promise<ConnectResult> {\n p.log.warn(\n \"pi uses a TypeScript extension file. Automated copy + register isn't implemented yet — manual install required.\",\n );\n p.note(\n [\n \"Run these from the agentmemory repo root:\",\n \"\",\n ` mkdir -p ${PI_EXT_DIR}`,\n ` cp integrations/pi/index.ts ${PI_EXT_DIR}/index.ts`,\n ` cp integrations/pi/security.ts ${PI_EXT_DIR}/security.ts`,\n \"\",\n \"Then add to ~/.pi/agent/settings.json:\",\n ' { \"extensions\": [\"~/.pi/agent/extensions/agentmemory\"] }',\n \"\",\n `Full guide: ${DOCS}`,\n ].join(\"\\n\"),\n \"pi manual install\",\n );\n return {\n kind: \"stub\",\n reason: \"ts-extension-copy-not-implemented\",\n };\n },\n};\n","import { platform } from \"node:os\";\nimport * as p from \"@clack/prompts\";\nimport type { ConnectAdapter, ConnectOptions, ConnectResult } from \"./types.js\";\nimport { adapter as claudeCode } from \"./claude-code.js\";\nimport { adapter as codex } from \"./codex.js\";\nimport { adapter as cursor } from \"./cursor.js\";\nimport { adapter as geminiCli } from \"./gemini-cli.js\";\nimport { adapter as hermes } from \"./hermes.js\";\nimport { adapter as openclaw } from \"./openclaw.js\";\nimport { adapter as openhuman } from \"./openhuman.js\";\nimport { adapter as pi } from \"./pi.js\";\n\nexport const ADAPTERS: readonly ConnectAdapter[] = [\n claudeCode,\n codex,\n cursor,\n geminiCli,\n openclaw,\n hermes,\n pi,\n openhuman,\n];\n\nexport function resolveAdapter(name: string): ConnectAdapter | null {\n const lower = name.toLowerCase();\n return ADAPTERS.find((a) => a.name === lower) ?? null;\n}\n\nexport function knownAgents(): string[] {\n return ADAPTERS.map((a) => a.name);\n}\n\nfunction parseFlags(args: string[]): {\n dryRun: boolean;\n force: boolean;\n all: boolean;\n positional: string[];\n} {\n const positional: string[] = [];\n let dryRun = false;\n let force = false;\n let all = false;\n for (const a of args) {\n if (a === \"--dry-run\") dryRun = true;\n else if (a === \"--force\") force = true;\n else if (a === \"--all\") all = true;\n else if (!a.startsWith(\"-\")) positional.push(a);\n }\n return { dryRun, force, all, positional };\n}\n\nasync function runAdapter(\n adapter: ConnectAdapter,\n opts: ConnectOptions,\n): Promise<ConnectResult> {\n if (!adapter.detect()) {\n p.log.warn(\n `${adapter.displayName}: not detected on this machine (skipping).${adapter.docs ? ` Docs: ${adapter.docs}` : \"\"}`,\n );\n return { kind: \"skipped\", reason: \"not-detected\" };\n }\n p.log.step(`Wiring ${adapter.displayName}…`);\n try {\n return await adapter.install(opts);\n } catch (err) {\n p.log.error(\n `${adapter.displayName}: ${err instanceof Error ? err.message : String(err)}`,\n );\n return { kind: \"skipped\", reason: \"exception\" };\n }\n}\n\nexport async function runConnect(args: string[]): Promise<void> {\n if (platform() === \"win32\") {\n p.intro(\"agentmemory connect\");\n p.log.warn(\n \"Windows: automated `connect` is not supported yet. See https://github.com/rohitg00/agentmemory#other-agents for manual install steps.\",\n );\n p.outro(\"Windows: manual install required — see docs\");\n return;\n }\n\n const { dryRun, force, all, positional } = parseFlags(args);\n const opts: ConnectOptions = { dryRun, force };\n\n p.intro(\"agentmemory connect\");\n\n if (positional.length === 0 && !all) {\n const detected = ADAPTERS.filter((a) => a.detect());\n if (detected.length === 0) {\n p.log.error(\"No supported agents detected on this machine.\");\n p.outro(`Supported: ${knownAgents().join(\", \")}`);\n process.exit(1);\n }\n const picked = await p.multiselect<string>({\n message: \"Wire agentmemory into which agents?\",\n options: detected.map((a) => ({ value: a.name, label: a.displayName })),\n required: true,\n });\n if (p.isCancel(picked)) {\n p.cancel(\"Cancelled.\");\n return;\n }\n const results: { name: string; result: ConnectResult }[] = [];\n for (const name of picked as string[]) {\n const adapter = resolveAdapter(name);\n if (!adapter) continue;\n results.push({ name, result: await runAdapter(adapter, opts) });\n }\n summarize(results);\n return;\n }\n\n if (all) {\n const detected = ADAPTERS.filter((a) => a.detect());\n if (detected.length === 0) {\n p.log.error(\"No supported agents detected on this machine.\");\n process.exit(1);\n }\n const results: { name: string; result: ConnectResult }[] = [];\n for (const adapter of detected) {\n results.push({\n name: adapter.name,\n result: await runAdapter(adapter, opts),\n });\n }\n summarize(results);\n return;\n }\n\n const agentName = positional[0]!;\n const adapter = resolveAdapter(agentName);\n if (!adapter) {\n p.log.error(`Unknown agent: ${agentName}`);\n p.outro(`Supported: ${knownAgents().join(\", \")}`);\n process.exit(1);\n }\n\n const result = await runAdapter(adapter, opts);\n summarize([{ name: agentName, result }]);\n if (result.kind === \"skipped\" && (result as { reason: string }).reason !== \"not-detected\") {\n process.exit(1);\n }\n}\n\nfunction summarize(\n results: { name: string; result: ConnectResult }[],\n): void {\n const lines = results.map(({ name, result }) => {\n switch (result.kind) {\n case \"installed\":\n return ` ✓ ${name}${result.mutatedPath ? ` → ${result.mutatedPath}` : \"\"}`;\n case \"already-wired\":\n return ` ✓ ${name} (already wired)`;\n case \"stub\":\n return ` ⚠ ${name} (manual install required: ${result.reason})`;\n case \"skipped\":\n return ` ✗ ${name} (skipped: ${result.reason})`;\n }\n });\n p.note(lines.join(\"\\n\"), \"summary\");\n\n const stubs = results.filter((r) => r.result.kind === \"stub\");\n if (stubs.length > 0) {\n p.log.info(\n `${stubs.length} agent(s) require manual install — see docs links above.`,\n );\n }\n p.outro(\"Restart any wired agent (or open a new session) to pick up agentmemory.\");\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as KV } from "./cli.mjs";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import { join, resolve, sep } from "node:path";
|
|
4
4
|
import { homedir } from "node:os";
|
|
@@ -113,4 +113,4 @@ async function decrementImageRef(kv, sdk, filePath) {
|
|
|
113
113
|
|
|
114
114
|
//#endregion
|
|
115
115
|
export { isManagedImagePath as a, decrementImageRef, getImageRefCount, getMaxBytes as i, incrementImageRef, IMAGES_DIR as n, saveImageToDisk as o, deleteImage as r, touchImage as s, withKeyedLock as t };
|
|
116
|
-
//# sourceMappingURL=image-refs-
|
|
116
|
+
//# sourceMappingURL=image-refs-R3tin9MR.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-refs-
|
|
1
|
+
{"version":3,"file":"image-refs-R3tin9MR.mjs","names":[],"sources":["../src/utils/image-store.ts","../src/state/keyed-mutex.ts","../src/functions/image-refs.ts"],"sourcesContent":["import { homedir } from \"node:os\";\nimport { join, resolve, sep } from \"node:path\";\nimport { existsSync } from \"node:fs\";\nimport { mkdir, writeFile, unlink, utimes, stat } from \"node:fs/promises\";\nimport { createHash } from \"node:crypto\";\n\nexport const IMAGES_DIR = join(homedir(), \".agentmemory\", \"images\");\n\nconst DEFAULT_MAX_BYTES = 500 * 1024 * 1024;\n\nexport function getMaxBytes(): number {\n return Number(process.env.AGENTMEMORY_IMAGE_STORE_MAX_BYTES) || DEFAULT_MAX_BYTES;\n}\n\nexport function isManagedImagePath(filePath: string): boolean {\n const resolved = resolve(filePath);\n const normalizedImagesDir = resolve(IMAGES_DIR);\n return resolved.startsWith(normalizedImagesDir + sep) || resolved === normalizedImagesDir;\n}\n\nfunction contentHash(data: string): string {\n return createHash(\"sha256\").update(data).digest(\"hex\");\n}\n\nexport async function saveImageToDisk(base64Data: string): Promise<{ filePath: string; bytesWritten: number }> {\n if (!base64Data) return { filePath: \"\", bytesWritten: 0 };\n\n if (!existsSync(IMAGES_DIR)) {\n await mkdir(IMAGES_DIR, { recursive: true });\n }\n\n let cleanBase64 = base64Data;\n let ext = \"png\";\n\n if (base64Data.startsWith(\"data:image/\")) {\n const commaIdx = base64Data.indexOf(\",\");\n if (commaIdx !== -1) {\n const meta = base64Data.substring(0, commaIdx);\n if (meta.includes(\"jpeg\") || meta.includes(\"jpg\")) ext = \"jpg\";\n else if (meta.includes(\"webp\")) ext = \"webp\";\n else if (meta.includes(\"gif\")) ext = \"gif\";\n cleanBase64 = base64Data.substring(commaIdx + 1);\n }\n } else if (base64Data.startsWith(\"/9j/\")) {\n ext = \"jpg\";\n }\n\n const hash = contentHash(cleanBase64);\n const filePath = join(IMAGES_DIR, `${hash}.${ext}`);\n\n if (existsSync(filePath)) {\n return { filePath, bytesWritten: 0 };\n }\n\n const buffer = Buffer.from(cleanBase64, \"base64\");\n await writeFile(filePath, buffer);\n\n const s = await stat(filePath);\n\n return { filePath, bytesWritten: s.size };\n}\n\nexport async function deleteImage(filePath: string | undefined): Promise<{ deletedBytes: number }> {\n if (!filePath) return { deletedBytes: 0 };\n if (!isManagedImagePath(filePath)) return { deletedBytes: 0 };\n try {\n if (existsSync(filePath)) {\n const s = await stat(filePath);\n const size = s.size;\n await unlink(filePath);\n return { deletedBytes: size };\n }\n } catch (err) {\n console.error(\"[agentmemory] Failed to delete image context:\", err);\n }\n return { deletedBytes: 0 };\n}\n\n/** Touch an image file to update its mtime (marking it as recently used for LRU eviction) */\nexport async function touchImage(filePath: string): Promise<void> {\n if (!filePath || !isManagedImagePath(filePath)) return;\n try {\n if (existsSync(filePath)) {\n const now = new Date();\n await utimes(filePath, now, now);\n }\n } catch (err) {\n // Ignore touch errors silently\n }\n}\n","const locks = new Map<string, Promise<void>>();\n\nexport function withKeyedLock<T>(\n key: string,\n fn: () => Promise<T>,\n): Promise<T> {\n const prev = locks.get(key) ?? Promise.resolve();\n const next = prev.then(fn, fn);\n const cleanup = next.then(\n () => {},\n () => {},\n );\n locks.set(key, cleanup);\n cleanup.then(() => {\n if (locks.get(key) === cleanup) locks.delete(key);\n });\n return next;\n}\n","import type { ISdk } from \"iii-sdk\";\nimport { KV } from \"../state/schema.js\";\nimport { StateKV } from \"../state/kv.js\";\nimport { deleteImage, touchImage } from \"../utils/image-store.js\";\nimport { withKeyedLock } from \"../state/keyed-mutex.js\";\n\nexport async function getImageRefCount(kv: StateKV, filePath: string): Promise<number> {\n const count = await kv.get<number>(KV.imageRefs, filePath);\n return count ? Number(count) : 0;\n}\n\nexport async function incrementImageRef(kv: StateKV, filePath: string): Promise<void> {\n return withKeyedLock(`imgRef:${filePath}`, async () => {\n const current = await getImageRefCount(kv, filePath);\n await kv.set(KV.imageRefs, filePath, current + 1);\n await touchImage(filePath);\n });\n}\n\nexport async function decrementImageRef(kv: StateKV, sdk: ISdk, filePath: string): Promise<void> {\n return withKeyedLock(`imgRef:${filePath}`, async () => {\n const current = await getImageRefCount(kv, filePath);\n if (current <= 1) {\n await kv.delete(KV.imageEmbeddings, filePath);\n await kv.delete(KV.imageRefs, filePath);\n const { deletedBytes } = await deleteImage(filePath);\n if (deletedBytes > 0) {\n sdk.triggerVoid(\"mem::disk-size-delta\", { deltaBytes: -deletedBytes });\n }\n } else {\n await kv.set(KV.imageRefs, filePath, current - 1);\n }\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as isManagedImagePath, i as getMaxBytes, n as IMAGES_DIR, o as saveImageToDisk, r as deleteImage, s as touchImage } from "./image-refs-
|
|
1
|
+
import { a as isManagedImagePath, i as getMaxBytes, n as IMAGES_DIR, o as saveImageToDisk, r as deleteImage, s as touchImage } from "./image-refs-R3tin9MR.mjs";
|
|
2
2
|
|
|
3
3
|
export { deleteImage, saveImageToDisk };
|