@agentmemory/agentmemory 0.9.27 → 0.9.29

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.
Files changed (156) hide show
  1. package/.env.example +15 -6
  2. package/AGENTS.md +7 -7
  3. package/README.md +292 -164
  4. package/dist/.env.example +15 -6
  5. package/dist/cli.d.mts.map +1 -1
  6. package/dist/cli.mjs +427 -177
  7. package/dist/cli.mjs.map +1 -1
  8. package/dist/{connect-bmZ5eqYN.mjs → connect-Qaeq15TQ.mjs} +717 -65
  9. package/dist/connect-Qaeq15TQ.mjs.map +1 -0
  10. package/dist/docker-compose.yml +2 -2
  11. package/dist/hooks/antigravity-bridge.d.mts +8 -0
  12. package/dist/hooks/antigravity-bridge.d.mts.map +1 -0
  13. package/dist/hooks/antigravity-bridge.mjs +114 -0
  14. package/dist/hooks/antigravity-bridge.mjs.map +1 -0
  15. package/dist/hooks/notification.mjs +21 -5
  16. package/dist/hooks/notification.mjs.map +1 -1
  17. package/dist/hooks/post-commit.mjs +15 -2
  18. package/dist/hooks/post-commit.mjs.map +1 -1
  19. package/dist/hooks/post-tool-failure.mjs +16 -4
  20. package/dist/hooks/post-tool-failure.mjs.map +1 -1
  21. package/dist/hooks/post-tool-use.mjs +16 -4
  22. package/dist/hooks/post-tool-use.mjs.map +1 -1
  23. package/dist/hooks/pre-compact.mjs +14 -3
  24. package/dist/hooks/pre-compact.mjs.map +1 -1
  25. package/dist/hooks/pre-tool-use.mjs +3 -2
  26. package/dist/hooks/pre-tool-use.mjs.map +1 -1
  27. package/dist/hooks/prompt-submit.mjs +16 -4
  28. package/dist/hooks/prompt-submit.mjs.map +1 -1
  29. package/dist/hooks/session-end.mjs +84 -19
  30. package/dist/hooks/session-end.mjs.map +1 -1
  31. package/dist/hooks/session-start.mjs +24 -5
  32. package/dist/hooks/session-start.mjs.map +1 -1
  33. package/dist/hooks/stop.mjs +3 -8
  34. package/dist/hooks/stop.mjs.map +1 -1
  35. package/dist/hooks/subagent-start.mjs +16 -4
  36. package/dist/hooks/subagent-start.mjs.map +1 -1
  37. package/dist/hooks/subagent-stop.mjs +16 -4
  38. package/dist/hooks/subagent-stop.mjs.map +1 -1
  39. package/dist/hooks/task-completed.mjs +16 -4
  40. package/dist/hooks/task-completed.mjs.map +1 -1
  41. package/dist/{image-refs-B5Zf_Djo.mjs → image-refs-BKLmp_sD.mjs} +4 -22
  42. package/dist/image-refs-BKLmp_sD.mjs.map +1 -0
  43. package/dist/image-refs-CJgZmb9X.mjs +34 -0
  44. package/dist/image-refs-CJgZmb9X.mjs.map +1 -0
  45. package/dist/index.mjs +1681 -911
  46. package/dist/index.mjs.map +1 -1
  47. package/dist/{image-store-Gpo2mgM9.mjs → keyed-mutex-DTHtcZrt.mjs} +14 -11
  48. package/dist/keyed-mutex-DTHtcZrt.mjs.map +1 -0
  49. package/dist/{logger-yHTcEBAI.mjs → logger-BEB7pCI9.mjs} +1 -1
  50. package/dist/{logger-yHTcEBAI.mjs.map → logger-BEB7pCI9.mjs.map} +1 -1
  51. package/dist/schema-BFZhNTF7.mjs +197 -0
  52. package/dist/schema-BFZhNTF7.mjs.map +1 -0
  53. package/dist/{src-MOg2zKJs.mjs → src-G7yt8gGm.mjs} +1521 -854
  54. package/dist/src-G7yt8gGm.mjs.map +1 -0
  55. package/dist/{standalone-BORXC71-.mjs → standalone-BqNJDJ04.mjs} +30 -16
  56. package/dist/standalone-BqNJDJ04.mjs.map +1 -0
  57. package/dist/standalone.d.mts.map +1 -1
  58. package/dist/standalone.mjs +55 -15
  59. package/dist/standalone.mjs.map +1 -1
  60. package/dist/{tools-registry-D8XVVPbJ.mjs → tools-registry-BV_2bu7z.mjs} +55 -17
  61. package/dist/tools-registry-BV_2bu7z.mjs.map +1 -0
  62. package/dist/viewer/favicon.svg +35 -1
  63. package/dist/viewer/index.html +473 -83
  64. package/docker-compose.yml +2 -2
  65. package/integrations/pi/README.md +77 -0
  66. package/integrations/pi/index.ts +403 -0
  67. package/integrations/pi/package.json +32 -0
  68. package/integrations/pi/security.ts +35 -0
  69. package/package.json +6 -4
  70. package/plugin/.claude-plugin/plugin.json +2 -2
  71. package/plugin/.codex-plugin/plugin.json +2 -2
  72. package/plugin/.devin-plugin/plugin.json +32 -0
  73. package/plugin/cursor/hooks.json +41 -0
  74. package/plugin/cursor/mcp.json +12 -0
  75. package/plugin/hooks/hooks.antigravity.json +43 -0
  76. package/plugin/hooks/hooks.devin.json +67 -0
  77. package/plugin/hooks/hooks.droid.json +55 -0
  78. package/plugin/opencode/README.md +1 -1
  79. package/plugin/opencode/agentmemory-capture.ts +73 -13
  80. package/plugin/opencode/plugin.json +1 -1
  81. package/plugin/plugin.json +2 -2
  82. package/plugin/scripts/antigravity-bridge.d.mts +8 -0
  83. package/plugin/scripts/antigravity-bridge.d.mts.map +1 -0
  84. package/plugin/scripts/antigravity-bridge.mjs +114 -0
  85. package/plugin/scripts/antigravity-bridge.mjs.map +1 -0
  86. package/plugin/scripts/notification.mjs +21 -5
  87. package/plugin/scripts/notification.mjs.map +1 -1
  88. package/plugin/scripts/post-commit.mjs +15 -2
  89. package/plugin/scripts/post-commit.mjs.map +1 -1
  90. package/plugin/scripts/post-tool-failure.mjs +16 -4
  91. package/plugin/scripts/post-tool-failure.mjs.map +1 -1
  92. package/plugin/scripts/post-tool-use.mjs +16 -4
  93. package/plugin/scripts/post-tool-use.mjs.map +1 -1
  94. package/plugin/scripts/pre-compact.mjs +14 -3
  95. package/plugin/scripts/pre-compact.mjs.map +1 -1
  96. package/plugin/scripts/pre-tool-use.mjs +3 -2
  97. package/plugin/scripts/pre-tool-use.mjs.map +1 -1
  98. package/plugin/scripts/prompt-submit.mjs +16 -4
  99. package/plugin/scripts/prompt-submit.mjs.map +1 -1
  100. package/plugin/scripts/session-end.mjs +84 -19
  101. package/plugin/scripts/session-end.mjs.map +1 -1
  102. package/plugin/scripts/session-start.mjs +24 -5
  103. package/plugin/scripts/session-start.mjs.map +1 -1
  104. package/plugin/scripts/stop.mjs +3 -8
  105. package/plugin/scripts/stop.mjs.map +1 -1
  106. package/plugin/scripts/subagent-start.mjs +16 -4
  107. package/plugin/scripts/subagent-start.mjs.map +1 -1
  108. package/plugin/scripts/subagent-stop.mjs +16 -4
  109. package/plugin/scripts/subagent-stop.mjs.map +1 -1
  110. package/plugin/scripts/task-completed.mjs +16 -4
  111. package/plugin/scripts/task-completed.mjs.map +1 -1
  112. package/plugin/skills/_shared/TROUBLESHOOTING.md +38 -0
  113. package/plugin/skills/agentmemory-agents/REFERENCE.md +31 -0
  114. package/plugin/skills/agentmemory-agents/SKILL.md +34 -0
  115. package/plugin/skills/agentmemory-architecture/SKILL.md +33 -0
  116. package/plugin/skills/agentmemory-config/REFERENCE.md +45 -0
  117. package/plugin/skills/agentmemory-config/SKILL.md +37 -0
  118. package/plugin/skills/agentmemory-hooks/REFERENCE.md +20 -0
  119. package/plugin/skills/agentmemory-hooks/SKILL.md +39 -0
  120. package/plugin/skills/agentmemory-mcp-tools/REFERENCE.md +66 -0
  121. package/plugin/skills/agentmemory-mcp-tools/SKILL.md +39 -0
  122. package/plugin/skills/agentmemory-rest-api/REFERENCE.md +142 -0
  123. package/plugin/skills/agentmemory-rest-api/SKILL.md +43 -0
  124. package/plugin/skills/commit-context/EXAMPLES.md +71 -0
  125. package/plugin/skills/commit-context/SKILL.md +53 -8
  126. package/plugin/skills/commit-history/EXAMPLES.md +71 -0
  127. package/plugin/skills/commit-history/SKILL.md +51 -9
  128. package/plugin/skills/forget/EXAMPLES.md +75 -0
  129. package/plugin/skills/forget/SKILL.md +57 -14
  130. package/plugin/skills/handoff/EXAMPLES.md +56 -0
  131. package/plugin/skills/handoff/SKILL.md +56 -9
  132. package/plugin/skills/lesson/SKILL.md +64 -0
  133. package/plugin/skills/memory-discipline/SKILL.md +57 -0
  134. package/plugin/skills/recall/EXAMPLES.md +74 -0
  135. package/plugin/skills/recall/SKILL.md +53 -11
  136. package/plugin/skills/recap/EXAMPLES.md +60 -0
  137. package/plugin/skills/recap/SKILL.md +51 -13
  138. package/plugin/skills/remember/EXAMPLES.md +67 -0
  139. package/plugin/skills/remember/SKILL.md +58 -17
  140. package/plugin/skills/session-history/EXAMPLES.md +59 -0
  141. package/plugin/skills/session-history/SKILL.md +54 -11
  142. package/plugin/skills/write-agentmemory-skill/SKILL.md +40 -0
  143. package/dist/connect-bmZ5eqYN.mjs.map +0 -1
  144. package/dist/image-refs-B5Zf_Djo.mjs.map +0 -1
  145. package/dist/image-store-Gpo2mgM9.mjs.map +0 -1
  146. package/dist/rolldown-runtime-twds-ZHy.mjs +0 -14
  147. package/dist/schema-CNiCWzV9.mjs +0 -78
  148. package/dist/schema-CNiCWzV9.mjs.map +0 -1
  149. package/dist/src-MOg2zKJs.mjs.map +0 -1
  150. package/dist/standalone-BORXC71-.mjs.map +0 -1
  151. package/dist/tools-registry-D8XVVPbJ.mjs.map +0 -1
  152. package/dist/version-9DNrRyph.mjs +0 -6
  153. package/dist/version-9DNrRyph.mjs.map +0 -1
  154. package/plugin/scripts/diagnostics.d.mts +0 -17
  155. package/plugin/scripts/diagnostics.d.mts.map +0 -1
  156. package/plugin/scripts/diagnostics.mjs.map +0 -1
@@ -1,9 +1,163 @@
1
- import { t as __exportAll } from "./rolldown-runtime-twds-ZHy.mjs";
1
+ import "node:module";
2
2
  import { copyFileSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
3
3
  import { dirname, join, resolve } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { homedir, platform } from "node:os";
6
6
  import * as p from "@clack/prompts";
7
+ import pc from "picocolors";
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) __defProp(target, name, {
13
+ get: all[name],
14
+ enumerable: true
15
+ });
16
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
17
+ return target;
18
+ };
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
7
161
  //#region src/cli/connect/util.ts
8
162
  const AGENTMEMORY_MCP_BLOCK = {
9
163
  command: "npx",
@@ -64,9 +218,12 @@ function readJsonSafe(path) {
64
218
  }
65
219
  }
66
220
  function writeJsonAtomic(path, value) {
221
+ writeTextAtomic(path, `${JSON.stringify(value, null, 2)}\n`);
222
+ }
223
+ function writeTextAtomic(path, content) {
67
224
  mkdirSync(dirname(path), { recursive: true });
68
225
  const tmp = `${path}.tmp-${process.pid}-${Date.now()}`;
69
- writeFileSync(tmp, `${JSON.stringify(value, null, 2)}\n`, "utf-8");
226
+ writeFileSync(tmp, content, "utf-8");
70
227
  renameSync(tmp, path);
71
228
  }
72
229
  function logInstalled(label, target) {
@@ -80,7 +237,7 @@ function logBackup(target) {
80
237
  }
81
238
  //#endregion
82
239
  //#region src/cli/connect/json-mcp-adapter.ts
83
- function entryMatches$2(entry) {
240
+ function entryMatches$3(entry) {
84
241
  if (!entry || typeof entry !== "object") return false;
85
242
  const e = entry;
86
243
  if (e["command"] !== "npx") return false;
@@ -91,6 +248,7 @@ function createJsonMcpAdapter(config) {
91
248
  return {
92
249
  name: config.name,
93
250
  displayName: config.displayName,
251
+ category: config.category ?? "mcp",
94
252
  ...config.docs !== void 0 && { docs: config.docs },
95
253
  ...config.protocolNote !== void 0 && { protocolNote: config.protocolNote },
96
254
  detect() {
@@ -100,9 +258,13 @@ function createJsonMcpAdapter(config) {
100
258
  const existing = readJsonSafe(config.configPath);
101
259
  const next = existing ? { ...existing } : {};
102
260
  const servers = { ...next[wrapperKey] ?? {} };
103
- const alreadyHas = entryMatches$2(servers["agentmemory"]);
261
+ const alreadyHas = entryMatches$3(servers["agentmemory"]);
104
262
  if (alreadyHas && !opts.force) {
105
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
+ }
106
268
  return {
107
269
  kind: "already-wired",
108
270
  mutatedPath: config.configPath
@@ -110,6 +272,10 @@ function createJsonMcpAdapter(config) {
110
272
  }
111
273
  if (opts.dryRun) {
112
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
+ }
113
279
  return {
114
280
  kind: "installed",
115
281
  mutatedPath: config.configPath
@@ -127,7 +293,7 @@ function createJsonMcpAdapter(config) {
127
293
  next[wrapperKey] = servers;
128
294
  writeJsonAtomic(config.configPath, next);
129
295
  const verifyServers = readJsonSafe(config.configPath)?.[wrapperKey];
130
- if (!entryMatches$2(verifyServers?.["agentmemory"])) {
296
+ if (!entryMatches$3(verifyServers?.["agentmemory"])) {
131
297
  p.log.error(`Verification failed: ${config.configPath} did not contain ${wrapperKey}.agentmemory after write.`);
132
298
  return {
133
299
  kind: "skipped",
@@ -135,6 +301,10 @@ function createJsonMcpAdapter(config) {
135
301
  };
136
302
  }
137
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
+ }
138
308
  return {
139
309
  kind: "installed",
140
310
  mutatedPath: config.configPath,
@@ -146,7 +316,7 @@ function createJsonMcpAdapter(config) {
146
316
  //#endregion
147
317
  //#region src/cli/connect/antigravity.ts
148
318
  const ANTIGRAVITY_DIR = platform() === "darwin" ? join(homedir(), "Library", "Application Support", "Antigravity", "User") : join(homedir(), ".config", "Antigravity", "User");
149
- const adapter$16 = createJsonMcpAdapter({
319
+ const adapter$20 = createJsonMcpAdapter({
150
320
  name: "antigravity",
151
321
  displayName: "Antigravity",
152
322
  detectDir: ANTIGRAVITY_DIR,
@@ -155,6 +325,84 @@ const adapter$16 = createJsonMcpAdapter({
155
325
  protocolNote: "→ Using MCP via mcp_config.json. Antigravity replaces Gemini CLI (sunset 2026-06-18)."
156
326
  });
157
327
  //#endregion
328
+ //#region src/cli/connect/antigravity-hooks.ts
329
+ /** Tool events: `[ { matcher, hooks: [...] } ]`. */
330
+ const TOOL_EVENT_KEYS = new Set(["PreToolUse", "PostToolUse"]);
331
+ /** Lifecycle events: a flat `[ { type, command } ]` handler list. */
332
+ const LIFECYCLE_EVENT_KEYS = new Set([
333
+ "PreInvocation",
334
+ "PostInvocation",
335
+ "Stop"
336
+ ]);
337
+ /** Events Antigravity dispatches. Anything else in a bundle is metadata. */
338
+ const EVENT_KEYS = new Set([...TOOL_EVENT_KEYS, ...LIFECYCLE_EVENT_KEYS]);
339
+ function buildMergedAntigravityHooks(existing, pluginRoot, manifestFile = "hooks.antigravity.json") {
340
+ const ours = JSON.parse(readFileSync(join(pluginRoot, "hooks", manifestFile), "utf-8"));
341
+ const scriptsDir = join(pluginRoot, "scripts");
342
+ const out = {};
343
+ for (const [name, bundle] of Object.entries(existing ?? {})) {
344
+ if (isAgentmemoryBundle(bundle, scriptsDir)) continue;
345
+ out[name] = bundle;
346
+ }
347
+ for (const [name, bundle] of Object.entries(ours)) out[name] = resolveBundle(bundle, pluginRoot);
348
+ return out;
349
+ }
350
+ /** True when `pluginRoot` cannot be expressed in an Antigravity `command`. */
351
+ function containsSpaces(pluginRoot) {
352
+ return /\s/.test(pluginRoot);
353
+ }
354
+ /**
355
+ * Every handler in a bundle, across both event shapes: an entry that carries
356
+ * no `hooks` array is itself the handler.
357
+ */
358
+ function allHandlers(bundle) {
359
+ const out = [];
360
+ for (const [key, value] of Object.entries(bundle)) {
361
+ if (!EVENT_KEYS.has(key) || !Array.isArray(value)) continue;
362
+ for (const entry of value) {
363
+ if (!entry || typeof entry !== "object") continue;
364
+ const nested = entry.hooks;
365
+ if (Array.isArray(nested)) out.push(...nested);
366
+ else out.push(entry);
367
+ }
368
+ }
369
+ return out;
370
+ }
371
+ function isAgentmemoryBundle(bundle, scriptsDir) {
372
+ if (!bundle || typeof bundle !== "object" || Array.isArray(bundle)) return false;
373
+ const normalizedScriptsDir = normalizePathForCommandMatch$1(scriptsDir);
374
+ return allHandlers(bundle).some((handler) => normalizePathForCommandMatch$1(handler?.command ?? "").includes(normalizedScriptsDir));
375
+ }
376
+ function resolveBundle(bundle, pluginRoot) {
377
+ const out = {};
378
+ for (const [key, value] of Object.entries(bundle)) {
379
+ if (!EVENT_KEYS.has(key) || !Array.isArray(value)) {
380
+ out[key] = value;
381
+ continue;
382
+ }
383
+ if (LIFECYCLE_EVENT_KEYS.has(key)) {
384
+ out[key] = value.map((handler) => resolveHandler(handler, pluginRoot));
385
+ continue;
386
+ }
387
+ out[key] = value.map((entry) => {
388
+ const next = { hooks: entry.hooks.map((handler) => resolveHandler(handler, pluginRoot)) };
389
+ if (entry.matcher !== void 0) next.matcher = entry.matcher;
390
+ return next;
391
+ });
392
+ }
393
+ return out;
394
+ }
395
+ function resolveHandler(handler, pluginRoot) {
396
+ return {
397
+ type: handler.type,
398
+ command: handler.command.replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g, () => pluginRoot),
399
+ ...handler.timeout !== void 0 && { timeout: handler.timeout }
400
+ };
401
+ }
402
+ function normalizePathForCommandMatch$1(value) {
403
+ return value.replace(/\\/g, "/");
404
+ }
405
+ //#endregion
158
406
  //#region src/cli/connect/codex-hooks.ts
159
407
  /**
160
408
  * Locate the bundled `plugin/` directory at runtime. Walks up from the
@@ -214,21 +462,78 @@ function normalizePathForCommandMatch(value) {
214
462
  return value.replace(/\\/g, "/");
215
463
  }
216
464
  //#endregion
465
+ //#region src/cli/connect/antigravity-cli.ts
466
+ const GEMINI_DIR = join(homedir(), ".gemini");
467
+ const ANTIGRAVITY_CLI_DIR = join(GEMINI_DIR, "antigravity-cli");
468
+ const CUSTOMIZATION_DIR = join(GEMINI_DIR, "config");
469
+ const ANTIGRAVITY_CLI_HOOKS = join(CUSTOMIZATION_DIR, "hooks.json");
470
+ const adapter$19 = createJsonMcpAdapter({
471
+ name: "antigravity-cli",
472
+ displayName: "Antigravity CLI (agy)",
473
+ detectDir: ANTIGRAVITY_CLI_DIR,
474
+ configPath: join(CUSTOMIZATION_DIR, "mcp_config.json"),
475
+ docs: "https://github.com/rohitg00/agentmemory#other-agents",
476
+ protocolNote: "→ Using MCP via ~/.gemini/config/mcp_config.json (the agy CLI, not the Antigravity IDE — that one is `connect antigravity`). The `/mcp` slash command inside agy lists configured servers. Pass --with-hooks to also install the native ~/.gemini/config/hooks.json auto-capture hooks.",
477
+ installHooks: installAntigravityCliHooks
478
+ });
479
+ /**
480
+ * Merge the bundled `plugin/hooks/hooks.antigravity.json` into
481
+ * `~/.gemini/config/hooks.json`, replacing only the bundle agentmemory owns.
482
+ */
483
+ function installAntigravityCliHooks(opts) {
484
+ let pluginRoot;
485
+ try {
486
+ pluginRoot = findPluginRoot();
487
+ } catch (err) {
488
+ return {
489
+ kind: "skipped",
490
+ reason: err instanceof Error ? err.message : String(err)
491
+ };
492
+ }
493
+ if (containsSpaces(pluginRoot)) return {
494
+ kind: "skipped",
495
+ 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.`
496
+ };
497
+ const existing = readJsonSafe(ANTIGRAVITY_CLI_HOOKS);
498
+ const merged = buildMergedAntigravityHooks(existing, pluginRoot);
499
+ if (opts.dryRun) {
500
+ p.log.info(`[dry-run] Would ${existing ? "merge" : "create"} ${ANTIGRAVITY_CLI_HOOKS} with ${Object.keys(merged).length} hook bundle(s)`);
501
+ return {
502
+ kind: "installed",
503
+ mutatedPath: ANTIGRAVITY_CLI_HOOKS
504
+ };
505
+ }
506
+ let backupPath;
507
+ if (existsSync(ANTIGRAVITY_CLI_HOOKS)) {
508
+ backupPath = backupFile(ANTIGRAVITY_CLI_HOOKS, "antigravity-cli-hooks", "json");
509
+ logBackup(backupPath);
510
+ } else mkdirSync(CUSTOMIZATION_DIR, { recursive: true });
511
+ writeJsonAtomic(ANTIGRAVITY_CLI_HOOKS, merged);
512
+ logInstalled("Antigravity CLI hooks", ANTIGRAVITY_CLI_HOOKS);
513
+ 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.");
514
+ return {
515
+ kind: "installed",
516
+ mutatedPath: ANTIGRAVITY_CLI_HOOKS,
517
+ ...backupPath !== void 0 && { backupPath }
518
+ };
519
+ }
520
+ //#endregion
217
521
  //#region src/cli/connect/claude-code.ts
218
522
  const CLAUDE_DIR = join(homedir(), ".claude");
219
523
  const CLAUDE_JSON = join(homedir(), ".claude.json");
220
524
  const CLAUDE_SETTINGS = join(CLAUDE_DIR, "settings.json");
221
- function entryMatches$1(entry) {
525
+ function entryMatches$2(entry) {
222
526
  if (!entry || typeof entry !== "object") return false;
223
527
  const e = entry;
224
528
  if (e["command"] !== "npx") return false;
225
529
  return (Array.isArray(e["args"]) ? e["args"] : []).includes("@agentmemory/mcp");
226
530
  }
227
- const adapter$15 = {
531
+ const adapter$18 = {
228
532
  name: "claude-code",
229
533
  displayName: "Claude Code",
534
+ category: "native",
230
535
  docs: "https://github.com/rohitg00/agentmemory#claude-code-one-block-paste-it",
231
- protocolNote: "→ Using MCP. Hooks are also available — see docs/claude-code.md.",
536
+ protocolNote: "→ Using MCP. Hooks are also available — see https://github.com/rohitg00/agentmemory#claude-code-one-block-paste-it.",
232
537
  detect() {
233
538
  return existsSync(CLAUDE_DIR);
234
539
  },
@@ -236,7 +541,7 @@ const adapter$15 = {
236
541
  const existing = readJsonSafe(CLAUDE_JSON);
237
542
  const next = existing ? { ...existing } : {};
238
543
  const servers = { ...next.mcpServers ?? {} };
239
- const alreadyHas = entryMatches$1(servers["agentmemory"]);
544
+ const alreadyHas = entryMatches$2(servers["agentmemory"]);
240
545
  if (alreadyHas && !opts.force) {
241
546
  logAlreadyWired("Claude Code", CLAUDE_JSON);
242
547
  if (opts.withHooks) {
@@ -266,7 +571,7 @@ const adapter$15 = {
266
571
  servers["agentmemory"] = AGENTMEMORY_MCP_BLOCK;
267
572
  next.mcpServers = servers;
268
573
  writeJsonAtomic(CLAUDE_JSON, next);
269
- if (!entryMatches$1(readJsonSafe(CLAUDE_JSON)?.mcpServers?.["agentmemory"])) {
574
+ if (!entryMatches$2(readJsonSafe(CLAUDE_JSON)?.mcpServers?.["agentmemory"])) {
270
575
  p.log.error(`Verification failed: ${CLAUDE_JSON} did not contain mcpServers.agentmemory after write.`);
271
576
  return {
272
577
  kind: "skipped",
@@ -335,7 +640,7 @@ function installClaudeHooks(opts) {
335
640
  }
336
641
  //#endregion
337
642
  //#region src/cli/connect/cline.ts
338
- const adapter$14 = createJsonMcpAdapter({
643
+ const adapter$17 = createJsonMcpAdapter({
339
644
  name: "cline",
340
645
  displayName: "Cline",
341
646
  detectDir: join(homedir(), ".cline"),
@@ -347,13 +652,14 @@ const adapter$14 = createJsonMcpAdapter({
347
652
  //#region src/cli/connect/copilot-cli.ts
348
653
  const COPILOT_DIR = process.env["COPILOT_HOME"] || join(homedir(), ".copilot");
349
654
  const COPILOT_MCP_JSON = join(COPILOT_DIR, "mcp-config.json");
350
- function entryMatches(entry) {
655
+ function entryMatches$1(entry) {
351
656
  if (!entry || typeof entry !== "object") return false;
352
657
  return JSON.stringify(entry) === JSON.stringify(AGENTMEMORY_COPILOT_MCP_BLOCK);
353
658
  }
354
- const adapter$13 = {
659
+ const adapter$16 = {
355
660
  name: "copilot-cli",
356
661
  displayName: "GitHub Copilot CLI",
662
+ category: "native",
357
663
  docs: "https://github.com/rohitg00/agentmemory#github-copilot-cli",
358
664
  protocolNote: "→ Using MCP. Install the plugin too for full hooks/skills coverage.",
359
665
  detect() {
@@ -363,7 +669,7 @@ const adapter$13 = {
363
669
  const existing = readJsonSafe(COPILOT_MCP_JSON);
364
670
  const next = existing ? { ...existing } : {};
365
671
  const servers = { ...next.mcpServers ?? {} };
366
- const alreadyHas = entryMatches(servers["agentmemory"]);
672
+ const alreadyHas = entryMatches$1(servers["agentmemory"]);
367
673
  if (alreadyHas && !opts.force) {
368
674
  logAlreadyWired("GitHub Copilot CLI", COPILOT_MCP_JSON);
369
675
  return {
@@ -386,7 +692,7 @@ const adapter$13 = {
386
692
  servers["agentmemory"] = AGENTMEMORY_COPILOT_MCP_BLOCK;
387
693
  next.mcpServers = servers;
388
694
  writeJsonAtomic(COPILOT_MCP_JSON, next);
389
- if (!entryMatches(readJsonSafe(COPILOT_MCP_JSON)?.mcpServers?.["agentmemory"])) {
695
+ if (!entryMatches$1(readJsonSafe(COPILOT_MCP_JSON)?.mcpServers?.["agentmemory"])) {
390
696
  p.log.error(`Verification failed: ${COPILOT_MCP_JSON} did not contain mcpServers.agentmemory after write.`);
391
697
  return {
392
698
  kind: "skipped",
@@ -433,9 +739,10 @@ function stripExistingBlock(toml) {
433
739
  }
434
740
  return out.join("\n").replace(/\n{3,}$/, "\n\n").trimEnd() + "\n";
435
741
  }
436
- const adapter$12 = {
742
+ const adapter$15 = {
437
743
  name: "codex",
438
744
  displayName: "Codex CLI",
745
+ category: "native",
439
746
  docs: "https://github.com/rohitg00/agentmemory#codex-cli-codex-plugin-platform",
440
747
  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.",
441
748
  detect() {
@@ -519,7 +826,8 @@ function installCodexHooks(opts) {
519
826
  }
520
827
  writeJsonAtomic(CODEX_HOOKS, merged);
521
828
  logInstalled("Codex hooks (workaround for openai/codex#16430)", CODEX_HOOKS);
522
- 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.");
829
+ 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.");
830
+ 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.");
523
831
  return {
524
832
  kind: "installed",
525
833
  mutatedPath: CODEX_HOOKS,
@@ -557,9 +865,10 @@ function renderFreshYaml() {
557
865
  ""
558
866
  ].join("\n");
559
867
  }
560
- const adapter$11 = {
868
+ const adapter$14 = {
561
869
  name: "continue",
562
870
  displayName: "Continue",
871
+ category: "mcp",
563
872
  docs: "https://github.com/rohitg00/agentmemory#other-agents",
564
873
  protocolNote: "→ Using MCP via ~/.continue/config.yaml (preferred) or config.json (legacy, only when no yaml).",
565
874
  detect() {
@@ -636,7 +945,7 @@ const adapter$11 = {
636
945
  };
637
946
  //#endregion
638
947
  //#region src/cli/connect/cursor.ts
639
- const adapter$10 = createJsonMcpAdapter({
948
+ const adapter$13 = createJsonMcpAdapter({
640
949
  name: "cursor",
641
950
  displayName: "Cursor",
642
951
  detectDir: join(homedir(), ".cursor"),
@@ -645,19 +954,225 @@ const adapter$10 = createJsonMcpAdapter({
645
954
  protocolNote: "→ Using MCP (the only protocol Cursor speaks). Memory bridge runs at :3111 underneath."
646
955
  });
647
956
  //#endregion
957
+ //#region src/cli/connect/devin.ts
958
+ function devinDir() {
959
+ if (platform() === "win32") {
960
+ const appData = process.env["APPDATA"];
961
+ if (appData) return join(appData, "devin");
962
+ }
963
+ const xdg = process.env["XDG_CONFIG_HOME"];
964
+ return xdg ? join(xdg, "devin") : join(homedir(), ".config", "devin");
965
+ }
966
+ const DEVIN_DIR = devinDir();
967
+ const DEVIN_CONFIG = join(DEVIN_DIR, "config.json");
968
+ const adapter$12 = createJsonMcpAdapter({
969
+ name: "devin",
970
+ displayName: "Devin CLI",
971
+ detectDir: DEVIN_DIR,
972
+ configPath: DEVIN_CONFIG,
973
+ docs: "https://github.com/rohitg00/agentmemory#other-agents",
974
+ 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.",
975
+ installHooks: installDevinHooks
976
+ });
977
+ function installDevinHooks(opts) {
978
+ let pluginRoot;
979
+ try {
980
+ pluginRoot = findPluginRoot();
981
+ } catch (err) {
982
+ return {
983
+ kind: "skipped",
984
+ reason: err instanceof Error ? err.message : String(err)
985
+ };
986
+ }
987
+ const existing = readJsonSafe(DEVIN_CONFIG) ?? {};
988
+ const merged = buildMergedHooks(existing["hooks"] ? { hooks: existing["hooks"] } : null, pluginRoot, "hooks.devin.json");
989
+ const next = {
990
+ ...existing,
991
+ hooks: merged.hooks
992
+ };
993
+ if (opts.dryRun) {
994
+ p.log.info(`[dry-run] Would write ${Object.keys(merged.hooks).length} hook event(s) into ${DEVIN_CONFIG}`);
995
+ return {
996
+ kind: "installed",
997
+ mutatedPath: DEVIN_CONFIG
998
+ };
999
+ }
1000
+ let backupPath;
1001
+ if (existsSync(DEVIN_CONFIG)) {
1002
+ backupPath = backupFile(DEVIN_CONFIG, "devin-hooks", "json");
1003
+ logBackup(backupPath);
1004
+ } else mkdirSync(DEVIN_DIR, { recursive: true });
1005
+ writeJsonAtomic(DEVIN_CONFIG, next);
1006
+ logInstalled("Devin CLI hooks", DEVIN_CONFIG);
1007
+ p.log.info("Verify with `/hooks` inside devin. Re-run `agentmemory connect devin --with-hooks` after upgrading agentmemory so the plugin paths stay current.");
1008
+ return {
1009
+ kind: "installed",
1010
+ mutatedPath: DEVIN_CONFIG,
1011
+ ...backupPath !== void 0 && { backupPath }
1012
+ };
1013
+ }
1014
+ //#endregion
648
1015
  //#region src/cli/connect/droid.ts
649
- const adapter$9 = createJsonMcpAdapter({
1016
+ const DROID_DIR = join(homedir(), ".factory");
1017
+ const DROID_HOOKS = join(DROID_DIR, "hooks.json");
1018
+ const adapter$11 = createJsonMcpAdapter({
650
1019
  name: "droid",
651
1020
  displayName: "Droid (Factory.ai)",
652
- detectDir: join(homedir(), ".factory"),
653
- configPath: join(homedir(), ".factory", "mcp.json"),
1021
+ detectDir: DROID_DIR,
1022
+ configPath: join(DROID_DIR, "mcp.json"),
654
1023
  docs: "https://github.com/rohitg00/agentmemory#other-agents",
655
- protocolNote: "→ Using MCP via ~/.factory/mcp.json. The `/mcp` slash command inside droid lists configured servers.",
656
- extraEntryFields: { type: "stdio" }
1024
+ 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.",
1025
+ extraEntryFields: { type: "stdio" },
1026
+ installHooks: installDroidHooks
657
1027
  });
1028
+ /**
1029
+ * Merge the bundled `plugin/hooks/hooks.droid.json` into
1030
+ * `~/.factory/hooks.json`. Same idempotent merge/strip-by-script-path
1031
+ * behavior as the Codex and Claude Code hook installers: re-running keeps
1032
+ * user-authored hook entries and only replaces the ones agentmemory owns.
1033
+ */
1034
+ function installDroidHooks(opts) {
1035
+ let pluginRoot;
1036
+ try {
1037
+ pluginRoot = findPluginRoot();
1038
+ } catch (err) {
1039
+ return {
1040
+ kind: "skipped",
1041
+ reason: err instanceof Error ? err.message : String(err)
1042
+ };
1043
+ }
1044
+ const existing = readJsonSafe(DROID_HOOKS);
1045
+ const merged = buildMergedHooks(existing, pluginRoot, "hooks.droid.json");
1046
+ if (opts.dryRun) {
1047
+ p.log.info(`[dry-run] Would ${existing ? "merge" : "create"} ${DROID_HOOKS} with ${Object.keys(merged.hooks).length} event(s)`);
1048
+ return {
1049
+ kind: "installed",
1050
+ mutatedPath: DROID_HOOKS
1051
+ };
1052
+ }
1053
+ let backupPath;
1054
+ if (existsSync(DROID_HOOKS)) {
1055
+ backupPath = backupFile(DROID_HOOKS, "droid-hooks", "json");
1056
+ logBackup(backupPath);
1057
+ } else mkdirSync(DROID_DIR, { recursive: true });
1058
+ writeJsonAtomic(DROID_HOOKS, merged);
1059
+ logInstalled("Droid hooks", DROID_HOOKS);
1060
+ 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.");
1061
+ return {
1062
+ kind: "installed",
1063
+ mutatedPath: DROID_HOOKS,
1064
+ ...backupPath !== void 0 && { backupPath }
1065
+ };
1066
+ }
1067
+ //#endregion
1068
+ //#region src/cli/connect/dsh.ts
1069
+ function dshHome() {
1070
+ return process.env["DSH_HOME"] || join(homedir(), ".dsh");
1071
+ }
1072
+ const MCP_BLOCK = `- insert:
1073
+ - id: agentmemory
1074
+ name: '@deepseek-ai/dsh-mcp-client'
1075
+ config:
1076
+ transport: stdio
1077
+ serverName: agentmemory
1078
+ command: npx
1079
+ args: ['-y', '@agentmemory/mcp']
1080
+ env:
1081
+ AGENTMEMORY_URL: http://localhost:3111
1082
+ `;
1083
+ const MCP_MARKER = "serverName: agentmemory";
1084
+ const HOOKS_MARKER = "id: agentmemory-hooks";
1085
+ function hooksBlock(hooksConfigPath) {
1086
+ return `- insert:
1087
+ - id: agentmemory-hooks
1088
+ name: '@deepseek-ai/dsh-hooks-claude-code'
1089
+ config:
1090
+ configPath: ${JSON.stringify(hooksConfigPath)}
1091
+ `;
1092
+ }
1093
+ function stripBlock(content, marker) {
1094
+ if (!content.includes(marker)) return content;
1095
+ const lines = content.split("\n");
1096
+ const markerIdx = lines.findIndex((l) => l.includes(marker));
1097
+ let start = markerIdx;
1098
+ while (start > 0 && !lines[start].startsWith("- ")) start--;
1099
+ let end = markerIdx + 1;
1100
+ while (end < lines.length && !lines[end].startsWith("- ")) end++;
1101
+ return lines.slice(0, start).concat(lines.slice(end)).join("\n").replace(/\n+$/, "\n");
1102
+ }
1103
+ function appendBlock(content, block) {
1104
+ const base = content.replace(/\n+$/, "\n");
1105
+ return base.trim() ? `${base}\n${block}` : block;
1106
+ }
1107
+ function installHooksFile(home) {
1108
+ const hooksPath = join(home, "agentmemory.hooks.json");
1109
+ const pluginRoot = findPluginRoot();
1110
+ writeJsonAtomic(hooksPath, buildMergedHooks(readJsonSafe(hooksPath), pluginRoot, "hooks.codex.json"));
1111
+ return hooksPath;
1112
+ }
1113
+ const adapter$10 = {
1114
+ name: "dsh",
1115
+ displayName: "DeepSeek Harness",
1116
+ docs: "https://github.com/rohitg00/agentmemory#other-agents",
1117
+ 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.",
1118
+ category: "native",
1119
+ detect() {
1120
+ return existsSync(dshHome());
1121
+ },
1122
+ async install(opts) {
1123
+ const home = dshHome();
1124
+ const configPath = join(home, "cordis.patch.yml");
1125
+ const existing = existsSync(configPath) ? readFileSync(configPath, "utf-8") : "";
1126
+ const wantHooks = opts.withHooks === true;
1127
+ const hasMcp = existing.includes(MCP_MARKER);
1128
+ const hasHooks = existing.includes(HOOKS_MARKER);
1129
+ if (hasMcp && (!wantHooks || hasHooks) && !opts.force) {
1130
+ logAlreadyWired(this.displayName, configPath);
1131
+ return {
1132
+ kind: "already-wired",
1133
+ mutatedPath: configPath
1134
+ };
1135
+ }
1136
+ if (opts.dryRun) {
1137
+ p.log.info(`[dry-run] Would append the agentmemory mcp-client row${wantHooks ? " and the hooks-claude-code row" : ""} to ${configPath}`);
1138
+ return {
1139
+ kind: "installed",
1140
+ mutatedPath: configPath
1141
+ };
1142
+ }
1143
+ let backupPath;
1144
+ if (existsSync(configPath)) {
1145
+ backupPath = backupFile(configPath, this.name, "yml");
1146
+ logBackup(backupPath);
1147
+ } else mkdirSync(dirname(configPath), { recursive: true });
1148
+ let next = stripBlock(existing, MCP_MARKER);
1149
+ next = appendBlock(next, MCP_BLOCK);
1150
+ if (wantHooks) {
1151
+ const hooksPath = installHooksFile(home);
1152
+ next = stripBlock(next, HOOKS_MARKER);
1153
+ next = appendBlock(next, hooksBlock(hooksPath));
1154
+ p.log.info(`Hook manifest: ${hooksPath}`);
1155
+ }
1156
+ writeTextAtomic(configPath, next);
1157
+ const written = readFileSync(configPath, "utf-8");
1158
+ if (!written.includes(MCP_MARKER) || wantHooks && !written.includes(HOOKS_MARKER)) {
1159
+ p.log.error(`Verification failed: ${configPath} did not contain the agentmemory rows after write.`);
1160
+ return {
1161
+ kind: "skipped",
1162
+ reason: "verification-failed"
1163
+ };
1164
+ }
1165
+ logInstalled(this.displayName, configPath);
1166
+ return {
1167
+ kind: "installed",
1168
+ mutatedPath: configPath,
1169
+ backupPath
1170
+ };
1171
+ }
1172
+ };
658
1173
  //#endregion
659
1174
  //#region src/cli/connect/gemini-cli.ts
660
- const adapter$8 = createJsonMcpAdapter({
1175
+ const adapter$9 = createJsonMcpAdapter({
661
1176
  name: "gemini-cli",
662
1177
  displayName: "Gemini CLI",
663
1178
  detectDir: join(homedir(), ".gemini"),
@@ -670,11 +1185,12 @@ const adapter$8 = createJsonMcpAdapter({
670
1185
  const HERMES_DIR = join(homedir(), ".hermes");
671
1186
  const HERMES_CONFIG = join(HERMES_DIR, "config.yaml");
672
1187
  const DOCS$2 = "https://github.com/rohitg00/agentmemory/tree/main/integrations/hermes";
673
- const adapter$7 = {
1188
+ const adapter$8 = {
674
1189
  name: "hermes",
675
1190
  displayName: "Hermes Agent",
1191
+ category: "native",
676
1192
  docs: DOCS$2,
677
- protocolNote: "→ Using MCP. Hooks are also available — see docs/hermes.md.",
1193
+ protocolNote: "→ Using MCP. Hooks are also available — see https://github.com/rohitg00/agentmemory/tree/main/integrations/hermes.",
678
1194
  detect() {
679
1195
  return existsSync(HERMES_DIR);
680
1196
  },
@@ -701,7 +1217,7 @@ const adapter$7 = {
701
1217
  };
702
1218
  //#endregion
703
1219
  //#region src/cli/connect/kiro.ts
704
- const adapter$6 = createJsonMcpAdapter({
1220
+ const adapter$7 = createJsonMcpAdapter({
705
1221
  name: "kiro",
706
1222
  displayName: "Kiro",
707
1223
  detectDir: join(homedir(), ".kiro"),
@@ -711,21 +1227,94 @@ const adapter$6 = createJsonMcpAdapter({
711
1227
  });
712
1228
  //#endregion
713
1229
  //#region src/cli/connect/openclaw.ts
714
- const adapter$5 = createJsonMcpAdapter({
1230
+ const adapter$6 = createJsonMcpAdapter({
715
1231
  name: "openclaw",
716
1232
  displayName: "OpenClaw",
1233
+ category: "native",
717
1234
  detectDir: join(homedir(), ".openclaw"),
718
1235
  configPath: join(homedir(), ".openclaw", "openclaw.json"),
719
1236
  docs: "https://github.com/rohitg00/agentmemory/tree/main/integrations/openclaw",
720
- protocolNote: "→ Using MCP. Hooks are also available — see docs/openclaw.md."
1237
+ protocolNote: "→ Using MCP. Hooks are also available — see https://github.com/rohitg00/agentmemory/tree/main/integrations/openclaw."
721
1238
  });
722
1239
  //#endregion
1240
+ //#region src/cli/connect/opencode.ts
1241
+ const CONFIG_PATH = join(homedir(), ".config", "opencode", "opencode.json");
1242
+ const DETECT_DIR = join(homedir(), ".config", "opencode");
1243
+ const OPENCODE_ENTRY = {
1244
+ type: "local",
1245
+ command: [
1246
+ "npx",
1247
+ "-y",
1248
+ "@agentmemory/mcp"
1249
+ ],
1250
+ enabled: true
1251
+ };
1252
+ function entryMatches(entry) {
1253
+ if (!entry || typeof entry !== "object") return false;
1254
+ const command = entry["command"];
1255
+ return Array.isArray(command) && command.includes("@agentmemory/mcp");
1256
+ }
1257
+ const adapter$5 = {
1258
+ name: "opencode",
1259
+ displayName: "OpenCode",
1260
+ category: "mcp",
1261
+ docs: "https://github.com/rohitg00/agentmemory#other-agents",
1262
+ protocolNote: "Using MCP via ~/.config/opencode/opencode.json (top-level `mcp` key). For full auto-capture, also install the bundled plugin in plugin/opencode/.",
1263
+ detect() {
1264
+ return existsSync(DETECT_DIR);
1265
+ },
1266
+ async install(opts) {
1267
+ const existing = readJsonSafe(CONFIG_PATH);
1268
+ const next = existing ? { ...existing } : {};
1269
+ const existingMcp = next["mcp"];
1270
+ const mcp = existingMcp && typeof existingMcp === "object" && !Array.isArray(existingMcp) ? { ...existingMcp } : {};
1271
+ const alreadyHas = entryMatches(mcp["agentmemory"]);
1272
+ if (alreadyHas && !opts.force) {
1273
+ logAlreadyWired(this.displayName, CONFIG_PATH);
1274
+ return {
1275
+ kind: "already-wired",
1276
+ mutatedPath: CONFIG_PATH
1277
+ };
1278
+ }
1279
+ if (opts.dryRun) {
1280
+ p.log.info(`[dry-run] Would ${alreadyHas ? "overwrite" : "add"} mcp.agentmemory in ${CONFIG_PATH}`);
1281
+ return {
1282
+ kind: "installed",
1283
+ mutatedPath: CONFIG_PATH
1284
+ };
1285
+ }
1286
+ let backupPath;
1287
+ if (existsSync(CONFIG_PATH)) {
1288
+ backupPath = backupFile(CONFIG_PATH, this.name);
1289
+ logBackup(backupPath);
1290
+ } else mkdirSync(dirname(CONFIG_PATH), { recursive: true });
1291
+ mcp["agentmemory"] = { ...OPENCODE_ENTRY };
1292
+ next["mcp"] = mcp;
1293
+ writeJsonAtomic(CONFIG_PATH, next);
1294
+ const verifyMcp = readJsonSafe(CONFIG_PATH)?.["mcp"];
1295
+ if (!entryMatches(verifyMcp?.["agentmemory"])) {
1296
+ p.log.error(`Verification failed: ${CONFIG_PATH} did not contain mcp.agentmemory after write.`);
1297
+ return {
1298
+ kind: "skipped",
1299
+ reason: "verification-failed"
1300
+ };
1301
+ }
1302
+ logInstalled(this.displayName, CONFIG_PATH);
1303
+ return {
1304
+ kind: "installed",
1305
+ mutatedPath: CONFIG_PATH,
1306
+ ...backupPath !== void 0 && { backupPath }
1307
+ };
1308
+ }
1309
+ };
1310
+ //#endregion
723
1311
  //#region src/cli/connect/openhuman.ts
724
1312
  const OPENHUMAN_DIR = join(homedir(), ".openhuman");
725
1313
  const DOCS$1 = "https://github.com/tinyhumansai/openhuman";
726
1314
  const adapter$4 = {
727
1315
  name: "openhuman",
728
1316
  displayName: "OpenHuman",
1317
+ category: "native",
729
1318
  docs: DOCS$1,
730
1319
  protocolNote: "→ Using native hooks (REST API at :3111). MCP not required.",
731
1320
  detect() {
@@ -752,31 +1341,75 @@ const adapter$4 = {
752
1341
  const PI_DIR = join(homedir(), ".pi");
753
1342
  const PI_EXT_DIR = join(PI_DIR, "agent", "extensions", "agentmemory");
754
1343
  const DOCS = "https://github.com/rohitg00/agentmemory/tree/main/integrations/pi";
1344
+ const EXT_FILES = ["index.ts", "security.ts"];
1345
+ function findPiSourceDir() {
1346
+ let packageRoot;
1347
+ try {
1348
+ packageRoot = dirname(findPluginRoot());
1349
+ } catch {
1350
+ return null;
1351
+ }
1352
+ const dir = join(packageRoot, "integrations", "pi");
1353
+ return EXT_FILES.every((f) => existsSync(join(dir, f))) ? dir : null;
1354
+ }
755
1355
  const adapter$3 = {
756
1356
  name: "pi",
757
1357
  displayName: "pi",
1358
+ category: "native",
758
1359
  docs: DOCS,
759
- protocolNote: "→ Using native hooks (REST API at :3111). MCP not required.",
1360
+ protocolNote: "→ Using native lifecycle hooks against the REST API at :3111 (recall on agent start, capture on agent end, memory tools). MCP not required.",
760
1361
  detect() {
761
1362
  return existsSync(PI_DIR);
762
1363
  },
763
- async install(_opts) {
764
- p.log.warn("pi uses a TypeScript extension file. Automated copy + register isn't implemented yet — manual install required.");
765
- p.note([
766
- "Run these from the agentmemory repo root:",
767
- "",
768
- ` mkdir -p ${PI_EXT_DIR}`,
769
- ` cp integrations/pi/index.ts ${PI_EXT_DIR}/index.ts`,
770
- ` cp integrations/pi/security.ts ${PI_EXT_DIR}/security.ts`,
771
- "",
772
- "Then add to ~/.pi/agent/settings.json:",
773
- " { \"extensions\": [\"~/.pi/agent/extensions/agentmemory\"] }",
774
- "",
775
- `Full guide: ${DOCS}`
776
- ].join("\n"), "pi manual install");
1364
+ async install(opts) {
1365
+ const sourceDir = findPiSourceDir();
1366
+ if (!sourceDir) {
1367
+ p.log.error("Bundled pi extension not found (integrations/pi missing from the install) — reinstall agentmemory.");
1368
+ return {
1369
+ kind: "skipped",
1370
+ reason: "bundled-extension-missing"
1371
+ };
1372
+ }
1373
+ const sources = EXT_FILES.map((f) => ({
1374
+ name: f,
1375
+ content: readFileSync(join(sourceDir, f), "utf-8"),
1376
+ target: join(PI_EXT_DIR, f)
1377
+ }));
1378
+ if (sources.every((s) => existsSync(s.target) && readFileSync(s.target, "utf-8") === s.content) && !opts.force) {
1379
+ logAlreadyWired(this.displayName, PI_EXT_DIR);
1380
+ return {
1381
+ kind: "already-wired",
1382
+ mutatedPath: PI_EXT_DIR
1383
+ };
1384
+ }
1385
+ if (opts.dryRun) {
1386
+ p.log.info(`[dry-run] Would install the pi extension (${EXT_FILES.join(", ")}) into ${PI_EXT_DIR}`);
1387
+ return {
1388
+ kind: "installed",
1389
+ mutatedPath: PI_EXT_DIR
1390
+ };
1391
+ }
1392
+ let backupPath;
1393
+ for (const s of sources) if (existsSync(s.target) && readFileSync(s.target, "utf-8") !== s.content) {
1394
+ const backup = backupFile(s.target, `${this.name}-${s.name.replace(/\.ts$/, "")}`, "ts");
1395
+ logBackup(backup);
1396
+ backupPath ??= backup;
1397
+ }
1398
+ mkdirSync(PI_EXT_DIR, { recursive: true });
1399
+ for (const s of sources) writeTextAtomic(s.target, s.content);
1400
+ if (!sources.every((s) => existsSync(s.target) && readFileSync(s.target, "utf-8") === s.content)) {
1401
+ p.log.error(`Verification failed: ${PI_EXT_DIR} does not match the bundled extension.`);
1402
+ return {
1403
+ kind: "skipped",
1404
+ reason: "verification-failed"
1405
+ };
1406
+ }
1407
+ logInstalled(this.displayName, PI_EXT_DIR);
1408
+ p.log.info("pi auto-discovers the extension on next launch; a running pi picks it up with /reload. Verify with /agentmemory-status.");
777
1409
  return {
778
- kind: "stub",
779
- reason: "ts-extension-copy-not-implemented"
1410
+ kind: "installed",
1411
+ mutatedPath: PI_EXT_DIR,
1412
+ backupPath
780
1413
  };
781
1414
  }
782
1415
  };
@@ -822,21 +1455,25 @@ var connect_exports = /* @__PURE__ */ __exportAll({
822
1455
  runConnect: () => runConnect
823
1456
  });
824
1457
  const ADAPTERS = [
1458
+ adapter$18,
1459
+ adapter$16,
825
1460
  adapter$15,
826
1461
  adapter$13,
827
1462
  adapter$12,
828
- adapter$10,
829
- adapter$8,
1463
+ adapter$9,
830
1464
  adapter$2,
831
- adapter$16,
832
- adapter$6,
1465
+ adapter$20,
1466
+ adapter$19,
1467
+ adapter$7,
833
1468
  adapter$1,
1469
+ adapter$17,
834
1470
  adapter$14,
835
- adapter$11,
836
1471
  adapter,
837
- adapter$9,
1472
+ adapter$11,
1473
+ adapter$10,
838
1474
  adapter$5,
839
- adapter$7,
1475
+ adapter$6,
1476
+ adapter$8,
840
1477
  adapter$3,
841
1478
  adapter$4
842
1479
  ];
@@ -853,16 +1490,19 @@ function parseFlags(args) {
853
1490
  let force = false;
854
1491
  let all = false;
855
1492
  let withHooks = false;
1493
+ let guidelines = true;
856
1494
  for (const a of args) if (a === "--dry-run") dryRun = true;
857
1495
  else if (a === "--force") force = true;
858
1496
  else if (a === "--all") all = true;
859
1497
  else if (a === "--with-hooks") withHooks = true;
1498
+ else if (a === "--no-guidelines") guidelines = false;
860
1499
  else if (!a.startsWith("-")) positional.push(a);
861
1500
  return {
862
1501
  dryRun,
863
1502
  force,
864
1503
  all,
865
1504
  withHooks,
1505
+ guidelines,
866
1506
  positional
867
1507
  };
868
1508
  }
@@ -877,7 +1517,18 @@ async function runAdapter(adapter, opts) {
877
1517
  p.log.step(`Wiring ${adapter.displayName}…`);
878
1518
  if (adapter.protocolNote) p.log.message(adapter.protocolNote);
879
1519
  try {
880
- return await adapter.install(opts);
1520
+ const result = await adapter.install(opts);
1521
+ if (opts.guidelines !== false && (result.kind === "installed" || result.kind === "already-wired")) try {
1522
+ const g = writeGuideline(adapter.name, {
1523
+ cwd: process.cwd(),
1524
+ dryRun: opts.dryRun
1525
+ });
1526
+ if (g.kind === "written") p.log.message(` ${pc.dim("guideline")} ${g.scope} → ${g.path} (memory auto-use)`);
1527
+ else if (g.kind === "would-write") p.log.message(` ${pc.dim("[dry-run] guideline")} → ${g.path}`);
1528
+ } catch (gerr) {
1529
+ p.log.warn(`${adapter.displayName}: guideline not written (${gerr instanceof Error ? gerr.message : String(gerr)})`);
1530
+ }
1531
+ return result;
881
1532
  } catch (err) {
882
1533
  p.log.error(`${adapter.displayName}: ${err instanceof Error ? err.message : String(err)}`);
883
1534
  return {
@@ -887,7 +1538,7 @@ async function runAdapter(adapter, opts) {
887
1538
  }
888
1539
  }
889
1540
  async function runConnect(args) {
890
- const { dryRun, force, all, withHooks, positional } = parseFlags(args);
1541
+ const { dryRun, force, all, withHooks, guidelines, positional } = parseFlags(args);
891
1542
  const allowWindowsAdapter = positional.length === 1 && positional[0]?.toLowerCase() === "copilot-cli";
892
1543
  if (platform() === "win32" && !allowWindowsAdapter) {
893
1544
  p.intro("agentmemory connect");
@@ -898,7 +1549,8 @@ async function runConnect(args) {
898
1549
  const opts = {
899
1550
  dryRun,
900
1551
  force,
901
- withHooks
1552
+ withHooks,
1553
+ guidelines
902
1554
  };
903
1555
  p.intro("agentmemory connect");
904
1556
  if (positional.length === 0 && !all) {
@@ -963,19 +1615,19 @@ async function runConnect(args) {
963
1615
  function summarize(results) {
964
1616
  const lines = results.map(({ name, result }) => {
965
1617
  switch (result.kind) {
966
- case "installed": return ` ✓ ${name}${result.mutatedPath ? ` → ${result.mutatedPath}` : ""}`;
967
- case "already-wired": return ` ✓ ${name} (already wired)`;
968
- case "stub": return ` ⚠ ${name} (manual install required: ${result.reason})`;
969
- case "skipped": return ` ✗ ${name} (skipped: ${result.reason})`;
1618
+ case "installed": return ` ${pc.green("✓")} ${pc.bold(name)}${result.mutatedPath ? ` ${pc.dim("→")} ${pc.cyan(result.mutatedPath)}` : ""}`;
1619
+ case "already-wired": return ` ${pc.green("✓")} ${pc.bold(name)} ${pc.dim("(already wired)")}`;
1620
+ case "stub": return ` ${pc.yellow("⚠")} ${pc.bold(name)} ${pc.yellow(`(manual install required: ${result.reason})`)}`;
1621
+ case "skipped": return ` ${pc.red("✗")} ${pc.bold(name)} ${pc.dim(`(skipped: ${result.reason})`)}`;
970
1622
  }
971
1623
  });
972
1624
  p.note(lines.join("\n"), "summary");
973
1625
  const stubs = results.filter((r) => r.result.kind === "stub");
974
1626
  if (stubs.length > 0) p.log.info(`${stubs.length} agent(s) require manual install — see docs links above.`);
975
- 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");
1627
+ 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");
976
1628
  p.outro("Restart any wired agent (or open a new session) to pick up agentmemory.");
977
1629
  }
978
1630
  //#endregion
979
- export { resolveAdapter as n, runAdapter as r, connect_exports as t };
1631
+ export { runAdapter as a, resolveAdapter as i, connect_exports as n, knownAgents as r, ADAPTERS as t };
980
1632
 
981
- //# sourceMappingURL=connect-bmZ5eqYN.mjs.map
1633
+ //# sourceMappingURL=connect-Qaeq15TQ.mjs.map