@agentmemory/agentmemory 0.9.28 → 0.9.30
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/.env.example +98 -28
- package/AGENTS.md +19 -26
- package/README.md +619 -274
- package/dist/.env.example +98 -28
- package/dist/cli.d.mts.map +1 -1
- package/dist/cli.mjs +1328 -244
- package/dist/cli.mjs.map +1 -1
- package/dist/{connect-JnsJXc68.mjs → connect-B4_ca6BD.mjs} +619 -70
- package/dist/connect-B4_ca6BD.mjs.map +1 -0
- package/dist/docker-compose.yml +42 -16
- package/dist/hooks/_capture.d.mts +22 -0
- package/dist/hooks/_capture.d.mts.map +1 -0
- package/dist/hooks/_capture.mjs +908 -0
- package/dist/hooks/_capture.mjs.map +1 -0
- package/dist/hooks/antigravity-bridge.d.mts +8 -0
- package/dist/hooks/antigravity-bridge.d.mts.map +1 -0
- package/dist/hooks/antigravity-bridge.mjs +123 -0
- package/dist/hooks/antigravity-bridge.mjs.map +1 -0
- package/dist/hooks/notification.mjs +34 -27
- package/dist/hooks/notification.mjs.map +1 -1
- package/dist/hooks/post-commit.mjs +84 -2
- package/dist/hooks/post-commit.mjs.map +1 -1
- package/dist/hooks/post-tool-failure.mjs +71 -26
- package/dist/hooks/post-tool-failure.mjs.map +1 -1
- package/dist/hooks/post-tool-use.mjs +99 -36
- package/dist/hooks/post-tool-use.mjs.map +1 -1
- package/dist/hooks/pre-compact.mjs +95 -5
- package/dist/hooks/pre-compact.mjs.map +1 -1
- package/dist/hooks/pre-tool-use.mjs +72 -2
- package/dist/hooks/pre-tool-use.mjs.map +1 -1
- package/dist/hooks/prompt-submit.mjs +25 -22
- package/dist/hooks/prompt-submit.mjs.map +1 -1
- package/dist/hooks/session-end.mjs +93 -24
- package/dist/hooks/session-end.mjs.map +1 -1
- package/dist/hooks/session-start.mjs +101 -6
- package/dist/hooks/session-start.mjs.map +1 -1
- package/dist/hooks/stop.mjs +72 -8
- package/dist/hooks/stop.mjs.map +1 -1
- package/dist/hooks/subagent-start.mjs +28 -26
- package/dist/hooks/subagent-start.mjs.map +1 -1
- package/dist/hooks/subagent-stop.mjs +29 -26
- package/dist/hooks/subagent-stop.mjs.map +1 -1
- package/dist/hooks/task-completed.mjs +31 -28
- package/dist/hooks/task-completed.mjs.map +1 -1
- package/dist/iii-config.docker.yaml +10 -10
- package/dist/iii-config.yaml +3 -1
- package/dist/{image-refs-BKLmp_sD.mjs → image-refs-BaT-9oMU.mjs} +2 -2
- package/dist/image-refs-BaT-9oMU.mjs.map +1 -0
- package/dist/{image-refs-C2YU7BIm.mjs → image-refs-T_urbwHM.mjs} +3 -3
- package/dist/image-refs-T_urbwHM.mjs.map +1 -0
- package/dist/{keyed-mutex-DTHtcZrt.mjs → image-store-BsN4vyjr.mjs} +2 -14
- package/dist/image-store-BsN4vyjr.mjs.map +1 -0
- package/dist/index.mjs +14021 -6494
- package/dist/index.mjs.map +1 -1
- package/dist/keyed-mutex-DchXsyfP.mjs +221 -0
- package/dist/keyed-mutex-DchXsyfP.mjs.map +1 -0
- package/dist/secret-store-BnY3A50C.mjs +2348 -0
- package/dist/secret-store-BnY3A50C.mjs.map +1 -0
- package/dist/{src-CzgoepGU.mjs → src-Jsq9LCeH.mjs} +7349 -2940
- package/dist/src-Jsq9LCeH.mjs.map +1 -0
- package/dist/{standalone-YsZFFQBM.mjs → standalone-DKCdrf1d.mjs} +62 -24
- package/dist/standalone-DKCdrf1d.mjs.map +1 -0
- package/dist/standalone.d.mts.map +1 -1
- package/dist/standalone.mjs +298 -27
- package/dist/standalone.mjs.map +1 -1
- package/dist/status-IRz7ta8-.mjs +2344 -0
- package/dist/status-IRz7ta8-.mjs.map +1 -0
- package/dist/viewer/favicon.svg +35 -1
- package/dist/viewer/index.html +7428 -2608
- package/docker-compose.yml +42 -16
- package/iii-config.docker.yaml +10 -10
- package/iii-config.yaml +3 -1
- package/integrations/pi/README.md +77 -0
- package/integrations/pi/index.ts +402 -0
- package/integrations/pi/package.json +32 -0
- package/integrations/pi/security.ts +87 -0
- package/package.json +15 -7
- package/plugin/.claude-plugin/plugin.json +2 -2
- package/plugin/.codex-plugin/plugin.json +26 -4
- package/plugin/.devin-plugin/plugin.json +32 -0
- package/plugin/.mcp.codex.json +12 -0
- package/plugin/.mcp.copilot.json +2 -7
- package/plugin/.mcp.json +2 -7
- package/plugin/assets/icon.svg +35 -0
- package/plugin/cursor/hooks.json +41 -0
- package/plugin/cursor/mcp.json +12 -0
- package/plugin/hooks/hooks.antigravity.json +43 -0
- package/plugin/hooks/hooks.copilot.json +11 -11
- package/plugin/hooks/hooks.devin.json +67 -0
- package/plugin/hooks/hooks.droid.json +55 -0
- package/plugin/opencode/README.md +267 -31
- package/plugin/opencode/agentmemory-capture.ts +644 -15
- package/plugin/opencode/plugin.json +1 -1
- package/plugin/plugin.json +2 -2
- package/plugin/scripts/_capture.d.mts +22 -0
- package/plugin/scripts/_capture.d.mts.map +1 -0
- package/plugin/scripts/_capture.mjs +908 -0
- package/plugin/scripts/_capture.mjs.map +1 -0
- package/plugin/scripts/antigravity-bridge.d.mts +8 -0
- package/plugin/scripts/antigravity-bridge.d.mts.map +1 -0
- package/plugin/scripts/antigravity-bridge.mjs +123 -0
- package/plugin/scripts/antigravity-bridge.mjs.map +1 -0
- package/plugin/scripts/notification.mjs +34 -27
- package/plugin/scripts/notification.mjs.map +1 -1
- package/plugin/scripts/plugin-bridge.mjs +378 -0
- package/plugin/scripts/post-commit.mjs +84 -2
- package/plugin/scripts/post-commit.mjs.map +1 -1
- package/plugin/scripts/post-tool-failure.mjs +71 -26
- package/plugin/scripts/post-tool-failure.mjs.map +1 -1
- package/plugin/scripts/post-tool-use.mjs +99 -36
- package/plugin/scripts/post-tool-use.mjs.map +1 -1
- package/plugin/scripts/pre-compact.mjs +95 -5
- package/plugin/scripts/pre-compact.mjs.map +1 -1
- package/plugin/scripts/pre-tool-use.mjs +72 -2
- package/plugin/scripts/pre-tool-use.mjs.map +1 -1
- package/plugin/scripts/prompt-submit.mjs +25 -22
- package/plugin/scripts/prompt-submit.mjs.map +1 -1
- package/plugin/scripts/session-end.mjs +93 -24
- package/plugin/scripts/session-end.mjs.map +1 -1
- package/plugin/scripts/session-start.mjs +101 -6
- package/plugin/scripts/session-start.mjs.map +1 -1
- package/plugin/scripts/stop.mjs +72 -8
- package/plugin/scripts/stop.mjs.map +1 -1
- package/plugin/scripts/subagent-start.mjs +28 -26
- package/plugin/scripts/subagent-start.mjs.map +1 -1
- package/plugin/scripts/subagent-stop.mjs +29 -26
- package/plugin/scripts/subagent-stop.mjs.map +1 -1
- package/plugin/scripts/task-completed.mjs +31 -28
- package/plugin/scripts/task-completed.mjs.map +1 -1
- package/plugin/skills/_shared/TROUBLESHOOTING.md +22 -6
- package/plugin/skills/agentmemory-agents/REFERENCE.md +8 -5
- package/plugin/skills/agentmemory-config/REFERENCE.md +52 -1
- package/plugin/skills/agentmemory-config/SKILL.md +44 -7
- package/plugin/skills/agentmemory-mcp-tools/REFERENCE.md +4 -3
- package/plugin/skills/agentmemory-rest-api/REFERENCE.md +23 -2
- package/plugin/skills/forget/SKILL.md +4 -1
- package/plugin/skills/handoff/SKILL.md +4 -2
- package/plugin/skills/lesson/SKILL.md +64 -0
- package/plugin/skills/memory-discipline/SKILL.md +65 -0
- package/plugin/skills/recall/SKILL.md +4 -1
- package/plugin/skills/remember/SKILL.md +6 -1
- package/dist/config-ChC9EtgV.mjs +0 -259
- package/dist/config-ChC9EtgV.mjs.map +0 -1
- package/dist/connect-JnsJXc68.mjs.map +0 -1
- package/dist/image-refs-BKLmp_sD.mjs.map +0 -1
- package/dist/image-refs-C2YU7BIm.mjs.map +0 -1
- package/dist/keyed-mutex-DTHtcZrt.mjs.map +0 -1
- package/dist/logger-BEB7pCI9.mjs +0 -43
- package/dist/logger-BEB7pCI9.mjs.map +0 -1
- package/dist/schema-CNiCWzV9.mjs +0 -78
- package/dist/schema-CNiCWzV9.mjs.map +0 -1
- package/dist/src-CzgoepGU.mjs.map +0 -1
- package/dist/standalone-YsZFFQBM.mjs.map +0 -1
- package/dist/tools-registry-D3NEoe5m.mjs +0 -1115
- package/dist/tools-registry-D3NEoe5m.mjs.map +0 -1
- package/plugin/scripts/diagnostics.d.mts +0 -17
- package/plugin/scripts/diagnostics.d.mts.map +0 -1
- package/plugin/scripts/diagnostics.mjs.map +0 -1
|
@@ -17,6 +17,147 @@ var __exportAll = (all, no_symbols) => {
|
|
|
17
17
|
return target;
|
|
18
18
|
};
|
|
19
19
|
//#endregion
|
|
20
|
+
//#region src/cli/connect/guidelines.ts
|
|
21
|
+
const START = "<!-- agentmemory:start -->";
|
|
22
|
+
const END = "<!-- agentmemory:end -->";
|
|
23
|
+
const GUIDELINE_BODY = `## Agent memory (agentmemory)
|
|
24
|
+
|
|
25
|
+
You have persistent long-term memory via the agentmemory MCP server. Tools: \`memory_recall\`, \`memory_smart_search\`, \`memory_save\`, \`memory_sessions\`.
|
|
26
|
+
|
|
27
|
+
- At the START of a task, call \`memory_recall\` (or \`memory_smart_search\`) with the task context to load relevant past decisions, fixes, and preferences before asking the user to repeat anything.
|
|
28
|
+
- When you learn something durable (a decision, a fix, a gotcha, a user preference, a project convention), call \`memory_save\` to persist it.
|
|
29
|
+
- Prefer recalling over re-deriving, and save concise reusable facts rather than transcripts.`;
|
|
30
|
+
function guidelineTargets(home = homedir()) {
|
|
31
|
+
return {
|
|
32
|
+
cursor: {
|
|
33
|
+
projectPath: join(".cursor", "rules", "agentmemory.mdc"),
|
|
34
|
+
format: "mdc",
|
|
35
|
+
scope: "project",
|
|
36
|
+
source: "https://cursor.com/docs/rules"
|
|
37
|
+
},
|
|
38
|
+
cline: {
|
|
39
|
+
projectPath: join(".clinerules", "agentmemory.md"),
|
|
40
|
+
format: "rule",
|
|
41
|
+
scope: "project",
|
|
42
|
+
source: "https://docs.cline.bot/customization/cline-rules"
|
|
43
|
+
},
|
|
44
|
+
continue: {
|
|
45
|
+
projectPath: join(".continue", "rules", "00-agentmemory.md"),
|
|
46
|
+
format: "rule",
|
|
47
|
+
scope: "project",
|
|
48
|
+
source: "https://docs.continue.dev/customize/deep-dives/rules"
|
|
49
|
+
},
|
|
50
|
+
zed: {
|
|
51
|
+
globalPath: join(home, ".config", "zed", "AGENTS.md"),
|
|
52
|
+
projectPath: "AGENTS.md",
|
|
53
|
+
format: "block",
|
|
54
|
+
scope: "global",
|
|
55
|
+
source: "https://zed.dev/docs/ai/instructions"
|
|
56
|
+
},
|
|
57
|
+
warp: {
|
|
58
|
+
projectPath: "AGENTS.md",
|
|
59
|
+
format: "block",
|
|
60
|
+
scope: "project",
|
|
61
|
+
source: "https://docs.warp.dev/agent-platform/capabilities/rules"
|
|
62
|
+
},
|
|
63
|
+
kiro: {
|
|
64
|
+
globalPath: join(home, ".kiro", "steering", "agentmemory.md"),
|
|
65
|
+
projectPath: join(".kiro", "steering", "agentmemory.md"),
|
|
66
|
+
format: "steering",
|
|
67
|
+
scope: "global",
|
|
68
|
+
source: "https://kiro.dev/docs/steering"
|
|
69
|
+
},
|
|
70
|
+
"gemini-cli": {
|
|
71
|
+
globalPath: join(home, ".gemini", "GEMINI.md"),
|
|
72
|
+
projectPath: "GEMINI.md",
|
|
73
|
+
format: "block",
|
|
74
|
+
scope: "global",
|
|
75
|
+
source: "https://github.com/google-gemini/gemini-cli/blob/main/docs/cli/gemini-md.md"
|
|
76
|
+
},
|
|
77
|
+
qwen: {
|
|
78
|
+
globalPath: join(home, ".qwen", "QWEN.md"),
|
|
79
|
+
projectPath: "QWEN.md",
|
|
80
|
+
format: "block",
|
|
81
|
+
scope: "global",
|
|
82
|
+
source: "https://github.com/QwenLM/qwen-code/blob/main/docs/users/features/memory.md"
|
|
83
|
+
},
|
|
84
|
+
opencode: {
|
|
85
|
+
globalPath: join(home, ".config", "opencode", "AGENTS.md"),
|
|
86
|
+
projectPath: "AGENTS.md",
|
|
87
|
+
format: "block",
|
|
88
|
+
scope: "global",
|
|
89
|
+
source: "https://opencode.ai/docs/rules"
|
|
90
|
+
},
|
|
91
|
+
droid: {
|
|
92
|
+
globalPath: join(home, ".factory", "AGENTS.md"),
|
|
93
|
+
projectPath: "AGENTS.md",
|
|
94
|
+
format: "block",
|
|
95
|
+
scope: "global",
|
|
96
|
+
source: "https://docs.factory.ai/cli/configuration/agents-md"
|
|
97
|
+
},
|
|
98
|
+
antigravity: {
|
|
99
|
+
globalPath: join(home, ".gemini", "GEMINI.md"),
|
|
100
|
+
projectPath: join(".agents", "rules", "agentmemory.md"),
|
|
101
|
+
format: "block",
|
|
102
|
+
scope: "global",
|
|
103
|
+
source: "https://antigravity.google/docs/rules-workflows"
|
|
104
|
+
},
|
|
105
|
+
"antigravity-cli": {
|
|
106
|
+
globalPath: join(home, ".gemini", "GEMINI.md"),
|
|
107
|
+
projectPath: join(".agents", "rules", "agentmemory.md"),
|
|
108
|
+
format: "block",
|
|
109
|
+
scope: "global",
|
|
110
|
+
source: "https://antigravity.google/docs/rules-workflows"
|
|
111
|
+
},
|
|
112
|
+
"copilot-cli": {
|
|
113
|
+
globalPath: join(home, ".copilot", "copilot-instructions.md"),
|
|
114
|
+
projectPath: join(".github", "copilot-instructions.md"),
|
|
115
|
+
format: "block",
|
|
116
|
+
scope: "global",
|
|
117
|
+
source: "https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-custom-instructions"
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function renderDedicated(format) {
|
|
122
|
+
if (format === "mdc") return `---\ndescription: agentmemory long-term memory usage\nalwaysApply: true\n---\n\n${GUIDELINE_BODY}\n`;
|
|
123
|
+
if (format === "steering") return `---\ninclusion: always\n---\n\n${GUIDELINE_BODY}\n`;
|
|
124
|
+
return `${GUIDELINE_BODY}\n`;
|
|
125
|
+
}
|
|
126
|
+
function upsertBlock(existing) {
|
|
127
|
+
const block = `${START}\n${GUIDELINE_BODY}\n${END}`;
|
|
128
|
+
const startIdx = existing.indexOf(START);
|
|
129
|
+
const endIdx = existing.indexOf(END);
|
|
130
|
+
if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) return existing.slice(0, startIdx) + block + existing.slice(endIdx + 24);
|
|
131
|
+
if (startIdx !== -1 || endIdx !== -1) return existing;
|
|
132
|
+
return `${existing}${existing.length === 0 || existing.endsWith("\n") ? "" : "\n"}${existing.length === 0 ? "" : "\n"}${block}\n`;
|
|
133
|
+
}
|
|
134
|
+
function writeGuideline(agentName, opts = { cwd: process.cwd() }) {
|
|
135
|
+
const target = guidelineTargets(opts.home ?? homedir())[agentName];
|
|
136
|
+
if (!target) return { kind: "no-target" };
|
|
137
|
+
const path = target.globalPath ?? join(opts.cwd, target.projectPath);
|
|
138
|
+
const dedicated = target.format !== "block";
|
|
139
|
+
const existing = existsSync(path) ? readFileSync(path, "utf8") : "";
|
|
140
|
+
const next = dedicated ? renderDedicated(target.format) : upsertBlock(existing);
|
|
141
|
+
if (existing === next) return {
|
|
142
|
+
kind: "unchanged",
|
|
143
|
+
path,
|
|
144
|
+
scope: target.scope
|
|
145
|
+
};
|
|
146
|
+
if (opts.dryRun) return {
|
|
147
|
+
kind: "would-write",
|
|
148
|
+
path,
|
|
149
|
+
scope: target.scope
|
|
150
|
+
};
|
|
151
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
152
|
+
writeFileSync(path, next, "utf8");
|
|
153
|
+
return {
|
|
154
|
+
kind: "written",
|
|
155
|
+
path,
|
|
156
|
+
scope: target.scope,
|
|
157
|
+
source: target.source
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
//#endregion
|
|
20
161
|
//#region src/cli/connect/util.ts
|
|
21
162
|
const AGENTMEMORY_MCP_BLOCK = {
|
|
22
163
|
command: "npx",
|
|
@@ -77,9 +218,12 @@ function readJsonSafe(path) {
|
|
|
77
218
|
}
|
|
78
219
|
}
|
|
79
220
|
function writeJsonAtomic(path, value) {
|
|
221
|
+
writeTextAtomic(path, `${JSON.stringify(value, null, 2)}\n`);
|
|
222
|
+
}
|
|
223
|
+
function writeTextAtomic(path, content) {
|
|
80
224
|
mkdirSync(dirname(path), { recursive: true });
|
|
81
225
|
const tmp = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
82
|
-
writeFileSync(tmp,
|
|
226
|
+
writeFileSync(tmp, content, "utf-8");
|
|
83
227
|
renameSync(tmp, path);
|
|
84
228
|
}
|
|
85
229
|
function logInstalled(label, target) {
|
|
@@ -117,6 +261,10 @@ function createJsonMcpAdapter(config) {
|
|
|
117
261
|
const alreadyHas = entryMatches$3(servers["agentmemory"]);
|
|
118
262
|
if (alreadyHas && !opts.force) {
|
|
119
263
|
logAlreadyWired(config.displayName, config.configPath);
|
|
264
|
+
if (opts.withHooks && config.installHooks) {
|
|
265
|
+
const hookResult = config.installHooks(opts);
|
|
266
|
+
if (hookResult.kind === "skipped") p.log.warn(`${config.displayName} hooks skipped: ${hookResult.reason}.`);
|
|
267
|
+
}
|
|
120
268
|
return {
|
|
121
269
|
kind: "already-wired",
|
|
122
270
|
mutatedPath: config.configPath
|
|
@@ -124,6 +272,10 @@ function createJsonMcpAdapter(config) {
|
|
|
124
272
|
}
|
|
125
273
|
if (opts.dryRun) {
|
|
126
274
|
p.log.info(`[dry-run] Would ${alreadyHas ? "overwrite" : "add"} ${wrapperKey}.agentmemory in ${config.configPath}`);
|
|
275
|
+
if (opts.withHooks && config.installHooks) {
|
|
276
|
+
const hookResult = config.installHooks(opts);
|
|
277
|
+
if (hookResult.kind === "skipped") p.log.warn(`${config.displayName} hooks skipped: ${hookResult.reason}.`);
|
|
278
|
+
}
|
|
127
279
|
return {
|
|
128
280
|
kind: "installed",
|
|
129
281
|
mutatedPath: config.configPath
|
|
@@ -149,6 +301,10 @@ function createJsonMcpAdapter(config) {
|
|
|
149
301
|
};
|
|
150
302
|
}
|
|
151
303
|
logInstalled(config.displayName, config.configPath);
|
|
304
|
+
if (opts.withHooks && config.installHooks) {
|
|
305
|
+
const hookResult = config.installHooks(opts);
|
|
306
|
+
if (hookResult.kind === "skipped") p.log.warn(`${config.displayName} hooks skipped: ${hookResult.reason}. MCP wiring still applied.`);
|
|
307
|
+
}
|
|
152
308
|
return {
|
|
153
309
|
kind: "installed",
|
|
154
310
|
mutatedPath: config.configPath,
|
|
@@ -158,16 +314,83 @@ function createJsonMcpAdapter(config) {
|
|
|
158
314
|
};
|
|
159
315
|
}
|
|
160
316
|
//#endregion
|
|
161
|
-
//#region src/cli/connect/antigravity.ts
|
|
162
|
-
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
317
|
+
//#region src/cli/connect/antigravity-hooks.ts
|
|
318
|
+
/** Tool events: `[ { matcher, hooks: [...] } ]`. */
|
|
319
|
+
const TOOL_EVENT_KEYS = new Set(["PreToolUse", "PostToolUse"]);
|
|
320
|
+
/** Lifecycle events: a flat `[ { type, command } ]` handler list. */
|
|
321
|
+
const LIFECYCLE_EVENT_KEYS = new Set([
|
|
322
|
+
"PreInvocation",
|
|
323
|
+
"PostInvocation",
|
|
324
|
+
"Stop"
|
|
325
|
+
]);
|
|
326
|
+
/** Events Antigravity dispatches. Anything else in a bundle is metadata. */
|
|
327
|
+
const EVENT_KEYS = new Set([...TOOL_EVENT_KEYS, ...LIFECYCLE_EVENT_KEYS]);
|
|
328
|
+
function buildMergedAntigravityHooks(existing, pluginRoot, manifestFile = "hooks.antigravity.json") {
|
|
329
|
+
const ours = JSON.parse(readFileSync(join(pluginRoot, "hooks", manifestFile), "utf-8"));
|
|
330
|
+
const scriptsDir = join(pluginRoot, "scripts");
|
|
331
|
+
const out = {};
|
|
332
|
+
for (const [name, bundle] of Object.entries(existing ?? {})) {
|
|
333
|
+
if (isAgentmemoryBundle(bundle, scriptsDir)) continue;
|
|
334
|
+
out[name] = bundle;
|
|
335
|
+
}
|
|
336
|
+
for (const [name, bundle] of Object.entries(ours)) out[name] = resolveBundle(bundle, pluginRoot);
|
|
337
|
+
return out;
|
|
338
|
+
}
|
|
339
|
+
/** True when `pluginRoot` cannot be expressed in an Antigravity `command`. */
|
|
340
|
+
function containsSpaces(pluginRoot) {
|
|
341
|
+
return /\s/.test(pluginRoot);
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Every handler in a bundle, across both event shapes: an entry that carries
|
|
345
|
+
* no `hooks` array is itself the handler.
|
|
346
|
+
*/
|
|
347
|
+
function allHandlers(bundle) {
|
|
348
|
+
const out = [];
|
|
349
|
+
for (const [key, value] of Object.entries(bundle)) {
|
|
350
|
+
if (!EVENT_KEYS.has(key) || !Array.isArray(value)) continue;
|
|
351
|
+
for (const entry of value) {
|
|
352
|
+
if (!entry || typeof entry !== "object") continue;
|
|
353
|
+
const nested = entry.hooks;
|
|
354
|
+
if (Array.isArray(nested)) out.push(...nested);
|
|
355
|
+
else out.push(entry);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return out;
|
|
359
|
+
}
|
|
360
|
+
function isAgentmemoryBundle(bundle, scriptsDir) {
|
|
361
|
+
if (!bundle || typeof bundle !== "object" || Array.isArray(bundle)) return false;
|
|
362
|
+
const normalizedScriptsDir = normalizePathForCommandMatch$1(scriptsDir);
|
|
363
|
+
return allHandlers(bundle).some((handler) => normalizePathForCommandMatch$1(handler?.command ?? "").includes(normalizedScriptsDir));
|
|
364
|
+
}
|
|
365
|
+
function resolveBundle(bundle, pluginRoot) {
|
|
366
|
+
const out = {};
|
|
367
|
+
for (const [key, value] of Object.entries(bundle)) {
|
|
368
|
+
if (!EVENT_KEYS.has(key) || !Array.isArray(value)) {
|
|
369
|
+
out[key] = value;
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
if (LIFECYCLE_EVENT_KEYS.has(key)) {
|
|
373
|
+
out[key] = value.map((handler) => resolveHandler(handler, pluginRoot));
|
|
374
|
+
continue;
|
|
375
|
+
}
|
|
376
|
+
out[key] = value.map((entry) => {
|
|
377
|
+
const next = { hooks: entry.hooks.map((handler) => resolveHandler(handler, pluginRoot)) };
|
|
378
|
+
if (entry.matcher !== void 0) next.matcher = entry.matcher;
|
|
379
|
+
return next;
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
return out;
|
|
383
|
+
}
|
|
384
|
+
function resolveHandler(handler, pluginRoot) {
|
|
385
|
+
return {
|
|
386
|
+
type: handler.type,
|
|
387
|
+
command: handler.command.replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g, () => pluginRoot),
|
|
388
|
+
...handler.timeout !== void 0 && { timeout: handler.timeout }
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
function normalizePathForCommandMatch$1(value) {
|
|
392
|
+
return value.replace(/\\/g, "/");
|
|
393
|
+
}
|
|
171
394
|
//#endregion
|
|
172
395
|
//#region src/cli/connect/codex-hooks.ts
|
|
173
396
|
/**
|
|
@@ -228,6 +451,81 @@ function normalizePathForCommandMatch(value) {
|
|
|
228
451
|
return value.replace(/\\/g, "/");
|
|
229
452
|
}
|
|
230
453
|
//#endregion
|
|
454
|
+
//#region src/cli/connect/antigravity-cli.ts
|
|
455
|
+
const GEMINI_DIR = join(homedir(), ".gemini");
|
|
456
|
+
const ANTIGRAVITY_CLI_DIR = join(GEMINI_DIR, "antigravity-cli");
|
|
457
|
+
const CUSTOMIZATION_DIR$1 = join(GEMINI_DIR, "config");
|
|
458
|
+
const ANTIGRAVITY_CLI_HOOKS = join(CUSTOMIZATION_DIR$1, "hooks.json");
|
|
459
|
+
const adapter$20 = createJsonMcpAdapter({
|
|
460
|
+
name: "antigravity-cli",
|
|
461
|
+
displayName: "Antigravity CLI (agy)",
|
|
462
|
+
detectDir: ANTIGRAVITY_CLI_DIR,
|
|
463
|
+
configPath: join(CUSTOMIZATION_DIR$1, "mcp_config.json"),
|
|
464
|
+
extraEntryFields: { env: {} },
|
|
465
|
+
docs: "https://github.com/rohitg00/agentmemory#other-agents",
|
|
466
|
+
protocolNote: "→ Using MCP via ~/.gemini/config/mcp_config.json, shared with current Antigravity IDE versions. The `/mcp` slash command inside agy lists configured servers. Pass --with-hooks to also install the native ~/.gemini/config/hooks.json auto-capture hooks.",
|
|
467
|
+
installHooks: installAntigravityCliHooks
|
|
468
|
+
});
|
|
469
|
+
/**
|
|
470
|
+
* Merge the bundled `plugin/hooks/hooks.antigravity.json` into
|
|
471
|
+
* `~/.gemini/config/hooks.json`, replacing only the bundle agentmemory owns.
|
|
472
|
+
*/
|
|
473
|
+
function installAntigravityCliHooks(opts) {
|
|
474
|
+
let pluginRoot;
|
|
475
|
+
try {
|
|
476
|
+
pluginRoot = findPluginRoot();
|
|
477
|
+
} catch (err) {
|
|
478
|
+
return {
|
|
479
|
+
kind: "skipped",
|
|
480
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
if (containsSpaces(pluginRoot)) return {
|
|
484
|
+
kind: "skipped",
|
|
485
|
+
reason: `Antigravity CLI cannot run hook commands whose path contains spaces, and agentmemory is installed at ${pluginRoot}. Reinstall it under a space-free path to use --with-hooks; MCP works either way.`
|
|
486
|
+
};
|
|
487
|
+
const existing = readJsonSafe(ANTIGRAVITY_CLI_HOOKS);
|
|
488
|
+
const merged = buildMergedAntigravityHooks(existing, pluginRoot);
|
|
489
|
+
if (opts.dryRun) {
|
|
490
|
+
p.log.info(`[dry-run] Would ${existing ? "merge" : "create"} ${ANTIGRAVITY_CLI_HOOKS} with ${Object.keys(merged).length} hook bundle(s)`);
|
|
491
|
+
return {
|
|
492
|
+
kind: "installed",
|
|
493
|
+
mutatedPath: ANTIGRAVITY_CLI_HOOKS
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
let backupPath;
|
|
497
|
+
if (existsSync(ANTIGRAVITY_CLI_HOOKS)) {
|
|
498
|
+
backupPath = backupFile(ANTIGRAVITY_CLI_HOOKS, "antigravity-cli-hooks", "json");
|
|
499
|
+
logBackup(backupPath);
|
|
500
|
+
} else mkdirSync(CUSTOMIZATION_DIR$1, { recursive: true });
|
|
501
|
+
writeJsonAtomic(ANTIGRAVITY_CLI_HOOKS, merged);
|
|
502
|
+
logInstalled("Antigravity CLI hooks", ANTIGRAVITY_CLI_HOOKS);
|
|
503
|
+
p.log.info("User-scope hooks reference absolute paths under the bundled plugin/ dir. Re-run `agentmemory connect antigravity-cli --with-hooks` after upgrading agentmemory to refresh them.");
|
|
504
|
+
return {
|
|
505
|
+
kind: "installed",
|
|
506
|
+
mutatedPath: ANTIGRAVITY_CLI_HOOKS,
|
|
507
|
+
...backupPath !== void 0 && { backupPath }
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
//#endregion
|
|
511
|
+
//#region src/cli/connect/antigravity.ts
|
|
512
|
+
const LEGACY_USER_DIR = platform() === "darwin" ? join(homedir(), "Library", "Application Support", "Antigravity", "User") : join(homedir(), ".config", "Antigravity", "User");
|
|
513
|
+
const CUSTOMIZATION_DIR = join(homedir(), ".gemini", "config");
|
|
514
|
+
const mcpAdapter = createJsonMcpAdapter({
|
|
515
|
+
name: "antigravity",
|
|
516
|
+
displayName: "Antigravity",
|
|
517
|
+
detectDir: join(homedir(), ".gemini", "antigravity-ide"),
|
|
518
|
+
configPath: join(CUSTOMIZATION_DIR, "mcp_config.json"),
|
|
519
|
+
extraEntryFields: { env: {} },
|
|
520
|
+
docs: "https://github.com/rohitg00/agentmemory#other-agents",
|
|
521
|
+
protocolNote: "→ Using MCP via ~/.gemini/config/mcp_config.json, shared by current Antigravity surfaces. Pass --with-hooks for capture through ~/.gemini/config/hooks.json.",
|
|
522
|
+
installHooks: installAntigravityCliHooks
|
|
523
|
+
});
|
|
524
|
+
const adapter$19 = {
|
|
525
|
+
...mcpAdapter,
|
|
526
|
+
detect: () => mcpAdapter.detect() || existsSync(join(homedir(), ".gemini", "antigravity")) || existsSync(LEGACY_USER_DIR)
|
|
527
|
+
};
|
|
528
|
+
//#endregion
|
|
231
529
|
//#region src/cli/connect/claude-code.ts
|
|
232
530
|
const CLAUDE_DIR = join(homedir(), ".claude");
|
|
233
531
|
const CLAUDE_JSON = join(homedir(), ".claude.json");
|
|
@@ -238,7 +536,7 @@ function entryMatches$2(entry) {
|
|
|
238
536
|
if (e["command"] !== "npx") return false;
|
|
239
537
|
return (Array.isArray(e["args"]) ? e["args"] : []).includes("@agentmemory/mcp");
|
|
240
538
|
}
|
|
241
|
-
const adapter$
|
|
539
|
+
const adapter$18 = {
|
|
242
540
|
name: "claude-code",
|
|
243
541
|
displayName: "Claude Code",
|
|
244
542
|
category: "native",
|
|
@@ -301,17 +599,6 @@ const adapter$16 = {
|
|
|
301
599
|
};
|
|
302
600
|
}
|
|
303
601
|
};
|
|
304
|
-
/**
|
|
305
|
-
* Merge the bundled `plugin/hooks/hooks.json` into
|
|
306
|
-
* `~/.claude/settings.json`'s top-level `hooks` field with absolute
|
|
307
|
-
* script paths. Use this when agentmemory is NOT installed through
|
|
308
|
-
* `/plugin marketplace add` (e.g. MCP standalone wiring), so the
|
|
309
|
-
* hook scripts survive version bumps without `${CLAUDE_PLUGIN_ROOT}`
|
|
310
|
-
* expansion (issue #508).
|
|
311
|
-
*
|
|
312
|
-
* Re-install strips entries whose command points under
|
|
313
|
-
* `<pluginRoot>/scripts/`; unrelated user hook entries survive.
|
|
314
|
-
*/
|
|
315
602
|
function installClaudeHooks(opts) {
|
|
316
603
|
let pluginRoot;
|
|
317
604
|
try {
|
|
@@ -340,7 +627,7 @@ function installClaudeHooks(opts) {
|
|
|
340
627
|
...existing,
|
|
341
628
|
hooks: merged.hooks
|
|
342
629
|
});
|
|
343
|
-
logInstalled("Claude Code hooks
|
|
630
|
+
logInstalled("Claude Code hooks", CLAUDE_SETTINGS);
|
|
344
631
|
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.");
|
|
345
632
|
return {
|
|
346
633
|
kind: "installed",
|
|
@@ -350,7 +637,7 @@ function installClaudeHooks(opts) {
|
|
|
350
637
|
}
|
|
351
638
|
//#endregion
|
|
352
639
|
//#region src/cli/connect/cline.ts
|
|
353
|
-
const adapter$
|
|
640
|
+
const adapter$17 = createJsonMcpAdapter({
|
|
354
641
|
name: "cline",
|
|
355
642
|
displayName: "Cline",
|
|
356
643
|
detectDir: join(homedir(), ".cline"),
|
|
@@ -366,7 +653,7 @@ function entryMatches$1(entry) {
|
|
|
366
653
|
if (!entry || typeof entry !== "object") return false;
|
|
367
654
|
return JSON.stringify(entry) === JSON.stringify(AGENTMEMORY_COPILOT_MCP_BLOCK);
|
|
368
655
|
}
|
|
369
|
-
const adapter$
|
|
656
|
+
const adapter$16 = {
|
|
370
657
|
name: "copilot-cli",
|
|
371
658
|
displayName: "GitHub Copilot CLI",
|
|
372
659
|
category: "native",
|
|
@@ -449,12 +736,12 @@ function stripExistingBlock(toml) {
|
|
|
449
736
|
}
|
|
450
737
|
return out.join("\n").replace(/\n{3,}$/, "\n\n").trimEnd() + "\n";
|
|
451
738
|
}
|
|
452
|
-
const adapter$
|
|
739
|
+
const adapter$15 = {
|
|
453
740
|
name: "codex",
|
|
454
741
|
displayName: "Codex CLI",
|
|
455
742
|
category: "native",
|
|
456
743
|
docs: "https://github.com/rohitg00/agentmemory#codex-cli-codex-plugin-platform",
|
|
457
|
-
protocolNote: "→ Using MCP. Hooks ship via the Codex plugin; on Codex Desktop, also pass --with-hooks to install the global hooks.json workaround
|
|
744
|
+
protocolNote: "→ Using MCP. Hooks ship via the Codex plugin; on Codex Desktop, also pass --with-hooks to install the global hooks.json workaround.",
|
|
458
745
|
detect() {
|
|
459
746
|
return existsSync(CODEX_DIR);
|
|
460
747
|
},
|
|
@@ -504,12 +791,6 @@ const adapter$13 = {
|
|
|
504
791
|
};
|
|
505
792
|
}
|
|
506
793
|
};
|
|
507
|
-
/**
|
|
508
|
-
* Install the global `~/.codex/hooks.json` fallback. See
|
|
509
|
-
* `codex-hooks.ts` for context (openai/codex#16430). Returns a result
|
|
510
|
-
* describing the side effect for the caller's summary; failures here do
|
|
511
|
-
* not roll back the MCP wiring.
|
|
512
|
-
*/
|
|
513
794
|
function installCodexHooks(opts) {
|
|
514
795
|
let pluginRoot;
|
|
515
796
|
try {
|
|
@@ -535,8 +816,9 @@ function installCodexHooks(opts) {
|
|
|
535
816
|
logBackup(backupPath);
|
|
536
817
|
}
|
|
537
818
|
writeJsonAtomic(CODEX_HOOKS, merged);
|
|
538
|
-
logInstalled("Codex hooks
|
|
539
|
-
p.log.
|
|
819
|
+
logInstalled("Codex hooks", CODEX_HOOKS);
|
|
820
|
+
p.log.warn("Codex runs only trusted hooks: launch `codex` (the TUI) once and choose \"Trust all and continue\" at the \"Hooks need review\" prompt. `codex exec` never shows the prompt, so hooks stay inert until then.");
|
|
821
|
+
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, then re-approve in the TUI.");
|
|
540
822
|
return {
|
|
541
823
|
kind: "installed",
|
|
542
824
|
mutatedPath: CODEX_HOOKS,
|
|
@@ -574,7 +856,7 @@ function renderFreshYaml() {
|
|
|
574
856
|
""
|
|
575
857
|
].join("\n");
|
|
576
858
|
}
|
|
577
|
-
const adapter$
|
|
859
|
+
const adapter$14 = {
|
|
578
860
|
name: "continue",
|
|
579
861
|
displayName: "Continue",
|
|
580
862
|
category: "mcp",
|
|
@@ -654,7 +936,7 @@ const adapter$12 = {
|
|
|
654
936
|
};
|
|
655
937
|
//#endregion
|
|
656
938
|
//#region src/cli/connect/cursor.ts
|
|
657
|
-
const adapter$
|
|
939
|
+
const adapter$13 = createJsonMcpAdapter({
|
|
658
940
|
name: "cursor",
|
|
659
941
|
displayName: "Cursor",
|
|
660
942
|
detectDir: join(homedir(), ".cursor"),
|
|
@@ -663,16 +945,222 @@ const adapter$11 = createJsonMcpAdapter({
|
|
|
663
945
|
protocolNote: "→ Using MCP (the only protocol Cursor speaks). Memory bridge runs at :3111 underneath."
|
|
664
946
|
});
|
|
665
947
|
//#endregion
|
|
948
|
+
//#region src/cli/connect/devin.ts
|
|
949
|
+
function devinDir() {
|
|
950
|
+
if (platform() === "win32") {
|
|
951
|
+
const appData = process.env["APPDATA"];
|
|
952
|
+
if (appData) return join(appData, "devin");
|
|
953
|
+
}
|
|
954
|
+
const xdg = process.env["XDG_CONFIG_HOME"];
|
|
955
|
+
return xdg ? join(xdg, "devin") : join(homedir(), ".config", "devin");
|
|
956
|
+
}
|
|
957
|
+
const DEVIN_DIR = devinDir();
|
|
958
|
+
const DEVIN_CONFIG = join(DEVIN_DIR, "config.json");
|
|
959
|
+
const adapter$12 = createJsonMcpAdapter({
|
|
960
|
+
name: "devin",
|
|
961
|
+
displayName: "Devin CLI",
|
|
962
|
+
detectDir: DEVIN_DIR,
|
|
963
|
+
configPath: DEVIN_CONFIG,
|
|
964
|
+
docs: "https://github.com/rohitg00/agentmemory#other-agents",
|
|
965
|
+
protocolNote: "→ Using MCP via the user config. Devin CLI migrates mcpServers into mcp_config.json on newer builds. Pass --with-hooks for native auto-capture.",
|
|
966
|
+
installHooks: installDevinHooks
|
|
967
|
+
});
|
|
968
|
+
function installDevinHooks(opts) {
|
|
969
|
+
let pluginRoot;
|
|
970
|
+
try {
|
|
971
|
+
pluginRoot = findPluginRoot();
|
|
972
|
+
} catch (err) {
|
|
973
|
+
return {
|
|
974
|
+
kind: "skipped",
|
|
975
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
976
|
+
};
|
|
977
|
+
}
|
|
978
|
+
const existing = readJsonSafe(DEVIN_CONFIG) ?? {};
|
|
979
|
+
const merged = buildMergedHooks(existing["hooks"] ? { hooks: existing["hooks"] } : null, pluginRoot, "hooks.devin.json");
|
|
980
|
+
const next = {
|
|
981
|
+
...existing,
|
|
982
|
+
hooks: merged.hooks
|
|
983
|
+
};
|
|
984
|
+
if (opts.dryRun) {
|
|
985
|
+
p.log.info(`[dry-run] Would write ${Object.keys(merged.hooks).length} hook event(s) into ${DEVIN_CONFIG}`);
|
|
986
|
+
return {
|
|
987
|
+
kind: "installed",
|
|
988
|
+
mutatedPath: DEVIN_CONFIG
|
|
989
|
+
};
|
|
990
|
+
}
|
|
991
|
+
let backupPath;
|
|
992
|
+
if (existsSync(DEVIN_CONFIG)) {
|
|
993
|
+
backupPath = backupFile(DEVIN_CONFIG, "devin-hooks", "json");
|
|
994
|
+
logBackup(backupPath);
|
|
995
|
+
} else mkdirSync(DEVIN_DIR, { recursive: true });
|
|
996
|
+
writeJsonAtomic(DEVIN_CONFIG, next);
|
|
997
|
+
logInstalled("Devin CLI hooks", DEVIN_CONFIG);
|
|
998
|
+
p.log.info("Verify with `/hooks` inside devin. Re-run `agentmemory connect devin --with-hooks` after upgrading agentmemory so the plugin paths stay current.");
|
|
999
|
+
return {
|
|
1000
|
+
kind: "installed",
|
|
1001
|
+
mutatedPath: DEVIN_CONFIG,
|
|
1002
|
+
...backupPath !== void 0 && { backupPath }
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
1005
|
+
//#endregion
|
|
666
1006
|
//#region src/cli/connect/droid.ts
|
|
667
|
-
const
|
|
1007
|
+
const DROID_DIR = join(homedir(), ".factory");
|
|
1008
|
+
const DROID_HOOKS = join(DROID_DIR, "hooks.json");
|
|
1009
|
+
const adapter$11 = createJsonMcpAdapter({
|
|
668
1010
|
name: "droid",
|
|
669
1011
|
displayName: "Droid (Factory.ai)",
|
|
670
|
-
detectDir:
|
|
671
|
-
configPath: join(
|
|
1012
|
+
detectDir: DROID_DIR,
|
|
1013
|
+
configPath: join(DROID_DIR, "mcp.json"),
|
|
672
1014
|
docs: "https://github.com/rohitg00/agentmemory#other-agents",
|
|
673
|
-
protocolNote: "→ Using MCP via ~/.factory/mcp.json. The `/mcp` slash command inside droid lists configured servers.",
|
|
674
|
-
extraEntryFields: { type: "stdio" }
|
|
1015
|
+
protocolNote: "→ Using MCP via ~/.factory/mcp.json. The `/mcp` slash command inside droid lists configured servers. Pass --with-hooks to also install the native ~/.factory/hooks.json auto-capture hooks.",
|
|
1016
|
+
extraEntryFields: { type: "stdio" },
|
|
1017
|
+
installHooks: installDroidHooks
|
|
675
1018
|
});
|
|
1019
|
+
/**
|
|
1020
|
+
* Merge the bundled `plugin/hooks/hooks.droid.json` into
|
|
1021
|
+
* `~/.factory/hooks.json`. Same idempotent merge/strip-by-script-path
|
|
1022
|
+
* behavior as the Codex and Claude Code hook installers: re-running keeps
|
|
1023
|
+
* user-authored hook entries and only replaces the ones agentmemory owns.
|
|
1024
|
+
*/
|
|
1025
|
+
function installDroidHooks(opts) {
|
|
1026
|
+
let pluginRoot;
|
|
1027
|
+
try {
|
|
1028
|
+
pluginRoot = findPluginRoot();
|
|
1029
|
+
} catch (err) {
|
|
1030
|
+
return {
|
|
1031
|
+
kind: "skipped",
|
|
1032
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
1033
|
+
};
|
|
1034
|
+
}
|
|
1035
|
+
const existing = readJsonSafe(DROID_HOOKS);
|
|
1036
|
+
const merged = buildMergedHooks(existing, pluginRoot, "hooks.droid.json");
|
|
1037
|
+
if (opts.dryRun) {
|
|
1038
|
+
p.log.info(`[dry-run] Would ${existing ? "merge" : "create"} ${DROID_HOOKS} with ${Object.keys(merged.hooks).length} event(s)`);
|
|
1039
|
+
return {
|
|
1040
|
+
kind: "installed",
|
|
1041
|
+
mutatedPath: DROID_HOOKS
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
1044
|
+
let backupPath;
|
|
1045
|
+
if (existsSync(DROID_HOOKS)) {
|
|
1046
|
+
backupPath = backupFile(DROID_HOOKS, "droid-hooks", "json");
|
|
1047
|
+
logBackup(backupPath);
|
|
1048
|
+
} else mkdirSync(DROID_DIR, { recursive: true });
|
|
1049
|
+
writeJsonAtomic(DROID_HOOKS, merged);
|
|
1050
|
+
logInstalled("Droid hooks", DROID_HOOKS);
|
|
1051
|
+
p.log.info("User-scope hooks reference absolute paths under the bundled plugin/ dir. Re-run `agentmemory connect droid --with-hooks` after upgrading agentmemory to refresh them.");
|
|
1052
|
+
return {
|
|
1053
|
+
kind: "installed",
|
|
1054
|
+
mutatedPath: DROID_HOOKS,
|
|
1055
|
+
...backupPath !== void 0 && { backupPath }
|
|
1056
|
+
};
|
|
1057
|
+
}
|
|
1058
|
+
//#endregion
|
|
1059
|
+
//#region src/cli/connect/dsh.ts
|
|
1060
|
+
function dshHome() {
|
|
1061
|
+
return process.env["DSH_HOME"] || join(homedir(), ".dsh");
|
|
1062
|
+
}
|
|
1063
|
+
const MCP_BLOCK = `- insert:
|
|
1064
|
+
- id: agentmemory
|
|
1065
|
+
name: '@deepseek-ai/dsh-mcp-client'
|
|
1066
|
+
config:
|
|
1067
|
+
transport: stdio
|
|
1068
|
+
serverName: agentmemory
|
|
1069
|
+
command: npx
|
|
1070
|
+
args: ['-y', '@agentmemory/mcp']
|
|
1071
|
+
env:
|
|
1072
|
+
AGENTMEMORY_URL: http://localhost:3111
|
|
1073
|
+
`;
|
|
1074
|
+
const MCP_MARKER = "serverName: agentmemory";
|
|
1075
|
+
const HOOKS_MARKER = "id: agentmemory-hooks";
|
|
1076
|
+
function hooksBlock(hooksConfigPath) {
|
|
1077
|
+
return `- insert:
|
|
1078
|
+
- id: agentmemory-hooks
|
|
1079
|
+
name: '@deepseek-ai/dsh-hooks-claude-code'
|
|
1080
|
+
config:
|
|
1081
|
+
configPath: ${JSON.stringify(hooksConfigPath)}
|
|
1082
|
+
`;
|
|
1083
|
+
}
|
|
1084
|
+
function stripBlock(content, marker) {
|
|
1085
|
+
if (!content.includes(marker)) return content;
|
|
1086
|
+
const lines = content.split("\n");
|
|
1087
|
+
const markerIdx = lines.findIndex((l) => l.includes(marker));
|
|
1088
|
+
let start = markerIdx;
|
|
1089
|
+
while (start > 0 && !lines[start].startsWith("- ")) start--;
|
|
1090
|
+
let end = markerIdx + 1;
|
|
1091
|
+
while (end < lines.length && !lines[end].startsWith("- ")) end++;
|
|
1092
|
+
return lines.slice(0, start).concat(lines.slice(end)).join("\n").replace(/\n+$/, "\n");
|
|
1093
|
+
}
|
|
1094
|
+
function appendBlock(content, block) {
|
|
1095
|
+
const base = content.replace(/\n+$/, "\n");
|
|
1096
|
+
return base.trim() ? `${base}\n${block}` : block;
|
|
1097
|
+
}
|
|
1098
|
+
function installHooksFile(home) {
|
|
1099
|
+
const hooksPath = join(home, "agentmemory.hooks.json");
|
|
1100
|
+
const pluginRoot = findPluginRoot();
|
|
1101
|
+
writeJsonAtomic(hooksPath, buildMergedHooks(readJsonSafe(hooksPath), pluginRoot, "hooks.codex.json"));
|
|
1102
|
+
return hooksPath;
|
|
1103
|
+
}
|
|
1104
|
+
const adapter$10 = {
|
|
1105
|
+
name: "dsh",
|
|
1106
|
+
displayName: "DeepSeek Harness",
|
|
1107
|
+
docs: "https://github.com/rohitg00/agentmemory#other-agents",
|
|
1108
|
+
protocolNote: "→ Using MCP via $DSH_HOME/cordis.patch.yml (the home-level patch layer every profile loads). Tools appear as mcp__agentmemory__*. Pass --with-hooks to also wire auto-capture through Harness's Claude Code hook bridge.",
|
|
1109
|
+
category: "native",
|
|
1110
|
+
detect() {
|
|
1111
|
+
return existsSync(dshHome());
|
|
1112
|
+
},
|
|
1113
|
+
async install(opts) {
|
|
1114
|
+
const home = dshHome();
|
|
1115
|
+
const configPath = join(home, "cordis.patch.yml");
|
|
1116
|
+
const existing = existsSync(configPath) ? readFileSync(configPath, "utf-8") : "";
|
|
1117
|
+
const wantHooks = opts.withHooks === true;
|
|
1118
|
+
const hasMcp = existing.includes(MCP_MARKER);
|
|
1119
|
+
const hasHooks = existing.includes(HOOKS_MARKER);
|
|
1120
|
+
if (hasMcp && (!wantHooks || hasHooks) && !opts.force) {
|
|
1121
|
+
logAlreadyWired(this.displayName, configPath);
|
|
1122
|
+
return {
|
|
1123
|
+
kind: "already-wired",
|
|
1124
|
+
mutatedPath: configPath
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1127
|
+
if (opts.dryRun) {
|
|
1128
|
+
p.log.info(`[dry-run] Would append the agentmemory mcp-client row${wantHooks ? " and the hooks-claude-code row" : ""} to ${configPath}`);
|
|
1129
|
+
return {
|
|
1130
|
+
kind: "installed",
|
|
1131
|
+
mutatedPath: configPath
|
|
1132
|
+
};
|
|
1133
|
+
}
|
|
1134
|
+
let backupPath;
|
|
1135
|
+
if (existsSync(configPath)) {
|
|
1136
|
+
backupPath = backupFile(configPath, this.name, "yml");
|
|
1137
|
+
logBackup(backupPath);
|
|
1138
|
+
} else mkdirSync(dirname(configPath), { recursive: true });
|
|
1139
|
+
let next = stripBlock(existing, MCP_MARKER);
|
|
1140
|
+
next = appendBlock(next, MCP_BLOCK);
|
|
1141
|
+
if (wantHooks) {
|
|
1142
|
+
const hooksPath = installHooksFile(home);
|
|
1143
|
+
next = stripBlock(next, HOOKS_MARKER);
|
|
1144
|
+
next = appendBlock(next, hooksBlock(hooksPath));
|
|
1145
|
+
p.log.info(`Hook manifest: ${hooksPath}`);
|
|
1146
|
+
}
|
|
1147
|
+
writeTextAtomic(configPath, next);
|
|
1148
|
+
const written = readFileSync(configPath, "utf-8");
|
|
1149
|
+
if (!written.includes(MCP_MARKER) || wantHooks && !written.includes(HOOKS_MARKER)) {
|
|
1150
|
+
p.log.error(`Verification failed: ${configPath} did not contain the agentmemory rows after write.`);
|
|
1151
|
+
return {
|
|
1152
|
+
kind: "skipped",
|
|
1153
|
+
reason: "verification-failed"
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
logInstalled(this.displayName, configPath);
|
|
1157
|
+
return {
|
|
1158
|
+
kind: "installed",
|
|
1159
|
+
mutatedPath: configPath,
|
|
1160
|
+
backupPath
|
|
1161
|
+
};
|
|
1162
|
+
}
|
|
1163
|
+
};
|
|
676
1164
|
//#endregion
|
|
677
1165
|
//#region src/cli/connect/gemini-cli.ts
|
|
678
1166
|
const adapter$9 = createJsonMcpAdapter({
|
|
@@ -844,32 +1332,75 @@ const adapter$4 = {
|
|
|
844
1332
|
const PI_DIR = join(homedir(), ".pi");
|
|
845
1333
|
const PI_EXT_DIR = join(PI_DIR, "agent", "extensions", "agentmemory");
|
|
846
1334
|
const DOCS = "https://github.com/rohitg00/agentmemory/tree/main/integrations/pi";
|
|
1335
|
+
const EXT_FILES = ["index.ts", "security.ts"];
|
|
1336
|
+
function findPiSourceDir() {
|
|
1337
|
+
let packageRoot;
|
|
1338
|
+
try {
|
|
1339
|
+
packageRoot = dirname(findPluginRoot());
|
|
1340
|
+
} catch {
|
|
1341
|
+
return null;
|
|
1342
|
+
}
|
|
1343
|
+
const dir = join(packageRoot, "integrations", "pi");
|
|
1344
|
+
return EXT_FILES.every((f) => existsSync(join(dir, f))) ? dir : null;
|
|
1345
|
+
}
|
|
847
1346
|
const adapter$3 = {
|
|
848
1347
|
name: "pi",
|
|
849
1348
|
displayName: "pi",
|
|
850
1349
|
category: "native",
|
|
851
1350
|
docs: DOCS,
|
|
852
|
-
protocolNote: "→ Using native hooks
|
|
1351
|
+
protocolNote: "→ Using native lifecycle hooks against the REST API at :3111 (recall on agent start, capture on agent end, memory tools). MCP not required.",
|
|
853
1352
|
detect() {
|
|
854
1353
|
return existsSync(PI_DIR);
|
|
855
1354
|
},
|
|
856
|
-
async install(
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
"
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
"",
|
|
868
|
-
|
|
869
|
-
|
|
1355
|
+
async install(opts) {
|
|
1356
|
+
const sourceDir = findPiSourceDir();
|
|
1357
|
+
if (!sourceDir) {
|
|
1358
|
+
p.log.error("Bundled pi extension not found (integrations/pi missing from the install) — reinstall agentmemory.");
|
|
1359
|
+
return {
|
|
1360
|
+
kind: "skipped",
|
|
1361
|
+
reason: "bundled-extension-missing"
|
|
1362
|
+
};
|
|
1363
|
+
}
|
|
1364
|
+
const sources = EXT_FILES.map((f) => ({
|
|
1365
|
+
name: f,
|
|
1366
|
+
content: readFileSync(join(sourceDir, f), "utf-8"),
|
|
1367
|
+
target: join(PI_EXT_DIR, f)
|
|
1368
|
+
}));
|
|
1369
|
+
if (sources.every((s) => existsSync(s.target) && readFileSync(s.target, "utf-8") === s.content) && !opts.force) {
|
|
1370
|
+
logAlreadyWired(this.displayName, PI_EXT_DIR);
|
|
1371
|
+
return {
|
|
1372
|
+
kind: "already-wired",
|
|
1373
|
+
mutatedPath: PI_EXT_DIR
|
|
1374
|
+
};
|
|
1375
|
+
}
|
|
1376
|
+
if (opts.dryRun) {
|
|
1377
|
+
p.log.info(`[dry-run] Would install the pi extension (${EXT_FILES.join(", ")}) into ${PI_EXT_DIR}`);
|
|
1378
|
+
return {
|
|
1379
|
+
kind: "installed",
|
|
1380
|
+
mutatedPath: PI_EXT_DIR
|
|
1381
|
+
};
|
|
1382
|
+
}
|
|
1383
|
+
let backupPath;
|
|
1384
|
+
for (const s of sources) if (existsSync(s.target) && readFileSync(s.target, "utf-8") !== s.content) {
|
|
1385
|
+
const backup = backupFile(s.target, `${this.name}-${s.name.replace(/\.ts$/, "")}`, "ts");
|
|
1386
|
+
logBackup(backup);
|
|
1387
|
+
backupPath ??= backup;
|
|
1388
|
+
}
|
|
1389
|
+
mkdirSync(PI_EXT_DIR, { recursive: true });
|
|
1390
|
+
for (const s of sources) writeTextAtomic(s.target, s.content);
|
|
1391
|
+
if (!sources.every((s) => existsSync(s.target) && readFileSync(s.target, "utf-8") === s.content)) {
|
|
1392
|
+
p.log.error(`Verification failed: ${PI_EXT_DIR} does not match the bundled extension.`);
|
|
1393
|
+
return {
|
|
1394
|
+
kind: "skipped",
|
|
1395
|
+
reason: "verification-failed"
|
|
1396
|
+
};
|
|
1397
|
+
}
|
|
1398
|
+
logInstalled(this.displayName, PI_EXT_DIR);
|
|
1399
|
+
p.log.info("pi auto-discovers the extension on next launch; a running pi picks it up with /reload. Verify with /agentmemory-status.");
|
|
870
1400
|
return {
|
|
871
|
-
kind: "
|
|
872
|
-
|
|
1401
|
+
kind: "installed",
|
|
1402
|
+
mutatedPath: PI_EXT_DIR,
|
|
1403
|
+
backupPath
|
|
873
1404
|
};
|
|
874
1405
|
}
|
|
875
1406
|
};
|
|
@@ -915,18 +1446,21 @@ var connect_exports = /* @__PURE__ */ __exportAll({
|
|
|
915
1446
|
runConnect: () => runConnect
|
|
916
1447
|
});
|
|
917
1448
|
const ADAPTERS = [
|
|
1449
|
+
adapter$18,
|
|
918
1450
|
adapter$16,
|
|
919
|
-
adapter$
|
|
1451
|
+
adapter$15,
|
|
920
1452
|
adapter$13,
|
|
921
|
-
adapter$
|
|
1453
|
+
adapter$12,
|
|
922
1454
|
adapter$9,
|
|
923
1455
|
adapter$2,
|
|
924
|
-
adapter$
|
|
1456
|
+
adapter$19,
|
|
1457
|
+
adapter$20,
|
|
925
1458
|
adapter$7,
|
|
926
1459
|
adapter$1,
|
|
927
|
-
adapter$
|
|
928
|
-
adapter$
|
|
1460
|
+
adapter$17,
|
|
1461
|
+
adapter$14,
|
|
929
1462
|
adapter,
|
|
1463
|
+
adapter$11,
|
|
930
1464
|
adapter$10,
|
|
931
1465
|
adapter$5,
|
|
932
1466
|
adapter$6,
|
|
@@ -947,16 +1481,19 @@ function parseFlags(args) {
|
|
|
947
1481
|
let force = false;
|
|
948
1482
|
let all = false;
|
|
949
1483
|
let withHooks = false;
|
|
1484
|
+
let guidelines = true;
|
|
950
1485
|
for (const a of args) if (a === "--dry-run") dryRun = true;
|
|
951
1486
|
else if (a === "--force") force = true;
|
|
952
1487
|
else if (a === "--all") all = true;
|
|
953
1488
|
else if (a === "--with-hooks") withHooks = true;
|
|
1489
|
+
else if (a === "--no-guidelines") guidelines = false;
|
|
954
1490
|
else if (!a.startsWith("-")) positional.push(a);
|
|
955
1491
|
return {
|
|
956
1492
|
dryRun,
|
|
957
1493
|
force,
|
|
958
1494
|
all,
|
|
959
1495
|
withHooks,
|
|
1496
|
+
guidelines,
|
|
960
1497
|
positional
|
|
961
1498
|
};
|
|
962
1499
|
}
|
|
@@ -971,7 +1508,18 @@ async function runAdapter(adapter, opts) {
|
|
|
971
1508
|
p.log.step(`Wiring ${adapter.displayName}…`);
|
|
972
1509
|
if (adapter.protocolNote) p.log.message(adapter.protocolNote);
|
|
973
1510
|
try {
|
|
974
|
-
|
|
1511
|
+
const result = await adapter.install(opts);
|
|
1512
|
+
if (opts.guidelines !== false && (result.kind === "installed" || result.kind === "already-wired")) try {
|
|
1513
|
+
const g = writeGuideline(adapter.name, {
|
|
1514
|
+
cwd: process.cwd(),
|
|
1515
|
+
dryRun: opts.dryRun
|
|
1516
|
+
});
|
|
1517
|
+
if (g.kind === "written") p.log.message(` ${pc.dim("guideline")} ${g.scope} → ${g.path} (memory auto-use)`);
|
|
1518
|
+
else if (g.kind === "would-write") p.log.message(` ${pc.dim("[dry-run] guideline")} → ${g.path}`);
|
|
1519
|
+
} catch (gerr) {
|
|
1520
|
+
p.log.warn(`${adapter.displayName}: guideline not written (${gerr instanceof Error ? gerr.message : String(gerr)})`);
|
|
1521
|
+
}
|
|
1522
|
+
return result;
|
|
975
1523
|
} catch (err) {
|
|
976
1524
|
p.log.error(`${adapter.displayName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
977
1525
|
return {
|
|
@@ -981,7 +1529,7 @@ async function runAdapter(adapter, opts) {
|
|
|
981
1529
|
}
|
|
982
1530
|
}
|
|
983
1531
|
async function runConnect(args) {
|
|
984
|
-
const { dryRun, force, all, withHooks, positional } = parseFlags(args);
|
|
1532
|
+
const { dryRun, force, all, withHooks, guidelines, positional } = parseFlags(args);
|
|
985
1533
|
const allowWindowsAdapter = positional.length === 1 && positional[0]?.toLowerCase() === "copilot-cli";
|
|
986
1534
|
if (platform() === "win32" && !allowWindowsAdapter) {
|
|
987
1535
|
p.intro("agentmemory connect");
|
|
@@ -992,7 +1540,8 @@ async function runConnect(args) {
|
|
|
992
1540
|
const opts = {
|
|
993
1541
|
dryRun,
|
|
994
1542
|
force,
|
|
995
|
-
withHooks
|
|
1543
|
+
withHooks,
|
|
1544
|
+
guidelines
|
|
996
1545
|
};
|
|
997
1546
|
p.intro("agentmemory connect");
|
|
998
1547
|
if (positional.length === 0 && !all) {
|
|
@@ -1066,10 +1615,10 @@ function summarize(results) {
|
|
|
1066
1615
|
p.note(lines.join("\n"), "summary");
|
|
1067
1616
|
const stubs = results.filter((r) => r.result.kind === "stub");
|
|
1068
1617
|
if (stubs.length > 0) p.log.info(`${stubs.length} agent(s) require manual install — see docs links above.`);
|
|
1069
|
-
if (results.some((r) => r.result.kind === "installed" || r.result.kind === "already-wired")) p.log.info("Next: install agentmemory's
|
|
1618
|
+
if (results.some((r) => r.result.kind === "installed" || r.result.kind === "already-wired")) p.log.info("Next: install agentmemory's 17 skills into the same agent(s) so they know when to call the tools:\n npx skills add rohitg00/agentmemory -y");
|
|
1070
1619
|
p.outro("Restart any wired agent (or open a new session) to pick up agentmemory.");
|
|
1071
1620
|
}
|
|
1072
1621
|
//#endregion
|
|
1073
1622
|
export { runAdapter as a, resolveAdapter as i, connect_exports as n, knownAgents as r, ADAPTERS as t };
|
|
1074
1623
|
|
|
1075
|
-
//# sourceMappingURL=connect-
|
|
1624
|
+
//# sourceMappingURL=connect-B4_ca6BD.mjs.map
|