@agentmemory/agentmemory 0.9.21 → 0.9.23
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 +7 -2
- package/README.md +288 -33
- package/dist/cli.d.mts +5 -1
- package/dist/cli.d.mts.map +1 -0
- package/dist/cli.mjs +128 -703
- package/dist/cli.mjs.map +1 -1
- package/dist/connect-Cf9bmBqO.mjs +1020 -0
- package/dist/connect-Cf9bmBqO.mjs.map +1 -0
- package/dist/hooks/notification.mjs +46 -21
- package/dist/hooks/notification.mjs.map +1 -1
- package/dist/hooks/post-tool-failure.mjs +47 -21
- package/dist/hooks/post-tool-failure.mjs.map +1 -1
- package/dist/hooks/post-tool-use.mjs +57 -22
- package/dist/hooks/post-tool-use.mjs.map +1 -1
- package/dist/hooks/pre-compact.mjs +26 -2
- package/dist/hooks/pre-compact.mjs.map +1 -1
- package/dist/hooks/pre-tool-use.mjs +19 -12
- package/dist/hooks/pre-tool-use.mjs.map +1 -1
- package/dist/hooks/prompt-submit.mjs +39 -16
- package/dist/hooks/prompt-submit.mjs.map +1 -1
- package/dist/hooks/session-end.mjs +26 -33
- package/dist/hooks/session-end.mjs.map +1 -1
- package/dist/hooks/session-start.mjs +28 -3
- package/dist/hooks/session-start.mjs.map +1 -1
- package/dist/hooks/stop.mjs +14 -9
- package/dist/hooks/stop.mjs.map +1 -1
- package/dist/hooks/subagent-start.mjs +31 -4
- package/dist/hooks/subagent-start.mjs.map +1 -1
- package/dist/hooks/subagent-stop.mjs +45 -20
- package/dist/hooks/subagent-stop.mjs.map +1 -1
- package/dist/hooks/task-completed.mjs +44 -21
- package/dist/hooks/task-completed.mjs.map +1 -1
- package/dist/iii-config.docker.yaml +3 -2
- package/dist/iii-config.yaml +11 -2
- package/dist/{image-refs-R3tin9MR.mjs → image-refs-CJS5B9Gq.mjs} +2 -2
- package/dist/{image-refs-R3tin9MR.mjs.map → image-refs-CJS5B9Gq.mjs.map} +1 -1
- package/dist/{image-store-DyrKZKqZ.mjs → image-store-CdE0amb1.mjs} +1 -1
- package/dist/index.mjs +866 -380
- package/dist/index.mjs.map +1 -1
- package/dist/logger-xlVlvCWX.mjs +43 -0
- package/dist/logger-xlVlvCWX.mjs.map +1 -0
- package/dist/schema-BkALl7Z_.mjs +74 -0
- package/dist/schema-BkALl7Z_.mjs.map +1 -0
- package/dist/{src-D5arboxc.mjs → src-DvS3bhMe.mjs} +844 -395
- package/dist/src-DvS3bhMe.mjs.map +1 -0
- package/dist/{standalone-C7BgzzIN.mjs → standalone-DHQcPX_g.mjs} +107 -14
- package/dist/standalone-DHQcPX_g.mjs.map +1 -0
- package/dist/standalone.d.mts.map +1 -1
- package/dist/standalone.mjs +108 -12
- package/dist/standalone.mjs.map +1 -1
- package/dist/{tools-registry-CRTWUFw9.mjs → tools-registry-DJizX9Az.mjs} +51 -12
- package/dist/tools-registry-DJizX9Az.mjs.map +1 -0
- package/dist/version-BPfyI4Kc.mjs +6 -0
- package/dist/version-BPfyI4Kc.mjs.map +1 -0
- package/dist/viewer/index.html +85 -10
- package/iii-config.docker.yaml +3 -2
- package/iii-config.yaml +11 -2
- package/package.json +6 -4
- package/plugin/.claude-plugin/plugin.json +2 -2
- package/plugin/.codex-plugin/plugin.json +2 -2
- package/plugin/.mcp.copilot.json +15 -0
- package/plugin/.mcp.json +3 -2
- package/plugin/hooks/hooks.copilot.json +72 -0
- package/plugin/opencode/agentmemory-capture.ts +34 -9
- package/plugin/plugin.json +15 -0
- package/plugin/scripts/diagnostics.d.mts +17 -0
- package/plugin/scripts/diagnostics.d.mts.map +1 -0
- package/plugin/scripts/diagnostics.mjs.map +1 -0
- package/plugin/scripts/notification.mjs +46 -21
- package/plugin/scripts/notification.mjs.map +1 -1
- package/plugin/scripts/post-tool-failure.mjs +47 -21
- package/plugin/scripts/post-tool-failure.mjs.map +1 -1
- package/plugin/scripts/post-tool-use.mjs +57 -22
- package/plugin/scripts/post-tool-use.mjs.map +1 -1
- package/plugin/scripts/pre-compact.mjs +26 -2
- package/plugin/scripts/pre-compact.mjs.map +1 -1
- package/plugin/scripts/pre-tool-use.mjs +19 -12
- package/plugin/scripts/pre-tool-use.mjs.map +1 -1
- package/plugin/scripts/prompt-submit.mjs +39 -16
- package/plugin/scripts/prompt-submit.mjs.map +1 -1
- package/plugin/scripts/session-end.mjs +26 -33
- package/plugin/scripts/session-end.mjs.map +1 -1
- package/plugin/scripts/session-start.mjs +28 -3
- package/plugin/scripts/session-start.mjs.map +1 -1
- package/plugin/scripts/stop.mjs +14 -9
- package/plugin/scripts/stop.mjs.map +1 -1
- package/plugin/scripts/subagent-start.mjs +31 -4
- package/plugin/scripts/subagent-start.mjs.map +1 -1
- package/plugin/scripts/subagent-stop.mjs +45 -20
- package/plugin/scripts/subagent-stop.mjs.map +1 -1
- package/plugin/scripts/task-completed.mjs +44 -21
- package/plugin/scripts/task-completed.mjs.map +1 -1
- package/dist/src-D5arboxc.mjs.map +0 -1
- package/dist/standalone-C7BgzzIN.mjs.map +0 -1
- package/dist/tools-registry-CRTWUFw9.mjs.map +0 -1
|
@@ -0,0 +1,1020 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { homedir, platform } from "node:os";
|
|
6
|
+
import * as p from "@clack/prompts";
|
|
7
|
+
|
|
8
|
+
//#region \0rolldown/runtime.js
|
|
9
|
+
var __defProp = Object.defineProperty;
|
|
10
|
+
var __exportAll = (all, no_symbols) => {
|
|
11
|
+
let target = {};
|
|
12
|
+
for (var name in all) {
|
|
13
|
+
__defProp(target, name, {
|
|
14
|
+
get: all[name],
|
|
15
|
+
enumerable: true
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
if (!no_symbols) {
|
|
19
|
+
__defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
20
|
+
}
|
|
21
|
+
return target;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/cli/connect/util.ts
|
|
26
|
+
const AGENTMEMORY_MCP_BLOCK = {
|
|
27
|
+
command: "npx",
|
|
28
|
+
args: ["-y", "@agentmemory/mcp"],
|
|
29
|
+
env: {
|
|
30
|
+
AGENTMEMORY_URL: "${AGENTMEMORY_URL:-http://localhost:3111}",
|
|
31
|
+
AGENTMEMORY_SECRET: "${AGENTMEMORY_SECRET:-}",
|
|
32
|
+
AGENTMEMORY_TOOLS: "${AGENTMEMORY_TOOLS:-all}"
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const COPILOT_MCP_COMMAND = process.platform === "win32" ? {
|
|
36
|
+
command: process.env["ComSpec"] || process.env["COMSPEC"] || "cmd.exe",
|
|
37
|
+
args: [
|
|
38
|
+
"/d",
|
|
39
|
+
"/s",
|
|
40
|
+
"/c",
|
|
41
|
+
"npx",
|
|
42
|
+
"-y",
|
|
43
|
+
"@agentmemory/mcp"
|
|
44
|
+
]
|
|
45
|
+
} : {
|
|
46
|
+
command: "npx",
|
|
47
|
+
args: ["-y", "@agentmemory/mcp"]
|
|
48
|
+
};
|
|
49
|
+
const AGENTMEMORY_COPILOT_MCP_BLOCK = {
|
|
50
|
+
type: "local",
|
|
51
|
+
...COPILOT_MCP_COMMAND,
|
|
52
|
+
env: {
|
|
53
|
+
AGENTMEMORY_URL: "${AGENTMEMORY_URL:-http://localhost:3111}",
|
|
54
|
+
AGENTMEMORY_SECRET: "${AGENTMEMORY_SECRET:-}",
|
|
55
|
+
AGENTMEMORY_TOOLS: "${AGENTMEMORY_TOOLS:-all}"
|
|
56
|
+
},
|
|
57
|
+
tools: ["*"]
|
|
58
|
+
};
|
|
59
|
+
function backupsDir() {
|
|
60
|
+
return join(homedir(), ".agentmemory", "backups");
|
|
61
|
+
}
|
|
62
|
+
function ensureBackupsDir() {
|
|
63
|
+
const dir = backupsDir();
|
|
64
|
+
mkdirSync(dir, { recursive: true });
|
|
65
|
+
return dir;
|
|
66
|
+
}
|
|
67
|
+
function timestampSlug() {
|
|
68
|
+
return (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
69
|
+
}
|
|
70
|
+
function backupFile(sourcePath, agent, ext = "json") {
|
|
71
|
+
ensureBackupsDir();
|
|
72
|
+
const stamp = timestampSlug();
|
|
73
|
+
const target = join(backupsDir(), `${agent}-${stamp}.${ext}`);
|
|
74
|
+
copyFileSync(sourcePath, target);
|
|
75
|
+
return target;
|
|
76
|
+
}
|
|
77
|
+
function readJsonSafe(path) {
|
|
78
|
+
if (!existsSync(path)) return null;
|
|
79
|
+
try {
|
|
80
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
81
|
+
} catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function writeJsonAtomic(path, value) {
|
|
86
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
87
|
+
const tmp = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
88
|
+
writeFileSync(tmp, `${JSON.stringify(value, null, 2)}\n`, "utf-8");
|
|
89
|
+
renameSync(tmp, path);
|
|
90
|
+
}
|
|
91
|
+
function logInstalled(label, target) {
|
|
92
|
+
p.log.success(`${label} → wired into ${target}`);
|
|
93
|
+
}
|
|
94
|
+
function logAlreadyWired(label, target) {
|
|
95
|
+
p.log.info(`${label} already wired in ${target} (use --force to re-install)`);
|
|
96
|
+
}
|
|
97
|
+
function logBackup(target) {
|
|
98
|
+
p.log.info(`Backup: ${target}`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
//#endregion
|
|
102
|
+
//#region src/cli/connect/json-mcp-adapter.ts
|
|
103
|
+
function entryMatches$2(entry) {
|
|
104
|
+
if (!entry || typeof entry !== "object") return false;
|
|
105
|
+
const e = entry;
|
|
106
|
+
if (e["command"] !== "npx") return false;
|
|
107
|
+
return (Array.isArray(e["args"]) ? e["args"] : []).includes("@agentmemory/mcp");
|
|
108
|
+
}
|
|
109
|
+
function createJsonMcpAdapter(config) {
|
|
110
|
+
const wrapperKey = config.wrapperKey ?? "mcpServers";
|
|
111
|
+
return {
|
|
112
|
+
name: config.name,
|
|
113
|
+
displayName: config.displayName,
|
|
114
|
+
...config.docs !== void 0 && { docs: config.docs },
|
|
115
|
+
...config.protocolNote !== void 0 && { protocolNote: config.protocolNote },
|
|
116
|
+
detect() {
|
|
117
|
+
return existsSync(config.detectDir);
|
|
118
|
+
},
|
|
119
|
+
async install(opts) {
|
|
120
|
+
const existing = readJsonSafe(config.configPath);
|
|
121
|
+
const next = existing ? { ...existing } : {};
|
|
122
|
+
const servers = { ...next[wrapperKey] ?? {} };
|
|
123
|
+
const alreadyHas = entryMatches$2(servers["agentmemory"]);
|
|
124
|
+
if (alreadyHas && !opts.force) {
|
|
125
|
+
logAlreadyWired(config.displayName, config.configPath);
|
|
126
|
+
return {
|
|
127
|
+
kind: "already-wired",
|
|
128
|
+
mutatedPath: config.configPath
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
if (opts.dryRun) {
|
|
132
|
+
p.log.info(`[dry-run] Would ${alreadyHas ? "overwrite" : "add"} ${wrapperKey}.agentmemory in ${config.configPath}`);
|
|
133
|
+
return {
|
|
134
|
+
kind: "installed",
|
|
135
|
+
mutatedPath: config.configPath
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
let backupPath;
|
|
139
|
+
if (existsSync(config.configPath)) {
|
|
140
|
+
backupPath = backupFile(config.configPath, config.name);
|
|
141
|
+
logBackup(backupPath);
|
|
142
|
+
} else mkdirSync(dirname(config.configPath), { recursive: true });
|
|
143
|
+
servers["agentmemory"] = {
|
|
144
|
+
...AGENTMEMORY_MCP_BLOCK,
|
|
145
|
+
...config.extraEntryFields ?? {}
|
|
146
|
+
};
|
|
147
|
+
next[wrapperKey] = servers;
|
|
148
|
+
writeJsonAtomic(config.configPath, next);
|
|
149
|
+
const verifyServers = readJsonSafe(config.configPath)?.[wrapperKey];
|
|
150
|
+
if (!entryMatches$2(verifyServers?.["agentmemory"])) {
|
|
151
|
+
p.log.error(`Verification failed: ${config.configPath} did not contain ${wrapperKey}.agentmemory after write.`);
|
|
152
|
+
return {
|
|
153
|
+
kind: "skipped",
|
|
154
|
+
reason: "verification-failed"
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
logInstalled(config.displayName, config.configPath);
|
|
158
|
+
return {
|
|
159
|
+
kind: "installed",
|
|
160
|
+
mutatedPath: config.configPath,
|
|
161
|
+
...backupPath !== void 0 && { backupPath }
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
//#endregion
|
|
168
|
+
//#region src/cli/connect/antigravity.ts
|
|
169
|
+
const ANTIGRAVITY_DIR = platform() === "darwin" ? join(homedir(), "Library", "Application Support", "Antigravity", "User") : join(homedir(), ".config", "Antigravity", "User");
|
|
170
|
+
const adapter$16 = createJsonMcpAdapter({
|
|
171
|
+
name: "antigravity",
|
|
172
|
+
displayName: "Antigravity",
|
|
173
|
+
detectDir: ANTIGRAVITY_DIR,
|
|
174
|
+
configPath: join(ANTIGRAVITY_DIR, "mcp_config.json"),
|
|
175
|
+
docs: "https://github.com/rohitg00/agentmemory#other-agents",
|
|
176
|
+
protocolNote: "→ Using MCP via mcp_config.json. Antigravity replaces Gemini CLI (sunset 2026-06-18)."
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
//#endregion
|
|
180
|
+
//#region src/cli/connect/codex-hooks.ts
|
|
181
|
+
/**
|
|
182
|
+
* Locate the bundled `plugin/` directory at runtime. Walks up from the
|
|
183
|
+
* module's own location looking for `plugin/scripts/` + `plugin/hooks/`,
|
|
184
|
+
* both shipped via the npm `files` field. Works for both `dist/cli.mjs`
|
|
185
|
+
* (bundled) and `src/cli/connect/codex-hooks.ts` (dev) layouts.
|
|
186
|
+
*/
|
|
187
|
+
function findPluginRoot(startUrl = import.meta.url) {
|
|
188
|
+
const here = dirname(fileURLToPath(startUrl));
|
|
189
|
+
let dir = here;
|
|
190
|
+
for (let i = 0; i < 12; i++) {
|
|
191
|
+
if (existsSync(join(dir, "plugin", "scripts")) && existsSync(join(dir, "plugin", "hooks"))) return resolve(join(dir, "plugin"));
|
|
192
|
+
const parent = dirname(dir);
|
|
193
|
+
if (parent === dir) break;
|
|
194
|
+
dir = parent;
|
|
195
|
+
}
|
|
196
|
+
throw new Error(`agentmemory: could not locate bundled plugin/ directory (searched up from ${here})`);
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Build the merged hooks.json content.
|
|
200
|
+
*
|
|
201
|
+
* 1. Strip any entry from `existing` whose first hook command points
|
|
202
|
+
* under `<pluginRoot>/scripts/`. This lets us re-install idempotently
|
|
203
|
+
* without leaving stale references.
|
|
204
|
+
* 2. Append fresh entries from the bundled Codex manifest with
|
|
205
|
+
* `${CLAUDE_PLUGIN_ROOT}` rewritten to the absolute plugin path.
|
|
206
|
+
* Matcher values from the bundled manifest are preserved so PreToolUse
|
|
207
|
+
* event routing keeps working.
|
|
208
|
+
*/
|
|
209
|
+
function buildMergedHooks(existing, pluginRoot, manifestFile = "hooks.codex.json") {
|
|
210
|
+
const bundledManifestPath = join(pluginRoot, "hooks", manifestFile);
|
|
211
|
+
const ours = JSON.parse(readFileSync(bundledManifestPath, "utf-8"));
|
|
212
|
+
const scriptsDir = join(pluginRoot, "scripts");
|
|
213
|
+
const out = { hooks: {} };
|
|
214
|
+
if (existing?.hooks) for (const [event, entries] of Object.entries(existing.hooks)) {
|
|
215
|
+
const kept = entries.filter((entry) => !isAgentmemoryEntry(entry, scriptsDir));
|
|
216
|
+
if (kept.length > 0) out.hooks[event] = kept;
|
|
217
|
+
}
|
|
218
|
+
for (const [event, entries] of Object.entries(ours.hooks)) {
|
|
219
|
+
const resolvedEntries = entries.map((entry) => {
|
|
220
|
+
const next = { hooks: entry.hooks.map((handler) => ({
|
|
221
|
+
type: handler.type,
|
|
222
|
+
command: handler.command.replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g, pluginRoot)
|
|
223
|
+
})) };
|
|
224
|
+
if (entry.matcher !== void 0) next.matcher = entry.matcher;
|
|
225
|
+
return next;
|
|
226
|
+
});
|
|
227
|
+
out.hooks[event] = [...out.hooks[event] ?? [], ...resolvedEntries];
|
|
228
|
+
}
|
|
229
|
+
return out;
|
|
230
|
+
}
|
|
231
|
+
function isAgentmemoryEntry(entry, scriptsDir) {
|
|
232
|
+
const normalizedScriptsDir = normalizePathForCommandMatch(scriptsDir);
|
|
233
|
+
return entry.hooks.some((handler) => normalizePathForCommandMatch(handler.command).includes(normalizedScriptsDir));
|
|
234
|
+
}
|
|
235
|
+
function normalizePathForCommandMatch(value) {
|
|
236
|
+
return value.replace(/\\/g, "/");
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
//#endregion
|
|
240
|
+
//#region src/cli/connect/claude-code.ts
|
|
241
|
+
const CLAUDE_DIR = join(homedir(), ".claude");
|
|
242
|
+
const CLAUDE_JSON = join(homedir(), ".claude.json");
|
|
243
|
+
const CLAUDE_SETTINGS = join(CLAUDE_DIR, "settings.json");
|
|
244
|
+
function entryMatches$1(entry) {
|
|
245
|
+
if (!entry || typeof entry !== "object") return false;
|
|
246
|
+
const e = entry;
|
|
247
|
+
if (e["command"] !== "npx") return false;
|
|
248
|
+
return (Array.isArray(e["args"]) ? e["args"] : []).includes("@agentmemory/mcp");
|
|
249
|
+
}
|
|
250
|
+
const adapter$15 = {
|
|
251
|
+
name: "claude-code",
|
|
252
|
+
displayName: "Claude Code",
|
|
253
|
+
docs: "https://github.com/rohitg00/agentmemory#claude-code-one-block-paste-it",
|
|
254
|
+
protocolNote: "→ Using MCP. Hooks are also available — see docs/claude-code.md.",
|
|
255
|
+
detect() {
|
|
256
|
+
return existsSync(CLAUDE_DIR);
|
|
257
|
+
},
|
|
258
|
+
async install(opts) {
|
|
259
|
+
const existing = readJsonSafe(CLAUDE_JSON);
|
|
260
|
+
const next = existing ? { ...existing } : {};
|
|
261
|
+
const servers = { ...next.mcpServers ?? {} };
|
|
262
|
+
const alreadyHas = entryMatches$1(servers["agentmemory"]);
|
|
263
|
+
if (alreadyHas && !opts.force) {
|
|
264
|
+
logAlreadyWired("Claude Code", CLAUDE_JSON);
|
|
265
|
+
if (opts.withHooks) {
|
|
266
|
+
const hookResult = installClaudeHooks(opts);
|
|
267
|
+
if (hookResult.kind === "skipped") p.log.warn(`Claude Code hooks fallback skipped: ${hookResult.reason}.`);
|
|
268
|
+
}
|
|
269
|
+
return {
|
|
270
|
+
kind: "already-wired",
|
|
271
|
+
mutatedPath: CLAUDE_JSON
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
if (opts.dryRun) {
|
|
275
|
+
p.log.info(`[dry-run] Would ${alreadyHas ? "overwrite" : "add"} mcpServers.agentmemory in ${CLAUDE_JSON}`);
|
|
276
|
+
return {
|
|
277
|
+
kind: "installed",
|
|
278
|
+
mutatedPath: CLAUDE_JSON
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
let backupPath;
|
|
282
|
+
if (existsSync(CLAUDE_JSON)) {
|
|
283
|
+
backupPath = backupFile(CLAUDE_JSON, "claude-code");
|
|
284
|
+
logBackup(backupPath);
|
|
285
|
+
} else {
|
|
286
|
+
mkdirSync(CLAUDE_DIR, { recursive: true });
|
|
287
|
+
writeFileSync(CLAUDE_JSON, "{}\n", "utf-8");
|
|
288
|
+
}
|
|
289
|
+
servers["agentmemory"] = AGENTMEMORY_MCP_BLOCK;
|
|
290
|
+
next.mcpServers = servers;
|
|
291
|
+
writeJsonAtomic(CLAUDE_JSON, next);
|
|
292
|
+
if (!entryMatches$1(readJsonSafe(CLAUDE_JSON)?.mcpServers?.["agentmemory"])) {
|
|
293
|
+
p.log.error(`Verification failed: ${CLAUDE_JSON} did not contain mcpServers.agentmemory after write.`);
|
|
294
|
+
return {
|
|
295
|
+
kind: "skipped",
|
|
296
|
+
reason: "verification-failed"
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
logInstalled("Claude Code", CLAUDE_JSON);
|
|
300
|
+
p.log.info("Restart Claude Code (or run `/mcp` inside a session) to pick up the new server.");
|
|
301
|
+
if (opts.withHooks) {
|
|
302
|
+
const hookResult = installClaudeHooks(opts);
|
|
303
|
+
if (hookResult.kind === "skipped") p.log.warn(`Claude Code hooks fallback skipped: ${hookResult.reason}. MCP wiring still applied.`);
|
|
304
|
+
}
|
|
305
|
+
return {
|
|
306
|
+
kind: "installed",
|
|
307
|
+
mutatedPath: CLAUDE_JSON,
|
|
308
|
+
backupPath
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
/**
|
|
313
|
+
* Merge the bundled `plugin/hooks/hooks.json` into
|
|
314
|
+
* `~/.claude/settings.json`'s top-level `hooks` field with absolute
|
|
315
|
+
* script paths. Use this when agentmemory is NOT installed through
|
|
316
|
+
* `/plugin marketplace add` (e.g. MCP standalone wiring), so the
|
|
317
|
+
* hook scripts survive version bumps without `${CLAUDE_PLUGIN_ROOT}`
|
|
318
|
+
* expansion (issue #508).
|
|
319
|
+
*
|
|
320
|
+
* Re-install strips entries whose command points under
|
|
321
|
+
* `<pluginRoot>/scripts/`; unrelated user hook entries survive.
|
|
322
|
+
*/
|
|
323
|
+
function installClaudeHooks(opts) {
|
|
324
|
+
let pluginRoot;
|
|
325
|
+
try {
|
|
326
|
+
pluginRoot = findPluginRoot();
|
|
327
|
+
} catch (err) {
|
|
328
|
+
return {
|
|
329
|
+
kind: "skipped",
|
|
330
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
const existing = readJsonSafe(CLAUDE_SETTINGS) ?? {};
|
|
334
|
+
const merged = buildMergedHooks(existing.hooks ? { hooks: existing.hooks } : null, pluginRoot, "hooks.json");
|
|
335
|
+
if (opts.dryRun) {
|
|
336
|
+
p.log.info(`[dry-run] Would merge agentmemory hook entries into ${CLAUDE_SETTINGS} (${Object.keys(merged.hooks).length} event(s))`);
|
|
337
|
+
return {
|
|
338
|
+
kind: "installed",
|
|
339
|
+
mutatedPath: CLAUDE_SETTINGS
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
let backupPath;
|
|
343
|
+
if (existsSync(CLAUDE_SETTINGS)) {
|
|
344
|
+
backupPath = backupFile(CLAUDE_SETTINGS, "claude-settings", "json");
|
|
345
|
+
logBackup(backupPath);
|
|
346
|
+
} else mkdirSync(CLAUDE_DIR, { recursive: true });
|
|
347
|
+
writeJsonAtomic(CLAUDE_SETTINGS, {
|
|
348
|
+
...existing,
|
|
349
|
+
hooks: merged.hooks
|
|
350
|
+
});
|
|
351
|
+
logInstalled("Claude Code hooks (workaround for #508)", CLAUDE_SETTINGS);
|
|
352
|
+
p.log.info("User-scope hook entries reference absolute paths under the bundled plugin/ dir. Re-run `agentmemory connect claude-code --with-hooks` after upgrading agentmemory to refresh them.");
|
|
353
|
+
return {
|
|
354
|
+
kind: "installed",
|
|
355
|
+
mutatedPath: CLAUDE_SETTINGS,
|
|
356
|
+
...backupPath !== void 0 && { backupPath }
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
//#endregion
|
|
361
|
+
//#region src/cli/connect/cline.ts
|
|
362
|
+
const adapter$14 = createJsonMcpAdapter({
|
|
363
|
+
name: "cline",
|
|
364
|
+
displayName: "Cline",
|
|
365
|
+
detectDir: join(homedir(), ".cline"),
|
|
366
|
+
configPath: join(homedir(), ".cline", "mcp.json"),
|
|
367
|
+
docs: "https://github.com/rohitg00/agentmemory#other-agents",
|
|
368
|
+
protocolNote: "→ Using MCP via ~/.cline/mcp.json (CLI). VS Code users: add the same block via Cline Settings → MCP Servers → Edit JSON."
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
//#endregion
|
|
372
|
+
//#region src/cli/connect/copilot-cli.ts
|
|
373
|
+
const COPILOT_DIR = process.env["COPILOT_HOME"] || join(homedir(), ".copilot");
|
|
374
|
+
const COPILOT_MCP_JSON = join(COPILOT_DIR, "mcp-config.json");
|
|
375
|
+
function entryMatches(entry) {
|
|
376
|
+
if (!entry || typeof entry !== "object") return false;
|
|
377
|
+
return JSON.stringify(entry) === JSON.stringify(AGENTMEMORY_COPILOT_MCP_BLOCK);
|
|
378
|
+
}
|
|
379
|
+
const adapter$13 = {
|
|
380
|
+
name: "copilot-cli",
|
|
381
|
+
displayName: "GitHub Copilot CLI",
|
|
382
|
+
docs: "https://github.com/rohitg00/agentmemory#github-copilot-cli",
|
|
383
|
+
protocolNote: "→ Using MCP. Install the plugin too for full hooks/skills coverage.",
|
|
384
|
+
detect() {
|
|
385
|
+
return existsSync(COPILOT_DIR);
|
|
386
|
+
},
|
|
387
|
+
async install(opts) {
|
|
388
|
+
const existing = readJsonSafe(COPILOT_MCP_JSON);
|
|
389
|
+
const next = existing ? { ...existing } : {};
|
|
390
|
+
const servers = { ...next.mcpServers ?? {} };
|
|
391
|
+
const alreadyHas = entryMatches(servers["agentmemory"]);
|
|
392
|
+
if (alreadyHas && !opts.force) {
|
|
393
|
+
logAlreadyWired("GitHub Copilot CLI", COPILOT_MCP_JSON);
|
|
394
|
+
return {
|
|
395
|
+
kind: "already-wired",
|
|
396
|
+
mutatedPath: COPILOT_MCP_JSON
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
if (opts.dryRun) {
|
|
400
|
+
p.log.info(`[dry-run] Would ${alreadyHas ? "overwrite" : "add"} mcpServers.agentmemory in ${COPILOT_MCP_JSON}`);
|
|
401
|
+
return {
|
|
402
|
+
kind: "installed",
|
|
403
|
+
mutatedPath: COPILOT_MCP_JSON
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
let backupPath;
|
|
407
|
+
if (existsSync(COPILOT_MCP_JSON)) {
|
|
408
|
+
backupPath = backupFile(COPILOT_MCP_JSON, "copilot-cli");
|
|
409
|
+
logBackup(backupPath);
|
|
410
|
+
} else mkdirSync(dirname(COPILOT_MCP_JSON), { recursive: true });
|
|
411
|
+
servers["agentmemory"] = AGENTMEMORY_COPILOT_MCP_BLOCK;
|
|
412
|
+
next.mcpServers = servers;
|
|
413
|
+
writeJsonAtomic(COPILOT_MCP_JSON, next);
|
|
414
|
+
if (!entryMatches(readJsonSafe(COPILOT_MCP_JSON)?.mcpServers?.["agentmemory"])) {
|
|
415
|
+
p.log.error(`Verification failed: ${COPILOT_MCP_JSON} did not contain mcpServers.agentmemory after write.`);
|
|
416
|
+
return {
|
|
417
|
+
kind: "skipped",
|
|
418
|
+
reason: "verification-failed"
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
logInstalled("GitHub Copilot CLI", COPILOT_MCP_JSON);
|
|
422
|
+
p.log.info("Copilot picks up MCP servers on next launch or after `/mcp`. Install the plugin too for full hooks/skills.");
|
|
423
|
+
return {
|
|
424
|
+
kind: "installed",
|
|
425
|
+
mutatedPath: COPILOT_MCP_JSON,
|
|
426
|
+
...backupPath !== void 0 && { backupPath }
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
//#endregion
|
|
432
|
+
//#region src/cli/connect/codex.ts
|
|
433
|
+
const CODEX_DIR = join(homedir(), ".codex");
|
|
434
|
+
const CODEX_TOML = join(CODEX_DIR, "config.toml");
|
|
435
|
+
const CODEX_HOOKS = join(CODEX_DIR, "hooks.json");
|
|
436
|
+
const TOML_BLOCK = `[mcp_servers.agentmemory]
|
|
437
|
+
command = "npx"
|
|
438
|
+
args = ["-y", "@agentmemory/mcp"]
|
|
439
|
+
|
|
440
|
+
[mcp_servers.agentmemory.env]
|
|
441
|
+
AGENTMEMORY_URL = "http://localhost:3111"
|
|
442
|
+
`;
|
|
443
|
+
const SECTION_HEADER = "[mcp_servers.agentmemory]";
|
|
444
|
+
function isWiredText(toml) {
|
|
445
|
+
return toml.includes(SECTION_HEADER);
|
|
446
|
+
}
|
|
447
|
+
function stripExistingBlock(toml) {
|
|
448
|
+
const lines = toml.split(/\r?\n/);
|
|
449
|
+
const out = [];
|
|
450
|
+
let skipping = false;
|
|
451
|
+
for (const line of lines) {
|
|
452
|
+
const trimmed = line.trim();
|
|
453
|
+
if (trimmed === SECTION_HEADER || trimmed === "[mcp_servers.agentmemory.env]") {
|
|
454
|
+
skipping = true;
|
|
455
|
+
continue;
|
|
456
|
+
}
|
|
457
|
+
if (skipping && trimmed.startsWith("[") && trimmed !== "[mcp_servers.agentmemory.env]") skipping = false;
|
|
458
|
+
if (!skipping) out.push(line);
|
|
459
|
+
}
|
|
460
|
+
return out.join("\n").replace(/\n{3,}$/, "\n\n").trimEnd() + "\n";
|
|
461
|
+
}
|
|
462
|
+
const adapter$12 = {
|
|
463
|
+
name: "codex",
|
|
464
|
+
displayName: "Codex CLI",
|
|
465
|
+
docs: "https://github.com/rohitg00/agentmemory#codex-cli-codex-plugin-platform",
|
|
466
|
+
protocolNote: "→ Using MCP. Hooks ship via the Codex plugin; on Codex Desktop, also pass --with-hooks to install the global hooks.json workaround for openai/codex#16430.",
|
|
467
|
+
detect() {
|
|
468
|
+
return existsSync(CODEX_DIR);
|
|
469
|
+
},
|
|
470
|
+
async install(opts) {
|
|
471
|
+
const exists = existsSync(CODEX_TOML);
|
|
472
|
+
const current = exists ? readFileSync(CODEX_TOML, "utf-8") : "";
|
|
473
|
+
const wired = isWiredText(current);
|
|
474
|
+
if (wired && !opts.force) {
|
|
475
|
+
logAlreadyWired("Codex CLI", CODEX_TOML);
|
|
476
|
+
return {
|
|
477
|
+
kind: "already-wired",
|
|
478
|
+
mutatedPath: CODEX_TOML
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
if (opts.dryRun) {
|
|
482
|
+
p.log.info(`[dry-run] Would ${wired ? "rewrite" : "append"} [mcp_servers.agentmemory] in ${CODEX_TOML}`);
|
|
483
|
+
if (opts.withHooks) installCodexHooks(opts);
|
|
484
|
+
return {
|
|
485
|
+
kind: "installed",
|
|
486
|
+
mutatedPath: CODEX_TOML
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
let backupPath;
|
|
490
|
+
if (exists) {
|
|
491
|
+
backupPath = backupFile(CODEX_TOML, "codex", "toml");
|
|
492
|
+
logBackup(backupPath);
|
|
493
|
+
} else mkdirSync(dirname(CODEX_TOML), { recursive: true });
|
|
494
|
+
const cleaned = wired ? stripExistingBlock(current) : current;
|
|
495
|
+
writeFileSync(CODEX_TOML, `${cleaned}${cleaned.length === 0 || cleaned.endsWith("\n") ? "" : "\n"}${cleaned.length > 0 ? "\n" : ""}${TOML_BLOCK}`, "utf-8");
|
|
496
|
+
if (!isWiredText(readFileSync(CODEX_TOML, "utf-8"))) {
|
|
497
|
+
p.log.error(`Verification failed: ${CODEX_TOML} did not contain ${SECTION_HEADER} after write.`);
|
|
498
|
+
return {
|
|
499
|
+
kind: "skipped",
|
|
500
|
+
reason: "verification-failed"
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
logInstalled("Codex CLI", CODEX_TOML);
|
|
504
|
+
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 add agentmemory@agentmemory");
|
|
505
|
+
if (opts.withHooks) {
|
|
506
|
+
const hookResult = installCodexHooks(opts);
|
|
507
|
+
if (hookResult.kind === "skipped") p.log.warn(`Codex hooks fallback skipped: ${hookResult.reason}. MCP wiring still applied.`);
|
|
508
|
+
}
|
|
509
|
+
return {
|
|
510
|
+
kind: "installed",
|
|
511
|
+
mutatedPath: CODEX_TOML,
|
|
512
|
+
...backupPath !== void 0 && { backupPath }
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
};
|
|
516
|
+
/**
|
|
517
|
+
* Install the global `~/.codex/hooks.json` fallback. See
|
|
518
|
+
* `codex-hooks.ts` for context (openai/codex#16430). Returns a result
|
|
519
|
+
* describing the side effect for the caller's summary; failures here do
|
|
520
|
+
* not roll back the MCP wiring.
|
|
521
|
+
*/
|
|
522
|
+
function installCodexHooks(opts) {
|
|
523
|
+
let pluginRoot;
|
|
524
|
+
try {
|
|
525
|
+
pluginRoot = findPluginRoot();
|
|
526
|
+
} catch (err) {
|
|
527
|
+
return {
|
|
528
|
+
kind: "skipped",
|
|
529
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
const existing = readJsonSafe(CODEX_HOOKS);
|
|
533
|
+
const merged = buildMergedHooks(existing, pluginRoot);
|
|
534
|
+
if (opts.dryRun) {
|
|
535
|
+
p.log.info(`[dry-run] Would ${existing ? "merge" : "create"} ${CODEX_HOOKS} with ${Object.keys(merged.hooks).length} event(s)`);
|
|
536
|
+
return {
|
|
537
|
+
kind: "installed",
|
|
538
|
+
mutatedPath: CODEX_HOOKS
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
let backupPath;
|
|
542
|
+
if (existsSync(CODEX_HOOKS)) {
|
|
543
|
+
backupPath = backupFile(CODEX_HOOKS, "codex-hooks", "json");
|
|
544
|
+
logBackup(backupPath);
|
|
545
|
+
}
|
|
546
|
+
writeJsonAtomic(CODEX_HOOKS, merged);
|
|
547
|
+
logInstalled("Codex hooks (workaround for openai/codex#16430)", CODEX_HOOKS);
|
|
548
|
+
p.log.info("User-scope hooks reference absolute paths under the bundled plugin/ dir. Re-run `agentmemory connect codex --with-hooks` after upgrading agentmemory to refresh them.");
|
|
549
|
+
return {
|
|
550
|
+
kind: "installed",
|
|
551
|
+
mutatedPath: CODEX_HOOKS,
|
|
552
|
+
...backupPath !== void 0 && { backupPath }
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
//#endregion
|
|
557
|
+
//#region src/cli/connect/continue.ts
|
|
558
|
+
const CONTINUE_DIR = join(homedir(), ".continue");
|
|
559
|
+
const YAML_PATH = join(CONTINUE_DIR, "config.yaml");
|
|
560
|
+
const JSON_PATH = join(CONTINUE_DIR, "config.json");
|
|
561
|
+
function buildEntry() {
|
|
562
|
+
return {
|
|
563
|
+
name: "agentmemory",
|
|
564
|
+
command: AGENTMEMORY_MCP_BLOCK.command,
|
|
565
|
+
args: [...AGENTMEMORY_MCP_BLOCK.args],
|
|
566
|
+
env: { ...AGENTMEMORY_MCP_BLOCK.env }
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
function entryIsAgentmemory(entry) {
|
|
570
|
+
if (!entry) return false;
|
|
571
|
+
return entry.name === "agentmemory" && entry.args.includes("@agentmemory/mcp");
|
|
572
|
+
}
|
|
573
|
+
function renderFreshYaml() {
|
|
574
|
+
const e = buildEntry();
|
|
575
|
+
const envLines = Object.entries(e.env ?? {}).map(([k, v]) => ` ${k}: "${v}"`).join("\n");
|
|
576
|
+
return [
|
|
577
|
+
"mcpServers:",
|
|
578
|
+
` - name: ${e.name}`,
|
|
579
|
+
` command: ${e.command}`,
|
|
580
|
+
" args:",
|
|
581
|
+
...e.args.map((a) => ` - "${a}"`),
|
|
582
|
+
" env:",
|
|
583
|
+
envLines,
|
|
584
|
+
""
|
|
585
|
+
].join("\n");
|
|
586
|
+
}
|
|
587
|
+
const adapter$11 = {
|
|
588
|
+
name: "continue",
|
|
589
|
+
displayName: "Continue",
|
|
590
|
+
docs: "https://github.com/rohitg00/agentmemory#other-agents",
|
|
591
|
+
protocolNote: "→ Using MCP via ~/.continue/config.yaml (preferred) or config.json (legacy, only when no yaml).",
|
|
592
|
+
detect() {
|
|
593
|
+
return existsSync(CONTINUE_DIR);
|
|
594
|
+
},
|
|
595
|
+
async install(opts) {
|
|
596
|
+
const yamlExists = existsSync(YAML_PATH);
|
|
597
|
+
const jsonExists = existsSync(JSON_PATH);
|
|
598
|
+
if (yamlExists) {
|
|
599
|
+
const manual = `\nMerge this block into ~/.continue/config.yaml (the snippet already includes the top-level mcpServers key — if your config already has a mcpServers list, append the agentmemory entry to it instead of duplicating the key):\n\n${renderFreshYaml().split("\n").map((l) => l ? ` ${l}` : l).join("\n")}`;
|
|
600
|
+
p.log.info(`Continue: ${YAML_PATH} already exists. Manual edit needed.${manual}`);
|
|
601
|
+
return {
|
|
602
|
+
kind: "stub",
|
|
603
|
+
reason: "config.yaml-needs-manual-edit"
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
if (jsonExists) {
|
|
607
|
+
const existing = readJsonSafe(JSON_PATH);
|
|
608
|
+
const next = existing ? { ...existing } : {};
|
|
609
|
+
const servers = Array.isArray(next.mcpServers) ? [...next.mcpServers] : [];
|
|
610
|
+
const idx = servers.findIndex((s) => s?.name === "agentmemory");
|
|
611
|
+
const alreadyHas = idx >= 0 && entryIsAgentmemory(servers[idx]);
|
|
612
|
+
if (alreadyHas && !opts.force) {
|
|
613
|
+
logAlreadyWired("Continue", JSON_PATH);
|
|
614
|
+
return {
|
|
615
|
+
kind: "already-wired",
|
|
616
|
+
mutatedPath: JSON_PATH
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
if (opts.dryRun) {
|
|
620
|
+
p.log.info(`[dry-run] Would ${alreadyHas ? "overwrite" : "add"} mcpServers[agentmemory] in ${JSON_PATH}`);
|
|
621
|
+
return {
|
|
622
|
+
kind: "installed",
|
|
623
|
+
mutatedPath: JSON_PATH
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
const backupPath = backupFile(JSON_PATH, "continue");
|
|
627
|
+
logBackup(backupPath);
|
|
628
|
+
const entry = buildEntry();
|
|
629
|
+
if (idx >= 0) servers[idx] = entry;
|
|
630
|
+
else servers.push(entry);
|
|
631
|
+
next.mcpServers = servers;
|
|
632
|
+
writeJsonAtomic(JSON_PATH, next);
|
|
633
|
+
const verifyEntry = readJsonSafe(JSON_PATH)?.mcpServers?.find((s) => s?.name === "agentmemory");
|
|
634
|
+
if (!entryIsAgentmemory(verifyEntry)) {
|
|
635
|
+
p.log.error(`Verification failed: ${JSON_PATH} did not contain mcpServers[agentmemory] after write.`);
|
|
636
|
+
return {
|
|
637
|
+
kind: "skipped",
|
|
638
|
+
reason: "verification-failed"
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
logInstalled("Continue (legacy config.json)", JSON_PATH);
|
|
642
|
+
return {
|
|
643
|
+
kind: "installed",
|
|
644
|
+
mutatedPath: JSON_PATH,
|
|
645
|
+
backupPath
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
if (opts.dryRun) {
|
|
649
|
+
p.log.info(`[dry-run] Would create ${YAML_PATH} with agentmemory entry`);
|
|
650
|
+
return {
|
|
651
|
+
kind: "installed",
|
|
652
|
+
mutatedPath: YAML_PATH
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
mkdirSync(dirname(YAML_PATH), { recursive: true });
|
|
656
|
+
writeFileSync(YAML_PATH, renderFreshYaml(), "utf-8");
|
|
657
|
+
logInstalled("Continue", YAML_PATH);
|
|
658
|
+
return {
|
|
659
|
+
kind: "installed",
|
|
660
|
+
mutatedPath: YAML_PATH
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
};
|
|
664
|
+
|
|
665
|
+
//#endregion
|
|
666
|
+
//#region src/cli/connect/cursor.ts
|
|
667
|
+
const adapter$10 = createJsonMcpAdapter({
|
|
668
|
+
name: "cursor",
|
|
669
|
+
displayName: "Cursor",
|
|
670
|
+
detectDir: join(homedir(), ".cursor"),
|
|
671
|
+
configPath: join(homedir(), ".cursor", "mcp.json"),
|
|
672
|
+
docs: "https://github.com/rohitg00/agentmemory#other-agents",
|
|
673
|
+
protocolNote: "→ Using MCP (the only protocol Cursor speaks). Memory bridge runs at :3111 underneath."
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
//#endregion
|
|
677
|
+
//#region src/cli/connect/droid.ts
|
|
678
|
+
const adapter$9 = createJsonMcpAdapter({
|
|
679
|
+
name: "droid",
|
|
680
|
+
displayName: "Droid (Factory.ai)",
|
|
681
|
+
detectDir: join(homedir(), ".factory"),
|
|
682
|
+
configPath: join(homedir(), ".factory", "mcp.json"),
|
|
683
|
+
docs: "https://github.com/rohitg00/agentmemory#other-agents",
|
|
684
|
+
protocolNote: "→ Using MCP via ~/.factory/mcp.json. The `/mcp` slash command inside droid lists configured servers.",
|
|
685
|
+
extraEntryFields: { type: "stdio" }
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
//#endregion
|
|
689
|
+
//#region src/cli/connect/gemini-cli.ts
|
|
690
|
+
const adapter$8 = createJsonMcpAdapter({
|
|
691
|
+
name: "gemini-cli",
|
|
692
|
+
displayName: "Gemini CLI",
|
|
693
|
+
detectDir: join(homedir(), ".gemini"),
|
|
694
|
+
configPath: join(homedir(), ".gemini", "settings.json"),
|
|
695
|
+
docs: "https://github.com/rohitg00/agentmemory#other-agents",
|
|
696
|
+
protocolNote: "→ Using MCP (the only protocol Gemini CLI speaks). Memory bridge runs at :3111 underneath."
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
//#endregion
|
|
700
|
+
//#region src/cli/connect/hermes.ts
|
|
701
|
+
const HERMES_DIR = join(homedir(), ".hermes");
|
|
702
|
+
const HERMES_CONFIG = join(HERMES_DIR, "config.yaml");
|
|
703
|
+
const DOCS$2 = "https://github.com/rohitg00/agentmemory/tree/main/integrations/hermes";
|
|
704
|
+
const adapter$7 = {
|
|
705
|
+
name: "hermes",
|
|
706
|
+
displayName: "Hermes Agent",
|
|
707
|
+
docs: DOCS$2,
|
|
708
|
+
protocolNote: "→ Using MCP. Hooks are also available — see docs/hermes.md.",
|
|
709
|
+
detect() {
|
|
710
|
+
return existsSync(HERMES_DIR);
|
|
711
|
+
},
|
|
712
|
+
async install(_opts) {
|
|
713
|
+
p.log.warn("Hermes uses YAML config. Automated merge isn't implemented yet — manual install required.");
|
|
714
|
+
p.note([
|
|
715
|
+
`Add to ${HERMES_CONFIG}:`,
|
|
716
|
+
"",
|
|
717
|
+
" mcp_servers:",
|
|
718
|
+
" agentmemory:",
|
|
719
|
+
" command: npx",
|
|
720
|
+
" args: [\"-y\", \"@agentmemory/mcp\"]",
|
|
721
|
+
"",
|
|
722
|
+
" memory:",
|
|
723
|
+
" provider: agentmemory",
|
|
724
|
+
"",
|
|
725
|
+
`Full guide: ${DOCS$2}`
|
|
726
|
+
].join("\n"), "Hermes manual install");
|
|
727
|
+
return {
|
|
728
|
+
kind: "stub",
|
|
729
|
+
reason: "yaml-merge-not-implemented"
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
//#endregion
|
|
735
|
+
//#region src/cli/connect/kiro.ts
|
|
736
|
+
const adapter$6 = createJsonMcpAdapter({
|
|
737
|
+
name: "kiro",
|
|
738
|
+
displayName: "Kiro",
|
|
739
|
+
detectDir: join(homedir(), ".kiro"),
|
|
740
|
+
configPath: join(homedir(), ".kiro", "settings", "mcp.json"),
|
|
741
|
+
docs: "https://github.com/rohitg00/agentmemory#other-agents",
|
|
742
|
+
protocolNote: "→ Using MCP via ~/.kiro/settings/mcp.json (user-level). Workspace overrides live in .kiro/settings/mcp.json."
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
//#endregion
|
|
746
|
+
//#region src/cli/connect/openclaw.ts
|
|
747
|
+
const adapter$5 = createJsonMcpAdapter({
|
|
748
|
+
name: "openclaw",
|
|
749
|
+
displayName: "OpenClaw",
|
|
750
|
+
detectDir: join(homedir(), ".openclaw"),
|
|
751
|
+
configPath: join(homedir(), ".openclaw", "openclaw.json"),
|
|
752
|
+
docs: "https://github.com/rohitg00/agentmemory/tree/main/integrations/openclaw",
|
|
753
|
+
protocolNote: "→ Using MCP. Hooks are also available — see docs/openclaw.md."
|
|
754
|
+
});
|
|
755
|
+
|
|
756
|
+
//#endregion
|
|
757
|
+
//#region src/cli/connect/openhuman.ts
|
|
758
|
+
const OPENHUMAN_DIR = join(homedir(), ".openhuman");
|
|
759
|
+
const DOCS$1 = "https://github.com/tinyhumansai/openhuman";
|
|
760
|
+
const adapter$4 = {
|
|
761
|
+
name: "openhuman",
|
|
762
|
+
displayName: "OpenHuman",
|
|
763
|
+
docs: DOCS$1,
|
|
764
|
+
protocolNote: "→ Using native hooks (REST API at :3111). MCP not required.",
|
|
765
|
+
detect() {
|
|
766
|
+
return existsSync(OPENHUMAN_DIR);
|
|
767
|
+
},
|
|
768
|
+
async install(_opts) {
|
|
769
|
+
p.log.warn("OpenHuman integration is not yet automated. No `integrations/openhuman/` folder exists in the agentmemory repo today.");
|
|
770
|
+
p.note([
|
|
771
|
+
"OpenHuman is a Memory-trait host. The expected wiring is the REST",
|
|
772
|
+
"proxy at http://localhost:3111 plus an OpenHuman-side Memory trait",
|
|
773
|
+
"impl. Once integrations/openhuman/ lands in agentmemory we'll wire",
|
|
774
|
+
"this up automatically.",
|
|
775
|
+
"",
|
|
776
|
+
`Tracking: ${DOCS$1}`
|
|
777
|
+
].join("\n"), "OpenHuman manual install");
|
|
778
|
+
return {
|
|
779
|
+
kind: "stub",
|
|
780
|
+
reason: "no-integration-folder-yet"
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
};
|
|
784
|
+
|
|
785
|
+
//#endregion
|
|
786
|
+
//#region src/cli/connect/pi.ts
|
|
787
|
+
const PI_DIR = join(homedir(), ".pi");
|
|
788
|
+
const PI_EXT_DIR = join(PI_DIR, "agent", "extensions", "agentmemory");
|
|
789
|
+
const DOCS = "https://github.com/rohitg00/agentmemory/tree/main/integrations/pi";
|
|
790
|
+
const adapter$3 = {
|
|
791
|
+
name: "pi",
|
|
792
|
+
displayName: "pi",
|
|
793
|
+
docs: DOCS,
|
|
794
|
+
protocolNote: "→ Using native hooks (REST API at :3111). MCP not required.",
|
|
795
|
+
detect() {
|
|
796
|
+
return existsSync(PI_DIR);
|
|
797
|
+
},
|
|
798
|
+
async install(_opts) {
|
|
799
|
+
p.log.warn("pi uses a TypeScript extension file. Automated copy + register isn't implemented yet — manual install required.");
|
|
800
|
+
p.note([
|
|
801
|
+
"Run these from the agentmemory repo root:",
|
|
802
|
+
"",
|
|
803
|
+
` mkdir -p ${PI_EXT_DIR}`,
|
|
804
|
+
` cp integrations/pi/index.ts ${PI_EXT_DIR}/index.ts`,
|
|
805
|
+
` cp integrations/pi/security.ts ${PI_EXT_DIR}/security.ts`,
|
|
806
|
+
"",
|
|
807
|
+
"Then add to ~/.pi/agent/settings.json:",
|
|
808
|
+
" { \"extensions\": [\"~/.pi/agent/extensions/agentmemory\"] }",
|
|
809
|
+
"",
|
|
810
|
+
`Full guide: ${DOCS}`
|
|
811
|
+
].join("\n"), "pi manual install");
|
|
812
|
+
return {
|
|
813
|
+
kind: "stub",
|
|
814
|
+
reason: "ts-extension-copy-not-implemented"
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
};
|
|
818
|
+
|
|
819
|
+
//#endregion
|
|
820
|
+
//#region src/cli/connect/qwen.ts
|
|
821
|
+
const adapter$2 = createJsonMcpAdapter({
|
|
822
|
+
name: "qwen",
|
|
823
|
+
displayName: "Qwen Code",
|
|
824
|
+
detectDir: join(homedir(), ".qwen"),
|
|
825
|
+
configPath: join(homedir(), ".qwen", "settings.json"),
|
|
826
|
+
docs: "https://github.com/rohitg00/agentmemory#other-agents",
|
|
827
|
+
protocolNote: "→ Using MCP via ~/.qwen/settings.json. Qwen Code's hook system can also be wired separately — see docs."
|
|
828
|
+
});
|
|
829
|
+
|
|
830
|
+
//#endregion
|
|
831
|
+
//#region src/cli/connect/warp.ts
|
|
832
|
+
const adapter$1 = createJsonMcpAdapter({
|
|
833
|
+
name: "warp",
|
|
834
|
+
displayName: "Warp",
|
|
835
|
+
detectDir: join(homedir(), ".warp"),
|
|
836
|
+
configPath: join(homedir(), ".warp", ".mcp.json"),
|
|
837
|
+
docs: "https://github.com/rohitg00/agentmemory#other-agents",
|
|
838
|
+
protocolNote: "→ Using MCP via ~/.warp/.mcp.json. Skills auto-discover from .claude/skills/ if the Claude Code plugin is also installed."
|
|
839
|
+
});
|
|
840
|
+
|
|
841
|
+
//#endregion
|
|
842
|
+
//#region src/cli/connect/zed.ts
|
|
843
|
+
const zedConfigDir = join(homedir(), ".config", "zed");
|
|
844
|
+
const adapter = createJsonMcpAdapter({
|
|
845
|
+
name: "zed",
|
|
846
|
+
displayName: "Zed",
|
|
847
|
+
detectDir: zedConfigDir,
|
|
848
|
+
configPath: join(zedConfigDir, "settings.json"),
|
|
849
|
+
wrapperKey: "context_servers",
|
|
850
|
+
docs: "https://github.com/rohitg00/agentmemory#other-agents",
|
|
851
|
+
protocolNote: "→ Using MCP via ~/.config/zed/settings.json (key: context_servers)."
|
|
852
|
+
});
|
|
853
|
+
|
|
854
|
+
//#endregion
|
|
855
|
+
//#region src/cli/connect/index.ts
|
|
856
|
+
var connect_exports = /* @__PURE__ */ __exportAll({
|
|
857
|
+
ADAPTERS: () => ADAPTERS,
|
|
858
|
+
knownAgents: () => knownAgents,
|
|
859
|
+
resolveAdapter: () => resolveAdapter,
|
|
860
|
+
runAdapter: () => runAdapter,
|
|
861
|
+
runConnect: () => runConnect
|
|
862
|
+
});
|
|
863
|
+
const ADAPTERS = [
|
|
864
|
+
adapter$15,
|
|
865
|
+
adapter$13,
|
|
866
|
+
adapter$12,
|
|
867
|
+
adapter$10,
|
|
868
|
+
adapter$8,
|
|
869
|
+
adapter$2,
|
|
870
|
+
adapter$16,
|
|
871
|
+
adapter$6,
|
|
872
|
+
adapter$1,
|
|
873
|
+
adapter$14,
|
|
874
|
+
adapter$11,
|
|
875
|
+
adapter,
|
|
876
|
+
adapter$9,
|
|
877
|
+
adapter$5,
|
|
878
|
+
adapter$7,
|
|
879
|
+
adapter$3,
|
|
880
|
+
adapter$4
|
|
881
|
+
];
|
|
882
|
+
function resolveAdapter(name) {
|
|
883
|
+
const lower = name.toLowerCase();
|
|
884
|
+
return ADAPTERS.find((a) => a.name === lower) ?? null;
|
|
885
|
+
}
|
|
886
|
+
function knownAgents() {
|
|
887
|
+
return ADAPTERS.map((a) => a.name);
|
|
888
|
+
}
|
|
889
|
+
function parseFlags(args) {
|
|
890
|
+
const positional = [];
|
|
891
|
+
let dryRun = false;
|
|
892
|
+
let force = false;
|
|
893
|
+
let all = false;
|
|
894
|
+
let withHooks = false;
|
|
895
|
+
for (const a of args) if (a === "--dry-run") dryRun = true;
|
|
896
|
+
else if (a === "--force") force = true;
|
|
897
|
+
else if (a === "--all") all = true;
|
|
898
|
+
else if (a === "--with-hooks") withHooks = true;
|
|
899
|
+
else if (!a.startsWith("-")) positional.push(a);
|
|
900
|
+
return {
|
|
901
|
+
dryRun,
|
|
902
|
+
force,
|
|
903
|
+
all,
|
|
904
|
+
withHooks,
|
|
905
|
+
positional
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
async function runAdapter(adapter, opts) {
|
|
909
|
+
if (!adapter.detect()) {
|
|
910
|
+
p.log.warn(`${adapter.displayName}: not detected on this machine (skipping).${adapter.docs ? ` Docs: ${adapter.docs}` : ""}`);
|
|
911
|
+
return {
|
|
912
|
+
kind: "skipped",
|
|
913
|
+
reason: "not-detected"
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
p.log.step(`Wiring ${adapter.displayName}…`);
|
|
917
|
+
if (adapter.protocolNote) p.log.message(adapter.protocolNote);
|
|
918
|
+
try {
|
|
919
|
+
return await adapter.install(opts);
|
|
920
|
+
} catch (err) {
|
|
921
|
+
p.log.error(`${adapter.displayName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
922
|
+
return {
|
|
923
|
+
kind: "skipped",
|
|
924
|
+
reason: "exception"
|
|
925
|
+
};
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
async function runConnect(args) {
|
|
929
|
+
const { dryRun, force, all, withHooks, positional } = parseFlags(args);
|
|
930
|
+
const allowWindowsAdapter = positional.length === 1 && positional[0]?.toLowerCase() === "copilot-cli";
|
|
931
|
+
if (platform() === "win32" && !allowWindowsAdapter) {
|
|
932
|
+
p.intro("agentmemory connect");
|
|
933
|
+
p.log.warn("Windows: automated `connect` is not supported yet. See https://github.com/rohitg00/agentmemory#other-agents for manual install steps.");
|
|
934
|
+
p.outro("Windows: manual install required — see docs");
|
|
935
|
+
return;
|
|
936
|
+
}
|
|
937
|
+
const opts = {
|
|
938
|
+
dryRun,
|
|
939
|
+
force,
|
|
940
|
+
withHooks
|
|
941
|
+
};
|
|
942
|
+
p.intro("agentmemory connect");
|
|
943
|
+
if (positional.length === 0 && !all) {
|
|
944
|
+
const detected = ADAPTERS.filter((a) => a.detect());
|
|
945
|
+
if (detected.length === 0) {
|
|
946
|
+
p.log.error("No supported agents detected on this machine.");
|
|
947
|
+
p.outro(`Supported: ${knownAgents().join(", ")}`);
|
|
948
|
+
process.exit(1);
|
|
949
|
+
}
|
|
950
|
+
const picked = await p.multiselect({
|
|
951
|
+
message: "Wire agentmemory into which agents?",
|
|
952
|
+
options: detected.map((a) => ({
|
|
953
|
+
value: a.name,
|
|
954
|
+
label: a.displayName
|
|
955
|
+
})),
|
|
956
|
+
required: true
|
|
957
|
+
});
|
|
958
|
+
if (p.isCancel(picked)) {
|
|
959
|
+
p.cancel("Cancelled.");
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
const results = [];
|
|
963
|
+
for (const name of picked) {
|
|
964
|
+
const adapter = resolveAdapter(name);
|
|
965
|
+
if (!adapter) continue;
|
|
966
|
+
results.push({
|
|
967
|
+
name,
|
|
968
|
+
result: await runAdapter(adapter, opts)
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
summarize(results);
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
if (all) {
|
|
975
|
+
const detected = ADAPTERS.filter((a) => a.detect());
|
|
976
|
+
if (detected.length === 0) {
|
|
977
|
+
p.log.error("No supported agents detected on this machine.");
|
|
978
|
+
process.exit(1);
|
|
979
|
+
}
|
|
980
|
+
const results = [];
|
|
981
|
+
for (const adapter of detected) results.push({
|
|
982
|
+
name: adapter.name,
|
|
983
|
+
result: await runAdapter(adapter, opts)
|
|
984
|
+
});
|
|
985
|
+
summarize(results);
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
988
|
+
const agentName = positional[0];
|
|
989
|
+
const adapter = resolveAdapter(agentName);
|
|
990
|
+
if (!adapter) {
|
|
991
|
+
p.log.error(`Unknown agent: ${agentName}`);
|
|
992
|
+
p.outro(`Supported: ${knownAgents().join(", ")}`);
|
|
993
|
+
process.exit(1);
|
|
994
|
+
}
|
|
995
|
+
const result = await runAdapter(adapter, opts);
|
|
996
|
+
summarize([{
|
|
997
|
+
name: agentName,
|
|
998
|
+
result
|
|
999
|
+
}]);
|
|
1000
|
+
if (result.kind === "skipped" && result.reason !== "not-detected") process.exit(1);
|
|
1001
|
+
}
|
|
1002
|
+
function summarize(results) {
|
|
1003
|
+
const lines = results.map(({ name, result }) => {
|
|
1004
|
+
switch (result.kind) {
|
|
1005
|
+
case "installed": return ` ✓ ${name}${result.mutatedPath ? ` → ${result.mutatedPath}` : ""}`;
|
|
1006
|
+
case "already-wired": return ` ✓ ${name} (already wired)`;
|
|
1007
|
+
case "stub": return ` ⚠ ${name} (manual install required: ${result.reason})`;
|
|
1008
|
+
case "skipped": return ` ✗ ${name} (skipped: ${result.reason})`;
|
|
1009
|
+
}
|
|
1010
|
+
});
|
|
1011
|
+
p.note(lines.join("\n"), "summary");
|
|
1012
|
+
const stubs = results.filter((r) => r.result.kind === "stub");
|
|
1013
|
+
if (stubs.length > 0) p.log.info(`${stubs.length} agent(s) require manual install — see docs links above.`);
|
|
1014
|
+
if (results.some((r) => r.result.kind === "installed" || r.result.kind === "already-wired")) p.log.info("Next: install agentmemory's 8 skills into the same agent(s) so they know when to call the tools:\n npx skills add rohitg00/agentmemory -y");
|
|
1015
|
+
p.outro("Restart any wired agent (or open a new session) to pick up agentmemory.");
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
//#endregion
|
|
1019
|
+
export { resolveAdapter as n, runAdapter as r, connect_exports as t };
|
|
1020
|
+
//# sourceMappingURL=connect-Cf9bmBqO.mjs.map
|