@agentmemory/agentmemory 0.9.29 → 0.9.31

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 (352) hide show
  1. package/.env.example +102 -35
  2. package/AGENTS.md +19 -26
  3. package/README.md +417 -525
  4. package/dist/.env.example +102 -35
  5. package/dist/cli.d.mts.map +1 -1
  6. package/dist/cli.mjs +2316 -655
  7. package/dist/cli.mjs.map +1 -1
  8. package/dist/compression-recovery-CnhLQC6N.mjs +5912 -0
  9. package/dist/compression-recovery-CnhLQC6N.mjs.map +1 -0
  10. package/dist/{connect-Qaeq15TQ.mjs → connect-BSLIAMpw.mjs} +900 -302
  11. package/dist/connect-BSLIAMpw.mjs.map +1 -0
  12. package/dist/hooks/_capture.d.mts +25 -0
  13. package/dist/hooks/_capture.d.mts.map +1 -0
  14. package/dist/hooks/_capture.mjs +944 -0
  15. package/dist/hooks/_capture.mjs.map +1 -0
  16. package/dist/hooks/antigravity-bridge.d.mts +1 -1
  17. package/dist/hooks/antigravity-bridge.d.mts.map +1 -1
  18. package/dist/hooks/antigravity-bridge.mjs +24 -15
  19. package/dist/hooks/antigravity-bridge.mjs.map +1 -1
  20. package/dist/hooks/notification.mjs +35 -29
  21. package/dist/hooks/notification.mjs.map +1 -1
  22. package/dist/hooks/post-commit.mjs +91 -1
  23. package/dist/hooks/post-commit.mjs.map +1 -1
  24. package/dist/hooks/post-tool-failure.mjs +71 -29
  25. package/dist/hooks/post-tool-failure.mjs.map +1 -1
  26. package/dist/hooks/post-tool-use.mjs +99 -39
  27. package/dist/hooks/post-tool-use.mjs.map +1 -1
  28. package/dist/hooks/pre-compact.mjs +113 -6
  29. package/dist/hooks/pre-compact.mjs.map +1 -1
  30. package/dist/hooks/pre-tool-use.mjs +91 -1
  31. package/dist/hooks/pre-tool-use.mjs.map +1 -1
  32. package/dist/hooks/prompt-submit.mjs +25 -25
  33. package/dist/hooks/prompt-submit.mjs.map +1 -1
  34. package/dist/hooks/session-end.mjs +67 -31
  35. package/dist/hooks/session-end.mjs.map +1 -1
  36. package/dist/hooks/session-start.mjs +110 -6
  37. package/dist/hooks/session-start.mjs.map +1 -1
  38. package/dist/hooks/stop.mjs +80 -8
  39. package/dist/hooks/stop.mjs.map +1 -1
  40. package/dist/hooks/subagent-start.mjs +28 -29
  41. package/dist/hooks/subagent-start.mjs.map +1 -1
  42. package/dist/hooks/subagent-stop.mjs +33 -29
  43. package/dist/hooks/subagent-stop.mjs.map +1 -1
  44. package/dist/hooks/task-completed.mjs +31 -31
  45. package/dist/hooks/task-completed.mjs.map +1 -1
  46. package/dist/{image-refs-BKLmp_sD.mjs → image-refs-BaT-9oMU.mjs} +2 -2
  47. package/dist/image-refs-BaT-9oMU.mjs.map +1 -0
  48. package/dist/{image-refs-CJgZmb9X.mjs → image-refs-Cyta4Lf9.mjs} +3 -3
  49. package/dist/image-refs-Cyta4Lf9.mjs.map +1 -0
  50. package/dist/{keyed-mutex-DTHtcZrt.mjs → image-store-BsN4vyjr.mjs} +2 -14
  51. package/dist/image-store-BsN4vyjr.mjs.map +1 -0
  52. package/dist/index.mjs +15180 -4119
  53. package/dist/index.mjs.map +1 -1
  54. package/dist/integrations/dsh.d.mts +55 -0
  55. package/dist/integrations/dsh.d.mts.map +1 -0
  56. package/dist/integrations/dsh.mjs +1145 -0
  57. package/dist/integrations/dsh.mjs.map +1 -0
  58. package/dist/{schema-BFZhNTF7.mjs → keyed-mutex-DCUh7PG-.mjs} +81 -8
  59. package/dist/keyed-mutex-DCUh7PG-.mjs.map +1 -0
  60. package/dist/secret-store-D9GwO0xp.mjs +2449 -0
  61. package/dist/secret-store-D9GwO0xp.mjs.map +1 -0
  62. package/dist/session-arguments-zxsbbd8y.mjs +113 -0
  63. package/dist/session-arguments-zxsbbd8y.mjs.map +1 -0
  64. package/dist/{src-G7yt8gGm.mjs → src-DaMtDzt_.mjs} +8320 -4260
  65. package/dist/src-DaMtDzt_.mjs.map +1 -0
  66. package/dist/{standalone-BqNJDJ04.mjs → standalone-BlqshyZ5.mjs} +246 -62
  67. package/dist/standalone-BlqshyZ5.mjs.map +1 -0
  68. package/dist/standalone.d.mts +1 -1
  69. package/dist/standalone.d.mts.map +1 -1
  70. package/dist/standalone.mjs +866 -78
  71. package/dist/standalone.mjs.map +1 -1
  72. package/dist/viewer/index.html +7394 -2816
  73. package/integrations/hermes/README.md +84 -0
  74. package/integrations/hermes/__init__.py +669 -0
  75. package/integrations/hermes/plugin.yaml +27 -0
  76. package/integrations/omp/LICENSE +190 -0
  77. package/integrations/omp/README.md +76 -0
  78. package/integrations/omp/capture.ts +1 -0
  79. package/integrations/omp/dist/index.mjs +1450 -0
  80. package/integrations/omp/index.ts +488 -0
  81. package/integrations/omp/package.json +13 -0
  82. package/integrations/omp/security.ts +67 -0
  83. package/integrations/omp/skills/agentmemory-agents/REFERENCE.md +32 -0
  84. package/integrations/omp/skills/agentmemory-agents/SKILL.md +48 -0
  85. package/integrations/omp/skills/agentmemory-agents/TROUBLESHOOTING.md +70 -0
  86. package/integrations/omp/skills/agentmemory-architecture/SKILL.md +33 -0
  87. package/integrations/omp/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
  88. package/integrations/omp/skills/agentmemory-config/REFERENCE.md +90 -0
  89. package/integrations/omp/skills/agentmemory-config/SKILL.md +78 -0
  90. package/integrations/omp/skills/agentmemory-config/TROUBLESHOOTING.md +70 -0
  91. package/integrations/omp/skills/agentmemory-hooks/REFERENCE.md +20 -0
  92. package/integrations/omp/skills/agentmemory-hooks/SKILL.md +49 -0
  93. package/integrations/omp/skills/agentmemory-hooks/TROUBLESHOOTING.md +70 -0
  94. package/integrations/omp/skills/agentmemory-mcp-tools/REFERENCE.md +66 -0
  95. package/integrations/omp/skills/agentmemory-mcp-tools/SKILL.md +42 -0
  96. package/integrations/omp/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
  97. package/integrations/omp/skills/agentmemory-rest-api/REFERENCE.md +158 -0
  98. package/integrations/omp/skills/agentmemory-rest-api/SKILL.md +49 -0
  99. package/integrations/omp/skills/agentmemory-rest-api/TROUBLESHOOTING.md +70 -0
  100. package/integrations/omp/skills/commit-context/EXAMPLES.md +71 -0
  101. package/integrations/omp/skills/commit-context/SKILL.md +64 -0
  102. package/integrations/omp/skills/commit-context/TROUBLESHOOTING.md +70 -0
  103. package/integrations/omp/skills/commit-history/EXAMPLES.md +71 -0
  104. package/integrations/omp/skills/commit-history/SKILL.md +62 -0
  105. package/integrations/omp/skills/commit-history/TROUBLESHOOTING.md +70 -0
  106. package/integrations/omp/skills/forget/EXAMPLES.md +40 -0
  107. package/integrations/omp/skills/forget/SKILL.md +73 -0
  108. package/integrations/omp/skills/forget/TROUBLESHOOTING.md +70 -0
  109. package/integrations/omp/skills/handoff/EXAMPLES.md +57 -0
  110. package/integrations/omp/skills/handoff/SKILL.md +75 -0
  111. package/integrations/omp/skills/handoff/TROUBLESHOOTING.md +70 -0
  112. package/integrations/omp/skills/lesson/SKILL.md +64 -0
  113. package/integrations/omp/skills/lesson/TROUBLESHOOTING.md +70 -0
  114. package/integrations/omp/skills/memory-discipline/SKILL.md +65 -0
  115. package/integrations/omp/skills/memory-discipline/TROUBLESHOOTING.md +70 -0
  116. package/integrations/omp/skills/recall/EXAMPLES.md +74 -0
  117. package/integrations/omp/skills/recall/SKILL.md +74 -0
  118. package/integrations/omp/skills/recall/TROUBLESHOOTING.md +70 -0
  119. package/integrations/omp/skills/recap/EXAMPLES.md +62 -0
  120. package/integrations/omp/skills/recap/SKILL.md +68 -0
  121. package/integrations/omp/skills/recap/TROUBLESHOOTING.md +70 -0
  122. package/integrations/omp/skills/remember/EXAMPLES.md +67 -0
  123. package/integrations/omp/skills/remember/SKILL.md +66 -0
  124. package/integrations/omp/skills/remember/TROUBLESHOOTING.md +70 -0
  125. package/integrations/omp/skills/session-history/EXAMPLES.md +59 -0
  126. package/integrations/omp/skills/session-history/SKILL.md +67 -0
  127. package/integrations/omp/skills/session-history/TROUBLESHOOTING.md +70 -0
  128. package/integrations/omp/skills/write-agentmemory-skill/SKILL.md +41 -0
  129. package/integrations/omp/skills/write-agentmemory-skill/TROUBLESHOOTING.md +70 -0
  130. package/integrations/openclaw/LICENSE +190 -0
  131. package/integrations/openclaw/README.md +88 -0
  132. package/integrations/openclaw/openclaw.plugin.json +71 -0
  133. package/integrations/openclaw/package.json +38 -0
  134. package/integrations/openclaw/plugin.mjs +425 -0
  135. package/integrations/openclaw/plugin.yaml +26 -0
  136. package/integrations/openclaw/skills/agentmemory-agents/REFERENCE.md +32 -0
  137. package/integrations/openclaw/skills/agentmemory-agents/SKILL.md +48 -0
  138. package/integrations/openclaw/skills/agentmemory-agents/TROUBLESHOOTING.md +70 -0
  139. package/integrations/openclaw/skills/agentmemory-architecture/SKILL.md +33 -0
  140. package/integrations/openclaw/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
  141. package/integrations/openclaw/skills/agentmemory-config/REFERENCE.md +90 -0
  142. package/integrations/openclaw/skills/agentmemory-config/SKILL.md +78 -0
  143. package/integrations/openclaw/skills/agentmemory-config/TROUBLESHOOTING.md +70 -0
  144. package/integrations/openclaw/skills/agentmemory-hooks/REFERENCE.md +20 -0
  145. package/integrations/openclaw/skills/agentmemory-hooks/SKILL.md +49 -0
  146. package/integrations/openclaw/skills/agentmemory-hooks/TROUBLESHOOTING.md +70 -0
  147. package/integrations/openclaw/skills/agentmemory-mcp-tools/REFERENCE.md +66 -0
  148. package/integrations/openclaw/skills/agentmemory-mcp-tools/SKILL.md +42 -0
  149. package/integrations/openclaw/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
  150. package/integrations/openclaw/skills/agentmemory-rest-api/REFERENCE.md +158 -0
  151. package/integrations/openclaw/skills/agentmemory-rest-api/SKILL.md +49 -0
  152. package/integrations/openclaw/skills/agentmemory-rest-api/TROUBLESHOOTING.md +70 -0
  153. package/integrations/openclaw/skills/commit-context/EXAMPLES.md +71 -0
  154. package/integrations/openclaw/skills/commit-context/SKILL.md +64 -0
  155. package/integrations/openclaw/skills/commit-context/TROUBLESHOOTING.md +70 -0
  156. package/integrations/openclaw/skills/commit-history/EXAMPLES.md +71 -0
  157. package/integrations/openclaw/skills/commit-history/SKILL.md +62 -0
  158. package/integrations/openclaw/skills/commit-history/TROUBLESHOOTING.md +70 -0
  159. package/integrations/openclaw/skills/forget/EXAMPLES.md +40 -0
  160. package/integrations/openclaw/skills/forget/SKILL.md +73 -0
  161. package/integrations/openclaw/skills/forget/TROUBLESHOOTING.md +70 -0
  162. package/integrations/openclaw/skills/handoff/EXAMPLES.md +57 -0
  163. package/integrations/openclaw/skills/handoff/SKILL.md +75 -0
  164. package/integrations/openclaw/skills/handoff/TROUBLESHOOTING.md +70 -0
  165. package/integrations/openclaw/skills/lesson/SKILL.md +64 -0
  166. package/integrations/openclaw/skills/lesson/TROUBLESHOOTING.md +70 -0
  167. package/integrations/openclaw/skills/memory-discipline/SKILL.md +65 -0
  168. package/integrations/openclaw/skills/memory-discipline/TROUBLESHOOTING.md +70 -0
  169. package/integrations/openclaw/skills/recall/EXAMPLES.md +74 -0
  170. package/integrations/openclaw/skills/recall/SKILL.md +74 -0
  171. package/integrations/openclaw/skills/recall/TROUBLESHOOTING.md +70 -0
  172. package/integrations/openclaw/skills/recap/EXAMPLES.md +62 -0
  173. package/integrations/openclaw/skills/recap/SKILL.md +68 -0
  174. package/integrations/openclaw/skills/recap/TROUBLESHOOTING.md +70 -0
  175. package/integrations/openclaw/skills/remember/EXAMPLES.md +67 -0
  176. package/integrations/openclaw/skills/remember/SKILL.md +66 -0
  177. package/integrations/openclaw/skills/remember/TROUBLESHOOTING.md +70 -0
  178. package/integrations/openclaw/skills/session-history/EXAMPLES.md +59 -0
  179. package/integrations/openclaw/skills/session-history/SKILL.md +67 -0
  180. package/integrations/openclaw/skills/session-history/TROUBLESHOOTING.md +70 -0
  181. package/integrations/openclaw/skills/write-agentmemory-skill/SKILL.md +41 -0
  182. package/integrations/openclaw/skills/write-agentmemory-skill/TROUBLESHOOTING.md +70 -0
  183. package/integrations/pi/LICENSE +190 -0
  184. package/integrations/pi/README.md +45 -51
  185. package/integrations/pi/dist/index.mjs +1379 -0
  186. package/integrations/pi/index.ts +139 -173
  187. package/integrations/pi/package.json +16 -6
  188. package/integrations/pi/security.ts +54 -22
  189. package/integrations/pi/skills/agentmemory-agents/REFERENCE.md +32 -0
  190. package/integrations/pi/skills/agentmemory-agents/SKILL.md +48 -0
  191. package/integrations/pi/skills/agentmemory-agents/TROUBLESHOOTING.md +70 -0
  192. package/integrations/pi/skills/agentmemory-architecture/SKILL.md +33 -0
  193. package/integrations/pi/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
  194. package/integrations/pi/skills/agentmemory-config/REFERENCE.md +90 -0
  195. package/integrations/pi/skills/agentmemory-config/SKILL.md +78 -0
  196. package/integrations/pi/skills/agentmemory-config/TROUBLESHOOTING.md +70 -0
  197. package/integrations/pi/skills/agentmemory-hooks/REFERENCE.md +20 -0
  198. package/integrations/pi/skills/agentmemory-hooks/SKILL.md +49 -0
  199. package/integrations/pi/skills/agentmemory-hooks/TROUBLESHOOTING.md +70 -0
  200. package/integrations/pi/skills/agentmemory-mcp-tools/REFERENCE.md +66 -0
  201. package/integrations/pi/skills/agentmemory-mcp-tools/SKILL.md +42 -0
  202. package/integrations/pi/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
  203. package/integrations/pi/skills/agentmemory-rest-api/REFERENCE.md +158 -0
  204. package/integrations/pi/skills/agentmemory-rest-api/SKILL.md +49 -0
  205. package/integrations/pi/skills/agentmemory-rest-api/TROUBLESHOOTING.md +70 -0
  206. package/integrations/pi/skills/commit-context/EXAMPLES.md +71 -0
  207. package/integrations/pi/skills/commit-context/SKILL.md +64 -0
  208. package/integrations/pi/skills/commit-context/TROUBLESHOOTING.md +70 -0
  209. package/integrations/pi/skills/commit-history/EXAMPLES.md +71 -0
  210. package/integrations/pi/skills/commit-history/SKILL.md +62 -0
  211. package/integrations/pi/skills/commit-history/TROUBLESHOOTING.md +70 -0
  212. package/integrations/pi/skills/forget/EXAMPLES.md +40 -0
  213. package/integrations/pi/skills/forget/SKILL.md +73 -0
  214. package/integrations/pi/skills/forget/TROUBLESHOOTING.md +70 -0
  215. package/integrations/pi/skills/handoff/EXAMPLES.md +57 -0
  216. package/integrations/pi/skills/handoff/SKILL.md +75 -0
  217. package/integrations/pi/skills/handoff/TROUBLESHOOTING.md +70 -0
  218. package/integrations/pi/skills/lesson/SKILL.md +64 -0
  219. package/integrations/pi/skills/lesson/TROUBLESHOOTING.md +70 -0
  220. package/integrations/pi/skills/memory-discipline/SKILL.md +65 -0
  221. package/integrations/pi/skills/memory-discipline/TROUBLESHOOTING.md +70 -0
  222. package/integrations/pi/skills/recall/EXAMPLES.md +74 -0
  223. package/integrations/pi/skills/recall/SKILL.md +74 -0
  224. package/integrations/pi/skills/recall/TROUBLESHOOTING.md +70 -0
  225. package/integrations/pi/skills/recap/EXAMPLES.md +62 -0
  226. package/integrations/pi/skills/recap/SKILL.md +68 -0
  227. package/integrations/pi/skills/recap/TROUBLESHOOTING.md +70 -0
  228. package/integrations/pi/skills/remember/EXAMPLES.md +67 -0
  229. package/integrations/pi/skills/remember/SKILL.md +66 -0
  230. package/integrations/pi/skills/remember/TROUBLESHOOTING.md +70 -0
  231. package/integrations/pi/skills/session-history/EXAMPLES.md +59 -0
  232. package/integrations/pi/skills/session-history/SKILL.md +67 -0
  233. package/integrations/pi/skills/session-history/TROUBLESHOOTING.md +70 -0
  234. package/integrations/pi/skills/write-agentmemory-skill/SKILL.md +41 -0
  235. package/integrations/pi/skills/write-agentmemory-skill/TROUBLESHOOTING.md +70 -0
  236. package/package.json +42 -12
  237. package/plugin/.claude-plugin/plugin.json +2 -2
  238. package/plugin/.codex-plugin/plugin.json +27 -4
  239. package/plugin/.devin-plugin/plugin.json +5 -3
  240. package/plugin/.mcp.codex.json +12 -0
  241. package/plugin/.mcp.copilot.json +2 -7
  242. package/plugin/.mcp.json +2 -7
  243. package/plugin/assets/icon.svg +35 -0
  244. package/plugin/cursor/hooks.json +23 -8
  245. package/plugin/hooks/hooks.copilot.json +11 -11
  246. package/plugin/hooks.json +67 -0
  247. package/plugin/opencode/README.md +267 -31
  248. package/plugin/opencode/agentmemory-capture.ts +594 -11
  249. package/plugin/opencode/plugin.json +1 -1
  250. package/plugin/plugin.json +1 -1
  251. package/plugin/scripts/_capture.d.mts +25 -0
  252. package/plugin/scripts/_capture.d.mts.map +1 -0
  253. package/plugin/scripts/_capture.mjs +944 -0
  254. package/plugin/scripts/_capture.mjs.map +1 -0
  255. package/plugin/scripts/antigravity-bridge.d.mts +1 -1
  256. package/plugin/scripts/antigravity-bridge.d.mts.map +1 -1
  257. package/plugin/scripts/antigravity-bridge.mjs +24 -15
  258. package/plugin/scripts/antigravity-bridge.mjs.map +1 -1
  259. package/plugin/scripts/cursor/run-detached.d.mts +1 -0
  260. package/plugin/scripts/cursor/run-detached.mjs +786 -0
  261. package/plugin/scripts/cursor/run-detached.mjs.map +1 -0
  262. package/plugin/scripts/cursor/run-hook.d.mts +1 -0
  263. package/plugin/scripts/cursor/run-hook.mjs +704 -0
  264. package/plugin/scripts/cursor/run-hook.mjs.map +1 -0
  265. package/plugin/scripts/notification.mjs +35 -29
  266. package/plugin/scripts/notification.mjs.map +1 -1
  267. package/plugin/scripts/plugin-bridge.mjs +409 -0
  268. package/plugin/scripts/post-commit.mjs +91 -1
  269. package/plugin/scripts/post-commit.mjs.map +1 -1
  270. package/plugin/scripts/post-tool-failure.mjs +71 -29
  271. package/plugin/scripts/post-tool-failure.mjs.map +1 -1
  272. package/plugin/scripts/post-tool-use.mjs +99 -39
  273. package/plugin/scripts/post-tool-use.mjs.map +1 -1
  274. package/plugin/scripts/pre-compact.mjs +113 -6
  275. package/plugin/scripts/pre-compact.mjs.map +1 -1
  276. package/plugin/scripts/pre-tool-use.mjs +91 -1
  277. package/plugin/scripts/pre-tool-use.mjs.map +1 -1
  278. package/plugin/scripts/prompt-submit.mjs +25 -25
  279. package/plugin/scripts/prompt-submit.mjs.map +1 -1
  280. package/plugin/scripts/session-end.mjs +67 -31
  281. package/plugin/scripts/session-end.mjs.map +1 -1
  282. package/plugin/scripts/session-start.mjs +110 -6
  283. package/plugin/scripts/session-start.mjs.map +1 -1
  284. package/plugin/scripts/stop.mjs +80 -8
  285. package/plugin/scripts/stop.mjs.map +1 -1
  286. package/plugin/scripts/subagent-start.mjs +28 -29
  287. package/plugin/scripts/subagent-start.mjs.map +1 -1
  288. package/plugin/scripts/subagent-stop.mjs +33 -29
  289. package/plugin/scripts/subagent-stop.mjs.map +1 -1
  290. package/plugin/scripts/task-completed.mjs +31 -31
  291. package/plugin/scripts/task-completed.mjs.map +1 -1
  292. package/plugin/skills/_shared/TROUBLESHOOTING.md +42 -12
  293. package/plugin/skills/agentmemory-agents/REFERENCE.md +10 -9
  294. package/plugin/skills/agentmemory-agents/SKILL.md +19 -5
  295. package/plugin/skills/agentmemory-agents/TROUBLESHOOTING.md +70 -0
  296. package/plugin/skills/agentmemory-architecture/SKILL.md +4 -4
  297. package/plugin/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
  298. package/plugin/skills/agentmemory-config/REFERENCE.md +48 -3
  299. package/plugin/skills/agentmemory-config/SKILL.md +51 -10
  300. package/plugin/skills/agentmemory-config/TROUBLESHOOTING.md +70 -0
  301. package/plugin/skills/agentmemory-hooks/SKILL.md +15 -5
  302. package/plugin/skills/agentmemory-hooks/TROUBLESHOOTING.md +70 -0
  303. package/plugin/skills/agentmemory-mcp-tools/REFERENCE.md +5 -5
  304. package/plugin/skills/agentmemory-mcp-tools/SKILL.md +6 -3
  305. package/plugin/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
  306. package/plugin/skills/agentmemory-rest-api/REFERENCE.md +18 -2
  307. package/plugin/skills/agentmemory-rest-api/SKILL.md +12 -6
  308. package/plugin/skills/agentmemory-rest-api/TROUBLESHOOTING.md +70 -0
  309. package/plugin/skills/commit-context/SKILL.md +1 -1
  310. package/plugin/skills/commit-context/TROUBLESHOOTING.md +70 -0
  311. package/plugin/skills/commit-history/SKILL.md +1 -1
  312. package/plugin/skills/commit-history/TROUBLESHOOTING.md +70 -0
  313. package/plugin/skills/forget/EXAMPLES.md +19 -54
  314. package/plugin/skills/forget/SKILL.md +16 -12
  315. package/plugin/skills/forget/TROUBLESHOOTING.md +70 -0
  316. package/plugin/skills/handoff/EXAMPLES.md +5 -4
  317. package/plugin/skills/handoff/SKILL.md +13 -6
  318. package/plugin/skills/handoff/TROUBLESHOOTING.md +70 -0
  319. package/plugin/skills/lesson/SKILL.md +1 -1
  320. package/plugin/skills/lesson/TROUBLESHOOTING.md +70 -0
  321. package/plugin/skills/memory-discipline/SKILL.md +14 -6
  322. package/plugin/skills/memory-discipline/TROUBLESHOOTING.md +70 -0
  323. package/plugin/skills/recall/SKILL.md +18 -7
  324. package/plugin/skills/recall/TROUBLESHOOTING.md +70 -0
  325. package/plugin/skills/recap/EXAMPLES.md +5 -3
  326. package/plugin/skills/recap/SKILL.md +11 -6
  327. package/plugin/skills/recap/TROUBLESHOOTING.md +70 -0
  328. package/plugin/skills/remember/EXAMPLES.md +3 -3
  329. package/plugin/skills/remember/SKILL.md +1 -1
  330. package/plugin/skills/remember/TROUBLESHOOTING.md +70 -0
  331. package/plugin/skills/session-history/EXAMPLES.md +2 -2
  332. package/plugin/skills/session-history/SKILL.md +10 -4
  333. package/plugin/skills/session-history/TROUBLESHOOTING.md +70 -0
  334. package/plugin/skills/write-agentmemory-skill/SKILL.md +2 -1
  335. package/plugin/skills/write-agentmemory-skill/TROUBLESHOOTING.md +70 -0
  336. package/dist/connect-Qaeq15TQ.mjs.map +0 -1
  337. package/dist/docker-compose.yml +0 -47
  338. package/dist/iii-config.docker.yaml +0 -53
  339. package/dist/iii-config.yaml +0 -61
  340. package/dist/image-refs-BKLmp_sD.mjs.map +0 -1
  341. package/dist/image-refs-CJgZmb9X.mjs.map +0 -1
  342. package/dist/keyed-mutex-DTHtcZrt.mjs.map +0 -1
  343. package/dist/logger-BEB7pCI9.mjs +0 -43
  344. package/dist/logger-BEB7pCI9.mjs.map +0 -1
  345. package/dist/schema-BFZhNTF7.mjs.map +0 -1
  346. package/dist/src-G7yt8gGm.mjs.map +0 -1
  347. package/dist/standalone-BqNJDJ04.mjs.map +0 -1
  348. package/dist/tools-registry-BV_2bu7z.mjs +0 -1405
  349. package/dist/tools-registry-BV_2bu7z.mjs.map +0 -1
  350. package/docker-compose.yml +0 -47
  351. package/iii-config.docker.yaml +0 -53
  352. package/iii-config.yaml +0 -61
@@ -4,6 +4,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
4
  import { dirname, join } from "node:path";
5
5
  import { homedir } from "node:os";
6
6
  import "picocolors";
7
+ import { AsyncLocalStorage } from "node:async_hooks";
7
8
  //#region src/mcp/in-memory-kv.ts
8
9
  var InMemoryKV = class {
9
10
  store = /* @__PURE__ */ new Map();
@@ -34,20 +35,30 @@ var InMemoryKV = class {
34
35
  return entries ? Array.from(entries.values()) : [];
35
36
  }
36
37
  persist() {
37
- if (!this.persistPath) return;
38
+ if (!this.persistPath) return false;
38
39
  try {
39
40
  const dir = dirname(this.persistPath);
40
41
  if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
41
42
  const data = {};
42
43
  for (const [scope, entries] of this.store) data[scope] = Object.fromEntries(entries);
43
44
  writeFileSync(this.persistPath, JSON.stringify(data), "utf-8");
45
+ return true;
44
46
  } catch (err) {
45
47
  process.stderr.write(`[@agentmemory/mcp] Persist failed: ${err instanceof Error ? err.message : String(err)}\n`);
48
+ return false;
46
49
  }
47
50
  }
48
51
  };
49
52
  //#endregion
50
53
  //#region src/mcp/transport.ts
54
+ let activeStdioTransports = 0;
55
+ var JsonRpcError = class extends Error {
56
+ constructor(code, message) {
57
+ super(message);
58
+ this.code = code;
59
+ this.name = "JsonRpcError";
60
+ }
61
+ };
51
62
  function isNotification(req) {
52
63
  return req.id === void 0 || req.id === null;
53
64
  }
@@ -113,7 +124,7 @@ async function processLine(line, handler, writeOut, writeErr = (msg) => process.
113
124
  jsonrpc: "2.0",
114
125
  id: request.id,
115
126
  error: {
116
- code: -32603,
127
+ code: err instanceof JsonRpcError ? err.code : -32603,
117
128
  message: err instanceof Error ? err.message : String(err)
118
129
  }
119
130
  });
@@ -193,6 +204,7 @@ function createMessageParser(onMessage, writeErr = (msg) => process.stderr.write
193
204
  function createStdioTransport(handler) {
194
205
  let parser = null;
195
206
  let queue = Promise.resolve();
207
+ let active = false;
196
208
  const writeResponse = (response) => {
197
209
  const formatted = formatResponse(response, parser?.isFramed() ?? false);
198
210
  if (typeof formatted === "string") {
@@ -204,6 +216,10 @@ function createStdioTransport(handler) {
204
216
  const onData = (chunk) => parser?.push(chunk);
205
217
  return {
206
218
  start() {
219
+ if (active) return;
220
+ active = true;
221
+ activeStdioTransports += 1;
222
+ process.env["AGENTMEMORY_MCP_STDIO__"] = "1";
207
223
  parser = createMessageParser((message) => {
208
224
  queue = queue.then(() => processLine(message, handler, writeResponse));
209
225
  queue.catch((err) => {
@@ -214,6 +230,11 @@ function createStdioTransport(handler) {
214
230
  },
215
231
  stop() {
216
232
  process.stdin.off("data", onData);
233
+ if (active) {
234
+ active = false;
235
+ activeStdioTransports -= 1;
236
+ if (activeStdioTransports === 0) delete process.env["AGENTMEMORY_MCP_STDIO__"];
237
+ }
217
238
  parser = null;
218
239
  }
219
240
  };
@@ -223,7 +244,7 @@ function createStdioTransport(handler) {
223
244
  const CORE_TOOLS = [
224
245
  {
225
246
  name: "memory_recall",
226
- description: "Search past session observations for relevant context. Use when you need to recall what happened in previous sessions, find past decisions, or look up how a file was modified before.",
247
+ description: "Search stored memories and session observations for relevant context. Use when you need to recall what happened in previous sessions, find past decisions, or look up how a file was modified before.",
227
248
  inputSchema: {
228
249
  type: "object",
229
250
  properties: {
@@ -241,7 +262,28 @@ const CORE_TOOLS = [
241
262
  },
242
263
  token_budget: {
243
264
  type: "number",
244
- description: "Optional token budget to trim returned results"
265
+ description: "Optional estimated content token budget; response includes truncation and recovery metadata"
266
+ },
267
+ targetLayer: {
268
+ type: "string",
269
+ enum: [
270
+ "all",
271
+ "memory",
272
+ "observation"
273
+ ],
274
+ description: "Search all indexed layers (default), durable memories, or raw observations before ranking"
275
+ },
276
+ project: {
277
+ type: "string",
278
+ description: "Filter by project path"
279
+ },
280
+ cwd: {
281
+ type: "string",
282
+ description: "Filter by session working directory"
283
+ },
284
+ agentId: {
285
+ type: "string",
286
+ description: "Filter by owning agent; '*' reads across agents"
245
287
  }
246
288
  },
247
289
  required: ["query"]
@@ -316,23 +358,46 @@ const CORE_TOOLS = [
316
358
  description: "Detect recurring patterns across sessions.",
317
359
  inputSchema: {
318
360
  type: "object",
319
- properties: { project: {
320
- type: "string",
321
- description: "Project path to analyze"
322
- } }
361
+ properties: {
362
+ project: {
363
+ type: "string",
364
+ description: "Project path to analyze"
365
+ },
366
+ limit: {
367
+ type: "integer",
368
+ description: "Most recent sessions to scan (default 50, max 500)"
369
+ }
370
+ }
323
371
  }
324
372
  },
325
373
  {
326
374
  name: "memory_sessions",
327
- description: "List recent sessions with their status and observation counts.",
375
+ description: "List recent sessions with status, observation counts, summaries and a continuation cursor. Filters apply before pagination; retain them when requesting the next page.",
328
376
  inputSchema: {
329
377
  type: "object",
330
- properties: {}
378
+ properties: {
379
+ project: {
380
+ type: "string",
381
+ description: "Exact project identifier used when sessions were started"
382
+ },
383
+ agentId: {
384
+ type: "string",
385
+ description: "Filter by owning agent; '*' reads across agents"
386
+ },
387
+ limit: {
388
+ type: "integer",
389
+ description: "Page size (default 20, max 100)"
390
+ },
391
+ cursor: {
392
+ type: "string",
393
+ description: "nextCursor from the previous page; omit for the first page"
394
+ }
395
+ }
331
396
  }
332
397
  },
333
398
  {
334
399
  name: "memory_smart_search",
335
- description: "Hybrid semantic+keyword search with progressive disclosure.",
400
+ description: "Hybrid semantic+keyword search with progressive disclosure. Pass query to search, or expandIds to recover full results.",
336
401
  inputSchema: {
337
402
  type: "object",
338
403
  properties: {
@@ -342,14 +407,34 @@ const CORE_TOOLS = [
342
407
  },
343
408
  expandIds: {
344
409
  type: "string",
345
- description: "Comma-separated observation IDs to expand"
410
+ description: "Comma-separated memory or observation IDs to expand; query is optional when provided"
346
411
  },
347
412
  limit: {
348
413
  type: "number",
349
414
  description: "Max results (default 10)"
415
+ },
416
+ targetLayer: {
417
+ type: "string",
418
+ enum: [
419
+ "all",
420
+ "memory",
421
+ "observation"
422
+ ],
423
+ description: "Search all indexed layers (default), durable memories, or raw observations before ranking"
424
+ },
425
+ project: {
426
+ type: "string",
427
+ description: "Filter by project path"
428
+ },
429
+ agentId: {
430
+ type: "string",
431
+ description: "Filter by owning agent; '*' reads across agents"
432
+ },
433
+ includeLessons: {
434
+ type: "boolean",
435
+ description: "Include lesson matches when targetLayer is all (default true)"
350
436
  }
351
- },
352
- required: ["query"]
437
+ }
353
438
  }
354
439
  },
355
440
  {
@@ -427,10 +512,31 @@ const CORE_TOOLS = [
427
512
  },
428
513
  {
429
514
  name: "memory_export",
430
- description: "Export all memory data as JSON.",
515
+ description: "Export memory data as JSON. Past the transport size limit the export is refused, so use the paging arguments on a large store.",
431
516
  inputSchema: {
432
517
  type: "object",
433
- properties: {}
518
+ properties: {
519
+ maxSessions: {
520
+ type: "number",
521
+ description: "Sessions per page (with their observations)"
522
+ },
523
+ offset: {
524
+ type: "number",
525
+ description: "Session offset"
526
+ },
527
+ collectionLimit: {
528
+ type: "number",
529
+ description: "Rows per page for memories, summaries, graphNodes, lessons and the other top-level collections; access logs follow the memories on the page. Sessions and their observations are paged only by maxSessions and offset, so pass collections to leave them out of each page"
530
+ },
531
+ collectionOffset: {
532
+ type: "number",
533
+ description: "Row offset for the top-level collections"
534
+ },
535
+ collections: {
536
+ type: "string",
537
+ description: "Comma-separated collections to return, e.g. memories,lessons. Sessions and their observations come back only when the list names sessions, access logs only together with memories. Unknown names are ignored. Omit for everything. A paged or selected export cannot be imported with strategy replace."
538
+ }
539
+ }
434
540
  }
435
541
  },
436
542
  {
@@ -1329,7 +1435,8 @@ function getAllTools() {
1329
1435
  ...V010_SLOTS_TOOLS
1330
1436
  ];
1331
1437
  }
1332
- const ENV_FILE = join(join(homedir(), ".agentmemory"), ".env");
1438
+ process.env["AGENTMEMORY_DATA_DIR"] || join(homedir(), ".agentmemory");
1439
+ const ENV_FILE = process.env["AGENTMEMORY_ENV_FILE"] || join(homedir(), ".agentmemory", ".env");
1333
1440
  let envFileCache;
1334
1441
  function loadEnvFile() {
1335
1442
  if (envFileCache) return envFileCache;
@@ -1337,7 +1444,10 @@ function loadEnvFile() {
1337
1444
  envFileCache = {};
1338
1445
  return envFileCache;
1339
1446
  }
1340
- const content = readFileSync(ENV_FILE, "utf-8");
1447
+ envFileCache = parseEnvContent(readFileSync(ENV_FILE, "utf-8"));
1448
+ return envFileCache;
1449
+ }
1450
+ function parseEnvContent(content) {
1341
1451
  const vars = {};
1342
1452
  for (const line of content.split("\n")) {
1343
1453
  const trimmed = line.trim();
@@ -1356,8 +1466,7 @@ function loadEnvFile() {
1356
1466
  }
1357
1467
  vars[key] = val;
1358
1468
  }
1359
- envFileCache = vars;
1360
- return envFileCache;
1469
+ return vars;
1361
1470
  }
1362
1471
  function getMergedEnv(overrides) {
1363
1472
  return {
@@ -1366,18 +1475,534 @@ function getMergedEnv(overrides) {
1366
1475
  ...overrides
1367
1476
  };
1368
1477
  }
1478
+ function loadAgentScope() {
1479
+ const env = getMergedEnv();
1480
+ const raw = env["AGENT_ID"];
1481
+ if (!raw) return null;
1482
+ const agentId = raw.trim().slice(0, 128);
1483
+ if (!agentId) return null;
1484
+ return {
1485
+ agentId,
1486
+ mode: env["AGENTMEMORY_AGENT_SCOPE"] === "isolated" ? "isolated" : "shared"
1487
+ };
1488
+ }
1489
+ function getAgentId() {
1490
+ return loadAgentScope()?.agentId;
1491
+ }
1492
+ function isAgentScopeIsolated() {
1493
+ return loadAgentScope()?.mode === "isolated";
1494
+ }
1369
1495
  function getStandalonePersistPath() {
1370
1496
  return getMergedEnv()["STANDALONE_PERSIST_PATH"] || join(homedir(), ".agentmemory", "standalone.json");
1371
1497
  }
1372
1498
  //#endregion
1499
+ //#region src/state/search-layer.ts
1500
+ function isSearchLayer(value) {
1501
+ return value === "all" || value === "memory" || value === "observation";
1502
+ }
1503
+ //#endregion
1504
+ //#region src/state/memory-utils.ts
1505
+ function memoryToObservation(memory) {
1506
+ return {
1507
+ id: memory.id,
1508
+ sessionId: memory.sessionIds?.[0] ?? "memory",
1509
+ timestamp: memory.createdAt,
1510
+ type: "decision",
1511
+ title: memory.title,
1512
+ facts: [memory.content],
1513
+ narrative: memory.content,
1514
+ concepts: memory.concepts,
1515
+ files: memory.files,
1516
+ importance: memory.strength,
1517
+ ...memory.agentId ? { agentId: memory.agentId } : {}
1518
+ };
1519
+ }
1520
+ //#endregion
1521
+ //#region src/functions/recall-response.ts
1522
+ function estimateTokens(value) {
1523
+ return Math.max(1, Math.ceil(JSON.stringify(value).length / 3));
1524
+ }
1525
+ function prefix(text, length) {
1526
+ let end = Math.min(length, text.length);
1527
+ if (end > 0 && end < text.length && /[\uD800-\uDBFF]/.test(text[end - 1])) end--;
1528
+ return text.slice(0, end);
1529
+ }
1530
+ function fitText(text, budget, makeResult) {
1531
+ let low = 0;
1532
+ let high = text.length;
1533
+ while (low < high) {
1534
+ const middle = Math.ceil((low + high) / 2);
1535
+ if (estimateTokens(makeResult(prefix(text, middle))) <= budget) low = middle;
1536
+ else high = middle - 1;
1537
+ }
1538
+ return makeResult(prefix(text, low));
1539
+ }
1540
+ function formatResult(result, format) {
1541
+ if (format === "full") return result;
1542
+ const observation = result.observation;
1543
+ const compact = {
1544
+ obsId: observation.id,
1545
+ sessionId: result.sessionId,
1546
+ title: observation.title,
1547
+ type: observation.type,
1548
+ score: result.score,
1549
+ timestamp: observation.timestamp,
1550
+ ...result.layer !== void 0 && { layer: result.layer }
1551
+ };
1552
+ if (format === "compact") return compact;
1553
+ const { type: _type, ...narrative } = compact;
1554
+ return {
1555
+ ...narrative,
1556
+ narrative: observation.narrative
1557
+ };
1558
+ }
1559
+ function clipResult(result, format, budget) {
1560
+ const observation = result.observation;
1561
+ const layer = result.layer !== void 0 ? { layer: result.layer } : {};
1562
+ if (format === "compact") {
1563
+ const base = {
1564
+ obsId: observation.id,
1565
+ sessionId: result.sessionId,
1566
+ title: "",
1567
+ type: observation.type,
1568
+ score: result.score,
1569
+ timestamp: observation.timestamp,
1570
+ ...layer,
1571
+ content_truncated: true
1572
+ };
1573
+ const minimum = estimateTokens(base);
1574
+ if (minimum > budget) return { minimum };
1575
+ return {
1576
+ result: fitText(observation.title, budget, (title) => ({
1577
+ ...base,
1578
+ title
1579
+ })),
1580
+ minimum
1581
+ };
1582
+ }
1583
+ const makeResult = (title, narrative) => {
1584
+ if (format === "narrative") return {
1585
+ obsId: observation.id,
1586
+ sessionId: result.sessionId,
1587
+ title,
1588
+ narrative,
1589
+ score: result.score,
1590
+ timestamp: observation.timestamp,
1591
+ ...layer,
1592
+ content_truncated: true
1593
+ };
1594
+ return {
1595
+ observation: {
1596
+ id: observation.id,
1597
+ sessionId: observation.sessionId,
1598
+ timestamp: observation.timestamp,
1599
+ type: observation.type,
1600
+ title,
1601
+ facts: [],
1602
+ narrative,
1603
+ concepts: [],
1604
+ files: [],
1605
+ importance: observation.importance,
1606
+ ...observation.confidence !== void 0 && { confidence: observation.confidence },
1607
+ ...observation.agentId !== void 0 && { agentId: observation.agentId },
1608
+ ...observation.origin && { origin: {
1609
+ channel: observation.origin.channel,
1610
+ capturedAt: observation.origin.capturedAt
1611
+ } }
1612
+ },
1613
+ score: result.score,
1614
+ sessionId: result.sessionId,
1615
+ ...layer,
1616
+ content_truncated: true
1617
+ };
1618
+ };
1619
+ const minimum = estimateTokens(makeResult("", ""));
1620
+ if (minimum > budget) return { minimum };
1621
+ const titleResult = fitText(prefix(observation.title, 120), budget, (title) => makeResult(title, ""));
1622
+ const title = "observation" in titleResult ? titleResult.observation.title : titleResult.title;
1623
+ return {
1624
+ result: fitText(observation.narrative || observation.facts.join("\n"), budget, (text) => makeResult(title, text)),
1625
+ minimum
1626
+ };
1627
+ }
1628
+ function buildRecallResponse(results, format, tokenBudget) {
1629
+ const selected = [];
1630
+ let used = 0;
1631
+ let clipped = false;
1632
+ let minimumBudget;
1633
+ for (const result of results) {
1634
+ const formatted = formatResult(result, format);
1635
+ const tokens = estimateTokens(formatted);
1636
+ if (tokenBudget === void 0 || used + tokens <= tokenBudget) {
1637
+ selected.push(formatted);
1638
+ used += tokens;
1639
+ continue;
1640
+ }
1641
+ if (selected.length === 0) {
1642
+ const preview = clipResult(result, format, tokenBudget);
1643
+ if (preview.result) {
1644
+ selected.push(preview.result);
1645
+ used = estimateTokens(preview.result);
1646
+ clipped = true;
1647
+ continue;
1648
+ } else minimumBudget = Math.min(preview.minimum, tokens);
1649
+ }
1650
+ break;
1651
+ }
1652
+ const excluded = results.slice(selected.length);
1653
+ const metadata = {
1654
+ tokens_used: used,
1655
+ tokens_budget: tokenBudget,
1656
+ truncated: clipped || excluded.length > 0,
1657
+ matched_count: results.length,
1658
+ excluded_by_budget: excluded.length,
1659
+ excluded_results: excluded.slice(0, 10).map((result) => ({
1660
+ obsId: result.observation.id,
1661
+ sessionId: result.sessionId,
1662
+ title: prefix(result.observation.title, 120)
1663
+ })),
1664
+ excluded_results_truncated: excluded.length > 10,
1665
+ ...minimumBudget !== void 0 && { minimum_budget: minimumBudget }
1666
+ };
1667
+ if (format === "narrative") {
1668
+ const narrativeResults = selected;
1669
+ return {
1670
+ ...metadata,
1671
+ format,
1672
+ results: narrativeResults,
1673
+ text: narrativeResults.map((result, index) => `${index + 1}. ${result.title}\n${result.narrative}`).join("\n\n")
1674
+ };
1675
+ }
1676
+ if (format === "compact") return {
1677
+ ...metadata,
1678
+ format,
1679
+ results: selected
1680
+ };
1681
+ return {
1682
+ ...metadata,
1683
+ format,
1684
+ results: selected
1685
+ };
1686
+ }
1687
+ //#endregion
1688
+ //#region src/mcp/search-arguments.ts
1689
+ function parseSearchExpansionIds(value) {
1690
+ return (typeof value === "string" ? value.split(",") : Array.isArray(value) ? value : []).flatMap((entry) => {
1691
+ if (typeof entry === "string") return entry.trim() ? [entry.trim()] : [];
1692
+ if (!entry || typeof entry !== "object" || typeof entry.obsId !== "string" || !entry.obsId.trim()) return [];
1693
+ const obsId = entry.obsId.trim();
1694
+ return typeof entry.sessionId === "string" && entry.sessionId.trim() ? [{
1695
+ obsId,
1696
+ sessionId: entry.sessionId.trim()
1697
+ }] : [obsId];
1698
+ });
1699
+ }
1700
+ //#endregion
1701
+ //#region src/state/list-query.ts
1702
+ function encodeCursor(position) {
1703
+ return Buffer.from(JSON.stringify(position), "utf-8").toString("base64url");
1704
+ }
1705
+ function decodeCursor(cursor) {
1706
+ if (!cursor) return null;
1707
+ try {
1708
+ const parsed = JSON.parse(Buffer.from(cursor, "base64url").toString("utf-8"));
1709
+ if (!parsed || typeof parsed !== "object") return null;
1710
+ const position = {};
1711
+ if (typeof parsed.key === "string") position.key = parsed.key;
1712
+ if (typeof parsed.id === "string") position.id = parsed.id;
1713
+ if (Number.isInteger(parsed.offset) && parsed.offset >= 0) position.offset = parsed.offset;
1714
+ return position;
1715
+ } catch {
1716
+ return null;
1717
+ }
1718
+ }
1719
+ function compareDesc(aKey, aId, bKey, bId) {
1720
+ if (aKey !== bKey) return aKey < bKey ? 1 : -1;
1721
+ if (aId === bId) return 0;
1722
+ return aId < bId ? 1 : -1;
1723
+ }
1724
+ function sortByKeyDesc(items, keyOf, idOf) {
1725
+ return items.sort((a, b) => compareDesc(keyOf(a), idOf(a), keyOf(b), idOf(b)));
1726
+ }
1727
+ function pageAfterCursor(sortedDesc, keyOf, idOf, cursor, limit) {
1728
+ const position = decodeCursor(cursor);
1729
+ let start = 0;
1730
+ if (position?.key !== void 0 && position.id !== void 0) {
1731
+ const { key, id } = position;
1732
+ start = sortedDesc.findIndex((item) => compareDesc(keyOf(item), idOf(item), key, id) > 0);
1733
+ if (start < 0) start = sortedDesc.length;
1734
+ }
1735
+ const page = sortedDesc.slice(start, start + limit);
1736
+ const last = page[page.length - 1];
1737
+ return {
1738
+ page,
1739
+ nextCursor: last !== void 0 && start + limit < sortedDesc.length ? encodeCursor({
1740
+ key: keyOf(last),
1741
+ id: idOf(last)
1742
+ }) : null
1743
+ };
1744
+ }
1745
+ //#endregion
1746
+ //#region src/mcp/session-arguments.ts
1747
+ function parseSessionArguments(args) {
1748
+ const limit = args.limit === void 0 ? 20 : args.limit;
1749
+ if (typeof limit !== "number" || !Number.isInteger(limit) || limit < 1) throw new Error("limit must be a positive integer");
1750
+ const query = { limit: String(Math.min(limit, 100)) };
1751
+ for (const field of [
1752
+ "project",
1753
+ "agentId",
1754
+ "cursor"
1755
+ ]) {
1756
+ if (args[field] === void 0) continue;
1757
+ if (field === "cursor" && typeof args[field] === "string" && !args[field].trim()) continue;
1758
+ if (typeof args[field] !== "string" || !args[field].trim()) throw new Error(`${field} must be a non-empty string`);
1759
+ query[field] = args[field].trim();
1760
+ }
1761
+ if (query.cursor) {
1762
+ const position = decodeCursor(query.cursor);
1763
+ if (!position || typeof position.key !== "string" || typeof position.id !== "string") throw new Error("cursor must be a session continuation token");
1764
+ }
1765
+ return query;
1766
+ }
1767
+ //#endregion
1373
1768
  //#region src/version.ts
1374
- const VERSION = "0.9.29";
1769
+ const VERSION = "0.9.31";
1375
1770
  createRequire(import.meta.url);
1376
1771
  //#endregion
1377
1772
  //#region src/state/schema.ts
1773
+ const KV = {
1774
+ sessions: "mem:sessions",
1775
+ observations: (sessionId) => `mem:obs:${sessionId}`,
1776
+ memories: "mem:memories",
1777
+ summaries: "mem:summaries",
1778
+ summaryRepairs: "mem:summary:repairs",
1779
+ config: "mem:config",
1780
+ metrics: "mem:metrics",
1781
+ health: "mem:health",
1782
+ embeddings: (obsId) => `mem:emb:${obsId}`,
1783
+ bm25Index: "mem:index:bm25",
1784
+ vectorPendingLog: "mem:index:vec-pending",
1785
+ relations: "mem:relations",
1786
+ profiles: "mem:profiles",
1787
+ claudeBridge: "mem:claude-bridge",
1788
+ graphNodes: "mem:graph:nodes",
1789
+ graphControl: "mem:graph:control",
1790
+ graphEdges: "mem:graph:edges",
1791
+ graphSnapshot: "mem:graph:snapshot",
1792
+ graphNameIndex: "mem:graph:name-index",
1793
+ graphEdgeKey: "mem:graph:edge-key",
1794
+ graphNodeDegree: "mem:graph:node-degree",
1795
+ graphMembership: "mem:graph:membership",
1796
+ graphRetrievalControl: "mem:graph:retrieval-control",
1797
+ graphRetrievalData: "mem:graph:retrieval-data",
1798
+ graphIndexMigration: "mem:graph:index-migration",
1799
+ graphIndexManifest: "mem:graph:index-manifest",
1800
+ semantic: "mem:semantic",
1801
+ procedural: "mem:procedural",
1802
+ teamShared: (teamId) => `mem:team:${teamId}:shared`,
1803
+ teamUsers: (teamId, userId) => `mem:team:${teamId}:users:${userId}`,
1804
+ teamProfile: (teamId) => `mem:team:${teamId}:profile`,
1805
+ audit: "mem:audit",
1806
+ auditMonth: (month) => `mem:audit:${month}`,
1807
+ auditMonths: "mem:audit:months",
1808
+ actions: "mem:actions",
1809
+ actionEdges: "mem:action-edges",
1810
+ leases: "mem:leases",
1811
+ routines: "mem:routines",
1812
+ routineRuns: "mem:routine-runs",
1813
+ signals: "mem:signals",
1814
+ checkpoints: "mem:checkpoints",
1815
+ mesh: "mem:mesh",
1816
+ sketches: "mem:sketches",
1817
+ facets: "mem:facets",
1818
+ sentinels: "mem:sentinels",
1819
+ crystals: "mem:crystals",
1820
+ lessons: "mem:lessons",
1821
+ insights: "mem:insights",
1822
+ graphEdgeHistory: "mem:graph:edge-history",
1823
+ enrichedChunks: (sessionId) => `mem:enriched:${sessionId}`,
1824
+ latentEmbeddings: (obsId) => `mem:latent:${obsId}`,
1825
+ retentionScores: "mem:retention",
1826
+ accessLog: "mem:access",
1827
+ imageRefs: "mem:image-refs",
1828
+ imageEmbeddings: "mem:image-embeddings",
1829
+ slots: "mem:slots",
1830
+ globalSlots: "mem:slots:global",
1831
+ state: "mem:state",
1832
+ commits: "mem:commits",
1833
+ recentSearches: "mem:recent-searches",
1834
+ projectSessionsIndex: "mem:idx:project-sessions",
1835
+ obsSessionIndex: (shard) => `mem:idx:obs:${shard}`,
1836
+ captureInbox: "mem:capture:inbox",
1837
+ captureEvents: (shard) => `mem:capture:events:${shard}`,
1838
+ capturePrompts: "mem:capture:prompts"
1839
+ };
1378
1840
  function generateId(prefix) {
1379
1841
  return `${prefix}_${Date.now().toString(36)}_${crypto.randomUUID().replace(/-/g, "").slice(0, 12)}`;
1380
1842
  }
1843
+ process.env["AGENTMEMORY_VERBOSE"] === "1" || process.env["AGENTMEMORY_VERBOSE"];
1844
+ new AsyncLocalStorage();
1845
+ KV.auditMonths;
1846
+ const AUDIT_MIGRATION_STATE_KEY = "migration";
1847
+ async function readAuditMigrationState(kv) {
1848
+ return kv.get(KV.auditMonths, AUDIT_MIGRATION_STATE_KEY);
1849
+ }
1850
+ function monthStartMs(month) {
1851
+ const [year, mon] = month.split("-").map(Number);
1852
+ return Date.UTC(year, mon - 1, 1);
1853
+ }
1854
+ function monthEndMs(month) {
1855
+ const [year, mon] = month.split("-").map(Number);
1856
+ return Date.UTC(year, mon, 1) - 1;
1857
+ }
1858
+ async function readAuditMonthIndex(kv) {
1859
+ return (await kv.get(KV.auditMonths, "index"))?.months ?? [];
1860
+ }
1861
+ async function listAuditMonthsDesc(kv) {
1862
+ return [...await readAuditMonthIndex(kv)].sort().reverse();
1863
+ }
1864
+ async function queryAudit(kv, filter) {
1865
+ const limit = filter?.limit || 100;
1866
+ let fromMs;
1867
+ if (filter?.dateFrom) {
1868
+ fromMs = new Date(filter.dateFrom).getTime();
1869
+ if (Number.isNaN(fromMs)) throw new Error(`Invalid dateFrom: ${filter.dateFrom}`);
1870
+ }
1871
+ const query = filter?.query?.trim().toLowerCase();
1872
+ let toMs;
1873
+ if (filter?.dateTo) {
1874
+ toMs = new Date(filter.dateTo).getTime();
1875
+ if (Number.isNaN(toMs)) throw new Error(`Invalid dateTo: ${filter.dateTo}`);
1876
+ }
1877
+ const matches = (entry) => {
1878
+ if (filter?.operation && entry.operation !== filter.operation) return false;
1879
+ const t = new Date(entry.timestamp).getTime();
1880
+ if (fromMs !== void 0 && t < fromMs) return false;
1881
+ if (toMs !== void 0 && t > toMs) return false;
1882
+ if (query && ![entry.functionId, ...entry.targetIds || []].some((v) => String(v || "").toLowerCase().includes(query))) return false;
1883
+ return true;
1884
+ };
1885
+ const seenIds = /* @__PURE__ */ new Set();
1886
+ const collected = [];
1887
+ const addIfNew = (row) => {
1888
+ if (seenIds.has(row.id)) return;
1889
+ seenIds.add(row.id);
1890
+ if (matches(row)) collected.push(row);
1891
+ };
1892
+ const months = await listAuditMonthsDesc(kv);
1893
+ for (const month of months) {
1894
+ if (collected.length >= limit) break;
1895
+ if (toMs !== void 0 && monthStartMs(month) > toMs) continue;
1896
+ if (fromMs !== void 0 && monthEndMs(month) < fromMs) break;
1897
+ const rows = await kv.list(KV.auditMonth(month));
1898
+ for (const row of rows) addIfNew(row);
1899
+ }
1900
+ let legacyFrozen = false;
1901
+ let legacyFrozenBytes;
1902
+ if (collected.length < limit) {
1903
+ const migrationState = await readAuditMigrationState(kv);
1904
+ if (migrationState?.safeToListLegacy) {
1905
+ const legacyRows = await kv.list(KV.audit);
1906
+ for (const row of legacyRows) addIfNew(row);
1907
+ } else if (migrationState?.status === "too-large" || migrationState?.status === "unreadable") {
1908
+ legacyFrozen = true;
1909
+ legacyFrozenBytes = migrationState.legacySizeBytes;
1910
+ }
1911
+ }
1912
+ collected.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
1913
+ return {
1914
+ entries: collected.slice(0, limit),
1915
+ legacyFrozen,
1916
+ legacyFrozenBytes
1917
+ };
1918
+ }
1919
+ //#endregion
1920
+ //#region src/secret-store.ts
1921
+ const SECRET_KEY = "AGENTMEMORY_SECRET";
1922
+ function agentmemoryHomeDir() {
1923
+ return process.env["AGENTMEMORY_DATA_DIR"] || join(homedir(), ".agentmemory");
1924
+ }
1925
+ function secretFilePath() {
1926
+ return join(agentmemoryHomeDir(), "secret");
1927
+ }
1928
+ function usable(value) {
1929
+ if (typeof value !== "string") return "";
1930
+ const trimmed = value.trim();
1931
+ if (!trimmed) return "";
1932
+ if (trimmed.startsWith("${") && trimmed.endsWith("}")) return "";
1933
+ return trimmed;
1934
+ }
1935
+ function unquote(value) {
1936
+ const quote = value[0];
1937
+ if ((quote === "\"" || quote === "'") && value.length > 1) {
1938
+ const close = value.indexOf(quote, 1);
1939
+ if (close !== -1) return value.slice(1, close);
1940
+ }
1941
+ const hash = value.indexOf(" #");
1942
+ return hash === -1 ? value : value.slice(0, hash).trim();
1943
+ }
1944
+ function readEnvFileSecret() {
1945
+ let content;
1946
+ try {
1947
+ content = readFileSync(process.env["AGENTMEMORY_ENV_FILE"] || join(homedir(), ".agentmemory", ".env"), "utf-8");
1948
+ } catch {
1949
+ return "";
1950
+ }
1951
+ if (typeof content !== "string") return "";
1952
+ let found = "";
1953
+ for (const line of content.split("\n")) {
1954
+ const trimmed = line.trim();
1955
+ if (trimmed.startsWith("#")) continue;
1956
+ const eq = trimmed.indexOf("=");
1957
+ if (eq === -1) continue;
1958
+ if (trimmed.slice(0, eq).replace(/^export\s+/, "").trim() !== SECRET_KEY) continue;
1959
+ found = usable(unquote(trimmed.slice(eq + 1).trim()));
1960
+ }
1961
+ return found;
1962
+ }
1963
+ function readSecretFile(path) {
1964
+ try {
1965
+ return usable(readFileSync(path, "utf-8"));
1966
+ } catch {
1967
+ return "";
1968
+ }
1969
+ }
1970
+ function legacyDataDirSecretPaths(env = process.env) {
1971
+ const dataDir = env["AGENTMEMORY_DATA_DIR"];
1972
+ if (!dataDir) return [];
1973
+ const paths = [
1974
+ join(dataDir, "secret"),
1975
+ join(dataDir, ".hmac"),
1976
+ join(dataDir, "..", ".hmac")
1977
+ ];
1978
+ return [...new Set(paths.filter((path) => path !== secretFilePath()))];
1979
+ }
1980
+ function readStoredSecret(env = process.env) {
1981
+ const canonicalPath = canonicalSecretPath();
1982
+ const localPath = secretFilePath();
1983
+ const legacyPaths = legacyDataDirSecretPaths(env);
1984
+ return readSecretFile(canonicalPath) || (localPath === canonicalPath ? "" : readSecretFile(localPath)) || legacyPaths.map(readSecretFile).find(Boolean) || "";
1985
+ }
1986
+ function isLoopbackUrl(url) {
1987
+ let hostname;
1988
+ try {
1989
+ hostname = new URL(url).hostname.toLowerCase();
1990
+ } catch {
1991
+ return false;
1992
+ }
1993
+ const bare = hostname.replace(/^\[|\]$/g, "");
1994
+ return bare === "localhost" || bare === "::1" || /^127(?:\.\d{1,3}){3}$/.test(bare);
1995
+ }
1996
+ function resolveClientSecret(baseUrl, env = process.env) {
1997
+ const fromEnv = usable(env[SECRET_KEY]);
1998
+ if (fromEnv) return fromEnv;
1999
+ if (env.AGENTMEMORY_CREDENTIAL_MODE === "explicit") return "";
2000
+ if (!isLoopbackUrl(baseUrl)) return "";
2001
+ return readEnvFileSecret() || readStoredSecret(env);
2002
+ }
2003
+ function canonicalSecretPath() {
2004
+ return join(homedir(), ".agentmemory", "secret");
2005
+ }
1381
2006
  //#endregion
1382
2007
  //#region src/mcp/rest-proxy.ts
1383
2008
  const DEFAULT_URL = "http://localhost:3111";
@@ -1390,11 +2015,22 @@ function probeTimeoutMs() {
1390
2015
  const n = Number(raw);
1391
2016
  return Number.isFinite(n) && n > 0 ? Math.floor(n) : DEFAULT_HEALTH_PROBE_TIMEOUT_MS;
1392
2017
  }
1393
- function forceProxy() {
2018
+ function isProxyRequired() {
1394
2019
  const raw = process.env["AGENTMEMORY_FORCE_PROXY"];
1395
2020
  return raw === "1" || raw === "true";
1396
2021
  }
2022
+ var ProxyCallError = class extends Error {
2023
+ status;
2024
+ body;
2025
+ constructor(message, status, body) {
2026
+ super(message);
2027
+ this.name = "ProxyCallError";
2028
+ this.status = status;
2029
+ this.body = body;
2030
+ }
2031
+ };
1397
2032
  let cached = null;
2033
+ let cachedUrl = null;
1398
2034
  let cachedAt = 0;
1399
2035
  let probeInFlight = null;
1400
2036
  function resolveEnvOrEmpty(name) {
@@ -1404,17 +2040,25 @@ function resolveEnvOrEmpty(name) {
1404
2040
  return raw;
1405
2041
  }
1406
2042
  function baseUrl() {
1407
- return (resolveEnvOrEmpty("AGENTMEMORY_URL") || DEFAULT_URL).replace(/\/+$/, "");
2043
+ const value = resolveEnvOrEmpty("AGENTMEMORY_URL") || DEFAULT_URL;
2044
+ try {
2045
+ const parsed = new URL(value);
2046
+ if (!["http:", "https:"].includes(parsed.protocol) || !parsed.hostname || parsed.username || parsed.password || /[?#\s]/.test(value)) throw new Error();
2047
+ return value.replace(/\/+$/, "");
2048
+ } catch {
2049
+ throw new Error("AGENTMEMORY_URL must be an HTTP(S) URL without credentials, query, or fragment");
2050
+ }
1408
2051
  }
1409
- function authHeader() {
1410
- const secret = resolveEnvOrEmpty("AGENTMEMORY_SECRET");
2052
+ function authHeader(url) {
2053
+ const secret = resolveClientSecret(url);
1411
2054
  return secret ? { authorization: `Bearer ${secret}` } : {};
1412
2055
  }
1413
2056
  const defaultLivezProbe = async (url, timeoutMs, headers) => {
1414
2057
  const res = await fetch(`${url}/agentmemory/livez`, {
1415
2058
  method: "GET",
1416
2059
  headers,
1417
- signal: AbortSignal.timeout(timeoutMs)
2060
+ signal: AbortSignal.timeout(timeoutMs),
2061
+ redirect: "error"
1418
2062
  });
1419
2063
  return {
1420
2064
  ok: res.ok,
@@ -1426,7 +2070,7 @@ let livezProbe = defaultLivezProbe;
1426
2070
  async function probe(url) {
1427
2071
  const timeout = probeTimeoutMs();
1428
2072
  try {
1429
- const res = await livezProbe(url, timeout, authHeader());
2073
+ const res = await livezProbe(url, timeout, authHeader(url));
1430
2074
  if (!res.ok) process.stderr.write(`[@agentmemory/mcp] livez probe ${url}/agentmemory/livez -> ${res.status ?? "?"} ${res.statusText ?? ""}; falling back to local InMemoryKV (set AGENTMEMORY_FORCE_PROXY=1 to skip the probe)\n`);
1431
2075
  return res.ok;
1432
2076
  } catch (err) {
@@ -1436,52 +2080,73 @@ async function probe(url) {
1436
2080
  }
1437
2081
  function invalidateHandle() {
1438
2082
  cached = null;
2083
+ cachedUrl = null;
1439
2084
  cachedAt = 0;
1440
2085
  }
1441
2086
  async function resolveHandle() {
1442
2087
  const now = Date.now();
2088
+ const url = baseUrl();
2089
+ if (cached && (cachedUrl !== url || cached.mode === "local" && isProxyRequired())) invalidateHandle();
1443
2090
  if (cached) if (cached.mode === "local" && now - cachedAt >= LOCAL_MODE_TTL_MS) {
1444
2091
  cached = null;
1445
2092
  cachedAt = 0;
1446
2093
  } else return cached;
1447
- if (probeInFlight) return probeInFlight;
1448
- const url = baseUrl();
1449
- const skipProbe = forceProxy();
1450
- probeInFlight = (async () => {
2094
+ const skipProbe = isProxyRequired();
2095
+ if (probeInFlight?.url === url && probeInFlight.forceProxy === skipProbe) return probeInFlight.promise;
2096
+ const pending = (async () => {
1451
2097
  const up = skipProbe ? true : await probe(url);
2098
+ if (baseUrl() !== url || isProxyRequired() !== skipProbe) return resolveHandle();
1452
2099
  if (skipProbe) process.stderr.write(`[@agentmemory/mcp] AGENTMEMORY_FORCE_PROXY set; skipping livez probe and trusting ${url}\n`);
1453
2100
  if (up) {
1454
2101
  const handle = {
1455
2102
  mode: "proxy",
1456
2103
  baseUrl: url,
1457
2104
  call: async (path, init) => {
2105
+ if (baseUrl() !== url) throw new Error("AgentMemory endpoint changed; resolve a new proxy handle before retrying.");
1458
2106
  const res = await fetch(`${url}${path}`, {
1459
2107
  ...init,
1460
2108
  headers: {
1461
2109
  "content-type": "application/json",
1462
- ...authHeader(),
2110
+ ...authHeader(url),
1463
2111
  ...init?.headers
1464
2112
  },
1465
- signal: AbortSignal.timeout(CALL_TIMEOUT_MS)
2113
+ signal: AbortSignal.timeout(CALL_TIMEOUT_MS),
2114
+ redirect: "error"
1466
2115
  });
1467
- if (!res.ok) throw new Error(`${init?.method || "GET"} ${path} -> ${res.status} ${res.statusText}`);
2116
+ if (!res.ok) {
2117
+ const errText = await res.text().catch(() => "");
2118
+ let errBody = void 0;
2119
+ if (errText) try {
2120
+ errBody = JSON.parse(errText);
2121
+ } catch {
2122
+ errBody = void 0;
2123
+ }
2124
+ throw new ProxyCallError(`${init?.method || "GET"} ${path} -> ${res.status} ${res.statusText}`, res.status, errBody);
2125
+ }
1468
2126
  const text = await res.text();
1469
2127
  return text ? JSON.parse(text) : null;
1470
2128
  }
1471
2129
  };
1472
2130
  cached = handle;
2131
+ cachedUrl = url;
1473
2132
  cachedAt = Date.now();
1474
2133
  return handle;
1475
2134
  }
1476
2135
  const local = { mode: "local" };
1477
2136
  cached = local;
2137
+ cachedUrl = url;
1478
2138
  cachedAt = Date.now();
1479
2139
  return local;
1480
2140
  })();
2141
+ probeInFlight = {
2142
+ url,
2143
+ forceProxy: skipProbe,
2144
+ promise: pending
2145
+ };
1481
2146
  try {
1482
- return await probeInFlight;
2147
+ return await pending;
1483
2148
  } finally {
1484
- probeInFlight = null;
2149
+ if (probeInFlight?.promise === pending) probeInFlight = null;
1485
2150
  }
1486
2151
  }
1487
2152
  //#endregion
@@ -1541,6 +2206,9 @@ function textResponse(payload, pretty = false) {
1541
2206
  text: JSON.stringify(payload, null, pretty ? 2 : 0)
1542
2207
  }] };
1543
2208
  }
2209
+ function isAuthenticationError(error) {
2210
+ return error instanceof ProxyCallError && (error.status === 401 || error.status === 403);
2211
+ }
1544
2212
  function validate(toolName, args) {
1545
2213
  if (!IMPLEMENTED_TOOLS.has(toolName)) throw new Error(`Unknown tool: ${toolName}`);
1546
2214
  const v = { tool: toolName };
@@ -1558,22 +2226,41 @@ function validate(toolName, args) {
1558
2226
  }
1559
2227
  case "memory_recall":
1560
2228
  case "memory_smart_search": {
2229
+ if (args.targetLayer !== void 0 && !isSearchLayer(args.targetLayer)) throw new Error("targetLayer must be one of: all, memory, observation");
2230
+ v.targetLayer = args.targetLayer ?? "all";
2231
+ for (const field of [
2232
+ "project",
2233
+ "cwd",
2234
+ "agentId",
2235
+ "sessionId",
2236
+ "source"
2237
+ ]) {
2238
+ if (args[field] !== void 0 && typeof args[field] !== "string") throw new Error(`${field} must be a string`);
2239
+ if (typeof args[field] === "string" && args[field].trim()) v[field] = args[field].trim();
2240
+ }
2241
+ if (toolName === "memory_smart_search") {
2242
+ v.expandIds = parseSearchExpansionIds(args.expandIds);
2243
+ if (typeof args.includeLessons === "boolean") v.includeLessons = args.includeLessons;
2244
+ }
1561
2245
  const query = args["query"];
1562
- if (typeof query !== "string" || !query.trim()) throw new Error("query is required");
1563
- v.query = query.trim();
2246
+ if (typeof query !== "string" || !query.trim()) {
2247
+ if (!v.expandIds?.length) throw new Error("query is required unless expandIds is provided");
2248
+ } else v.query = query.trim();
1564
2249
  v.limit = parseLimit(args["limit"]);
1565
- const fmt = args["format"];
1566
- if (typeof fmt === "string" && fmt.trim()) v.format = fmt.trim().toLowerCase();
1567
- const budget = args["token_budget"];
1568
- if (typeof budget === "number" && Number.isFinite(budget) && budget > 0) v.tokenBudget = Math.floor(budget);
1569
- else if (typeof budget === "string" && budget.trim()) {
1570
- const n = Number(budget);
1571
- if (Number.isFinite(n) && n > 0) v.tokenBudget = Math.floor(n);
2250
+ if (toolName === "memory_recall") {
2251
+ const format = typeof args.format === "string" ? args.format.trim().toLowerCase() : args.format ?? "full";
2252
+ if (format !== "full" && format !== "compact" && format !== "narrative") throw new Error("format must be one of: full, compact, narrative");
2253
+ v.format = format;
2254
+ if (args.token_budget !== void 0) {
2255
+ const budget = typeof args.token_budget === "string" ? Number(args.token_budget) : args.token_budget;
2256
+ if (typeof budget !== "number" || !Number.isInteger(budget) || budget < 1) throw new Error("token_budget must be a positive integer");
2257
+ v.tokenBudget = budget;
2258
+ }
1572
2259
  }
1573
2260
  return v;
1574
2261
  }
1575
2262
  case "memory_sessions":
1576
- v.limit = parseLimit(args["limit"], 20);
2263
+ v.sessionQuery = parseSessionArguments(args);
1577
2264
  return v;
1578
2265
  case "memory_governance_delete": {
1579
2266
  const ids = normalizeList(args["memoryIds"]);
@@ -1582,7 +2269,22 @@ function validate(toolName, args) {
1582
2269
  v.reason = args["reason"] || "plugin skill request";
1583
2270
  return v;
1584
2271
  }
1585
- case "memory_export": return v;
2272
+ case "memory_export": {
2273
+ const query = new URLSearchParams();
2274
+ for (const key of [
2275
+ "maxSessions",
2276
+ "offset",
2277
+ "collectionLimit",
2278
+ "collectionOffset"
2279
+ ]) {
2280
+ const n = Number(args[key]);
2281
+ const min = key === "maxSessions" || key === "collectionLimit" ? 1 : 0;
2282
+ if (args[key] !== void 0 && Number.isInteger(n) && n >= min) query.set(key, String(n));
2283
+ }
2284
+ if (typeof args["collections"] === "string") query.set("collections", args["collections"]);
2285
+ v.exportQuery = query.toString();
2286
+ return v;
2287
+ }
1586
2288
  case "memory_audit":
1587
2289
  v.limit = parseLimit(args["limit"], 50);
1588
2290
  return v;
@@ -1606,7 +2308,11 @@ async function handleProxy(v, handle) {
1606
2308
  const body = {
1607
2309
  query: v.query,
1608
2310
  limit: v.limit,
1609
- format: v.format ?? "full"
2311
+ format: v.format ?? "full",
2312
+ targetLayer: v.targetLayer,
2313
+ project: v.project,
2314
+ cwd: v.cwd,
2315
+ agentId: v.agentId
1610
2316
  };
1611
2317
  if (v.tokenBudget != null) body["token_budget"] = v.tokenBudget;
1612
2318
  return textResponse(await handle.call("/agentmemory/search", {
@@ -1617,16 +2323,21 @@ async function handleProxy(v, handle) {
1617
2323
  case "memory_smart_search": {
1618
2324
  const body = {
1619
2325
  query: v.query,
1620
- limit: v.limit
2326
+ limit: v.limit,
2327
+ targetLayer: v.targetLayer,
2328
+ project: v.project,
2329
+ agentId: v.agentId,
2330
+ expandIds: v.expandIds,
2331
+ sessionId: v.sessionId,
2332
+ source: v.source,
2333
+ includeLessons: v.includeLessons
1621
2334
  };
1622
- if (v.format != null) body["format"] = v.format;
1623
- if (v.tokenBudget != null) body["token_budget"] = v.tokenBudget;
1624
2335
  return textResponse(await handle.call("/agentmemory/smart-search", {
1625
2336
  method: "POST",
1626
2337
  body: JSON.stringify(body)
1627
2338
  }), true);
1628
2339
  }
1629
- case "memory_sessions": return textResponse(await handle.call(`/agentmemory/sessions?limit=${v.limit}`, { method: "GET" }), true);
2340
+ case "memory_sessions": return textResponse(await handle.call(`/agentmemory/sessions?${new URLSearchParams(v.sessionQuery)}`, { method: "GET" }), true);
1630
2341
  case "memory_governance_delete": return textResponse(await handle.call("/agentmemory/governance/memories", {
1631
2342
  method: "DELETE",
1632
2343
  body: JSON.stringify({
@@ -1634,11 +2345,23 @@ async function handleProxy(v, handle) {
1634
2345
  reason: v.reason
1635
2346
  })
1636
2347
  }));
1637
- case "memory_export": return textResponse(await handle.call("/agentmemory/export", { method: "GET" }), true);
2348
+ case "memory_export": try {
2349
+ return textResponse(await handle.call(`/agentmemory/export${v.exportQuery ? `?${v.exportQuery}` : ""}`, { method: "GET" }), true);
2350
+ } catch (err) {
2351
+ if (err instanceof ProxyCallError && err.status === 413 && err.body != null && typeof err.body === "object" && err.body.oversized === true) return textResponse(err.body, true);
2352
+ throw err;
2353
+ }
1638
2354
  case "memory_audit": return textResponse(await handle.call(`/agentmemory/audit?limit=${v.limit}`, { method: "GET" }), true);
1639
2355
  default: throw new Error(`Unknown tool: ${v.tool}`);
1640
2356
  }
1641
2357
  }
2358
+ function localFallbackNotice(persisted) {
2359
+ const store = persisted ? "the local fallback file, which the server does not read" : "this process's in-memory fallback store, which is lost when the process exits";
2360
+ return {
2361
+ storage: "local",
2362
+ warning: `agentmemory server at ${displayAgentmemoryUrl()} did not confirm this call, so it ran against ${store}.`
2363
+ };
2364
+ }
1642
2365
  async function handleLocal(v, kvInstance) {
1643
2366
  switch (v.tool) {
1644
2367
  case "memory_save": {
@@ -1656,34 +2379,96 @@ async function handleLocal(v, kvInstance) {
1656
2379
  strength: 7,
1657
2380
  version: 1,
1658
2381
  isLatest: true,
1659
- sessionIds: []
2382
+ sessionIds: [],
2383
+ ...v.project !== void 0 && { project: v.project },
2384
+ ...(v.agentId ?? getAgentId()) !== void 0 && { agentId: v.agentId ?? getAgentId() }
2385
+ });
2386
+ return textResponse({
2387
+ saved: id,
2388
+ ...localFallbackNotice(kvInstance.persist())
1660
2389
  });
1661
- kvInstance.persist();
1662
- return textResponse({ saved: id });
1663
2390
  }
1664
2391
  case "memory_recall":
1665
2392
  case "memory_smart_search": {
2393
+ const isolated = isAgentScopeIsolated();
2394
+ const agentId = v.agentId === "*" ? void 0 : v.agentId ?? (isolated ? getAgentId() : void 0);
2395
+ if (isolated && v.agentId !== "*" && !agentId) throw new Error("AGENTMEMORY_AGENT_SCOPE=isolated requires an agentId; pass '*' to read across agents");
1666
2396
  const query = (v.query || "").toLowerCase();
1667
2397
  const limit = v.limit ?? DEFAULT_LIMIT;
2398
+ const all = v.targetLayer === "observation" ? [] : await kvInstance.list("mem:memories");
2399
+ const sessions = v.project || v.cwd ? await kvInstance.list("mem:sessions") : [];
2400
+ const sessionsById = new Map(sessions.map((session) => [session.id, session]));
2401
+ const scoped = all.filter((memory) => {
2402
+ if (memory.isLatest === false || agentId && memory.agentId !== agentId) return false;
2403
+ const linkedSessions = (memory.sessionIds ?? []).map((id) => sessionsById.get(id));
2404
+ if (v.project && (memory.project ? memory.project !== v.project : !linkedSessions.some((session) => session?.project === v.project))) return false;
2405
+ if (v.cwd && !linkedSessions.some((session) => session?.cwd === v.cwd)) return false;
2406
+ return true;
2407
+ });
2408
+ if (v.tool === "memory_smart_search" && v.expandIds?.length) {
2409
+ const ids = v.expandIds.map((entry) => typeof entry === "string" ? entry : entry.obsId);
2410
+ const byId = new Map(scoped.map((memory) => [memory.id, memory]));
2411
+ const eligible = ids.filter((id) => byId.has(id));
2412
+ return textResponse({
2413
+ mode: "expanded",
2414
+ results: eligible.slice(0, 20).map((id) => {
2415
+ const observation = memoryToObservation(byId.get(id));
2416
+ return {
2417
+ obsId: id,
2418
+ sessionId: observation.sessionId,
2419
+ observation,
2420
+ layer: "memory"
2421
+ };
2422
+ }),
2423
+ truncated: eligible.length > 20
2424
+ }, true);
2425
+ }
2426
+ const results = scoped.filter((memory) => {
2427
+ const text = [
2428
+ memory.title,
2429
+ memory.content,
2430
+ ...memory.files ?? [],
2431
+ ...memory.concepts ?? [],
2432
+ ...memory.sessionIds ?? [],
2433
+ memory.id
2434
+ ].join(" ").toLowerCase();
2435
+ return query.split(/\s+/).every((word) => text.includes(word));
2436
+ }).slice(0, limit);
2437
+ if (v.tool === "memory_recall") return textResponse(buildRecallResponse(results.map((memory) => {
2438
+ const observation = memoryToObservation(memory);
2439
+ return {
2440
+ sessionId: observation.sessionId,
2441
+ observation,
2442
+ score: 1,
2443
+ layer: "memory"
2444
+ };
2445
+ }), v.format ?? "full", v.tokenBudget), true);
1668
2446
  return textResponse({
1669
2447
  mode: "compact",
1670
- results: (await kvInstance.list("mem:memories")).filter((m) => {
1671
- const text = [
1672
- typeof m["title"] === "string" ? m["title"] : "",
1673
- typeof m["content"] === "string" ? m["content"] : "",
1674
- Array.isArray(m["files"]) ? m["files"].join(" ") : "",
1675
- Array.isArray(m["concepts"]) ? m["concepts"].join(" ") : "",
1676
- Array.isArray(m["sessionIds"]) ? m["sessionIds"].join(" ") : "",
1677
- typeof m["id"] === "string" ? m["id"] : ""
1678
- ].join(" ").toLowerCase();
1679
- return query.split(/\s+/).every((word) => text.includes(word));
1680
- }).slice(0, limit)
2448
+ results: results.map((memory) => ({
2449
+ ...memory,
2450
+ obsId: memory.id,
2451
+ sessionId: memory.sessionIds?.[0] ?? "memory",
2452
+ layer: "memory"
2453
+ }))
1681
2454
  }, true);
1682
2455
  }
1683
2456
  case "memory_sessions": {
1684
- const sessions = await kvInstance.list("mem:sessions");
1685
- const limit = v.limit ?? 20;
1686
- return textResponse({ sessions: sessions.slice(0, limit) }, true);
2457
+ const query = v.sessionQuery;
2458
+ const agentId = query.agentId === "*" ? void 0 : query.agentId ?? (isAgentScopeIsolated() ? getAgentId() : void 0);
2459
+ const sessions = (await kvInstance.list("mem:sessions")).filter((session) => session && typeof session.id === "string" && session.id.length > 0).filter((session) => !query.project || session.project === query.project).filter((session) => !agentId || session.agentId === agentId);
2460
+ const key = (session) => session.startedAt || "";
2461
+ const { page, nextCursor } = pageAfterCursor(sortByKeyDesc(sessions, key, (session) => session.id), key, (session) => session.id, query.cursor, Number(query.limit));
2462
+ return textResponse({
2463
+ sessions: await Promise.all(page.map(async (session) => {
2464
+ const summary = await kvInstance.get("mem:summaries", session.id);
2465
+ return summary ? {
2466
+ ...session,
2467
+ summary
2468
+ } : session;
2469
+ })),
2470
+ nextCursor
2471
+ }, true);
1687
2472
  }
1688
2473
  case "memory_governance_delete": {
1689
2474
  let deleted = 0;
@@ -1691,11 +2476,12 @@ async function handleLocal(v, kvInstance) {
1691
2476
  await kvInstance.delete("mem:memories", id);
1692
2477
  deleted++;
1693
2478
  }
1694
- kvInstance.persist();
2479
+ const persisted = kvInstance.persist();
1695
2480
  return textResponse({
1696
2481
  deleted,
1697
2482
  requested: (v.memoryIds || []).length,
1698
- reason: v.reason
2483
+ reason: v.reason,
2484
+ ...localFallbackNotice(persisted)
1699
2485
  });
1700
2486
  }
1701
2487
  case "memory_export": return textResponse({
@@ -1703,11 +2489,7 @@ async function handleLocal(v, kvInstance) {
1703
2489
  memories: await kvInstance.list("mem:memories"),
1704
2490
  sessions: await kvInstance.list("mem:sessions")
1705
2491
  }, true);
1706
- case "memory_audit": {
1707
- const entries = await kvInstance.list("mem:audit");
1708
- const limit = v.limit ?? 50;
1709
- return textResponse({ entries: entries.slice(0, limit) }, true);
1710
- }
2492
+ case "memory_audit": return textResponse(await queryAudit(kvInstance, { limit: v.limit ?? 50 }), true);
1711
2493
  default: throw new Error(`Unknown tool: ${v.tool}`);
1712
2494
  }
1713
2495
  }
@@ -1739,6 +2521,10 @@ async function handleToolCall(toolName, args, kvInstance = kv) {
1739
2521
  if (handle.mode === "proxy") try {
1740
2522
  return await handleProxy(validated, handle);
1741
2523
  } catch (err) {
2524
+ if (toolName === "memory_sessions" || isAuthenticationError(err) || isProxyRequired()) {
2525
+ invalidateHandle();
2526
+ throw err;
2527
+ }
1742
2528
  process.stderr.write(`[@agentmemory/mcp] proxy call failed for ${toolName}: ${err instanceof Error ? err.message : String(err)}; invalidating handle and falling back to local KV\n`);
1743
2529
  invalidateHandle();
1744
2530
  }
@@ -1759,10 +2545,12 @@ async function handleToolsList() {
1759
2545
  if (debug) process.stderr.write(`[@agentmemory/mcp] tools/list: returning ${remote.tools.length} tools from server\n`);
1760
2546
  return { tools: remote.tools };
1761
2547
  }
2548
+ if (isProxyRequired()) throw new Error("AgentMemory returned an invalid tool inventory");
1762
2549
  process.stderr.write(`[@agentmemory/mcp] tools/list: server returned unexpected shape (no .tools array); falling back to local IMPLEMENTED_TOOLS list. Set AGENTMEMORY_DEBUG=1 to inspect response.\n`);
1763
2550
  } catch (err) {
1764
- process.stderr.write(`[@agentmemory/mcp] tools/list proxy failed: ${err instanceof Error ? err.message : String(err)}; falling back to local list\n`);
1765
2551
  invalidateHandle();
2552
+ if (isAuthenticationError(err) || isProxyRequired()) throw err;
2553
+ process.stderr.write(`[@agentmemory/mcp] tools/list proxy failed: ${err instanceof Error ? err.message : String(err)}; falling back to local list\n`);
1766
2554
  }
1767
2555
  const fallback = getAllTools().filter((t) => IMPLEMENTED_TOOLS.has(t.name));
1768
2556
  if (debug) process.stderr.write(`[@agentmemory/mcp] tools/list: returning ${fallback.length} local fallback tools (${fallback.map((t) => t.name).join(",")})\n`);