@vinaes/succ 1.4.0 → 1.5.37

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 (683) hide show
  1. package/README.md +64 -10
  2. package/dist/cli.js +71 -1
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/agents-md.d.ts.map +1 -1
  5. package/dist/commands/agents-md.js +3 -2
  6. package/dist/commands/agents-md.js.map +1 -1
  7. package/dist/commands/analyze-profile.d.ts.map +1 -1
  8. package/dist/commands/analyze-profile.js +32 -8
  9. package/dist/commands/analyze-profile.js.map +1 -1
  10. package/dist/commands/analyze-recursive.d.ts.map +1 -1
  11. package/dist/commands/analyze-recursive.js +6 -2
  12. package/dist/commands/analyze-recursive.js.map +1 -1
  13. package/dist/commands/analyze-utils.d.ts.map +1 -1
  14. package/dist/commands/analyze-utils.js +17 -4
  15. package/dist/commands/analyze-utils.js.map +1 -1
  16. package/dist/commands/benchmark-quality.d.ts.map +1 -1
  17. package/dist/commands/benchmark-quality.js +11 -4
  18. package/dist/commands/benchmark-quality.js.map +1 -1
  19. package/dist/commands/benchmark-sqlite-vec.d.ts.map +1 -1
  20. package/dist/commands/benchmark-sqlite-vec.js +4 -0
  21. package/dist/commands/benchmark-sqlite-vec.js.map +1 -1
  22. package/dist/commands/benchmark.d.ts.map +1 -1
  23. package/dist/commands/benchmark.js +5 -1
  24. package/dist/commands/benchmark.js.map +1 -1
  25. package/dist/commands/codex-chat.d.ts +8 -0
  26. package/dist/commands/codex-chat.d.ts.map +1 -0
  27. package/dist/commands/codex-chat.js +161 -0
  28. package/dist/commands/codex-chat.js.map +1 -0
  29. package/dist/commands/config.d.ts.map +1 -1
  30. package/dist/commands/config.js +32 -4
  31. package/dist/commands/config.js.map +1 -1
  32. package/dist/commands/daemon.d.ts.map +1 -1
  33. package/dist/commands/daemon.js +13 -4
  34. package/dist/commands/daemon.js.map +1 -1
  35. package/dist/commands/index-code.d.ts +4 -0
  36. package/dist/commands/index-code.d.ts.map +1 -1
  37. package/dist/commands/index-code.js +1 -1
  38. package/dist/commands/index-code.js.map +1 -1
  39. package/dist/commands/init.d.ts.map +1 -1
  40. package/dist/commands/init.js +305 -203
  41. package/dist/commands/init.js.map +1 -1
  42. package/dist/commands/memories.d.ts.map +1 -1
  43. package/dist/commands/memories.js +25 -14
  44. package/dist/commands/memories.js.map +1 -1
  45. package/dist/commands/progress.d.ts.map +1 -1
  46. package/dist/commands/progress.js +3 -2
  47. package/dist/commands/progress.js.map +1 -1
  48. package/dist/commands/reindex.d.ts.map +1 -1
  49. package/dist/commands/reindex.js +54 -36
  50. package/dist/commands/reindex.js.map +1 -1
  51. package/dist/commands/retention.d.ts.map +1 -1
  52. package/dist/commands/retention.js +7 -5
  53. package/dist/commands/retention.js.map +1 -1
  54. package/dist/commands/scan-code.d.ts +76 -0
  55. package/dist/commands/scan-code.d.ts.map +1 -0
  56. package/dist/commands/scan-code.js +385 -0
  57. package/dist/commands/scan-code.js.map +1 -0
  58. package/dist/commands/score.d.ts.map +1 -1
  59. package/dist/commands/score.js +3 -2
  60. package/dist/commands/score.js.map +1 -1
  61. package/dist/commands/session.d.ts +33 -0
  62. package/dist/commands/session.d.ts.map +1 -0
  63. package/dist/commands/session.js +163 -0
  64. package/dist/commands/session.js.map +1 -0
  65. package/dist/commands/setup.d.ts.map +1 -1
  66. package/dist/commands/setup.js +254 -15
  67. package/dist/commands/setup.js.map +1 -1
  68. package/dist/commands/soul.js +3 -2
  69. package/dist/commands/soul.js.map +1 -1
  70. package/dist/commands/status.d.ts.map +1 -1
  71. package/dist/commands/status.js +14 -5
  72. package/dist/commands/status.js.map +1 -1
  73. package/dist/commands/watch.d.ts.map +1 -1
  74. package/dist/commands/watch.js +13 -4
  75. package/dist/commands/watch.js.map +1 -1
  76. package/dist/daemon/analyzer.d.ts.map +1 -1
  77. package/dist/daemon/analyzer.js +21 -5
  78. package/dist/daemon/analyzer.js.map +1 -1
  79. package/dist/daemon/client.d.ts.map +1 -1
  80. package/dist/daemon/client.js +32 -8
  81. package/dist/daemon/client.js.map +1 -1
  82. package/dist/daemon/routes/analyzer.d.ts +3 -0
  83. package/dist/daemon/routes/analyzer.d.ts.map +1 -0
  84. package/dist/daemon/routes/analyzer.js +27 -0
  85. package/dist/daemon/routes/analyzer.js.map +1 -0
  86. package/dist/daemon/routes/hooks.d.ts +14 -0
  87. package/dist/daemon/routes/hooks.d.ts.map +1 -0
  88. package/dist/daemon/routes/hooks.js +1212 -0
  89. package/dist/daemon/routes/hooks.js.map +1 -0
  90. package/dist/daemon/routes/memory.d.ts +4 -0
  91. package/dist/daemon/routes/memory.d.ts.map +1 -0
  92. package/dist/daemon/routes/memory.js +71 -0
  93. package/dist/daemon/routes/memory.js.map +1 -0
  94. package/dist/daemon/routes/reflection.d.ts +10 -0
  95. package/dist/daemon/routes/reflection.d.ts.map +1 -0
  96. package/dist/daemon/routes/reflection.js +397 -0
  97. package/dist/daemon/routes/reflection.js.map +1 -0
  98. package/dist/daemon/routes/search.d.ts +5 -0
  99. package/dist/daemon/routes/search.d.ts.map +1 -0
  100. package/dist/daemon/routes/search.js +93 -0
  101. package/dist/daemon/routes/search.js.map +1 -0
  102. package/dist/daemon/routes/sessions.d.ts +3 -0
  103. package/dist/daemon/routes/sessions.d.ts.map +1 -0
  104. package/dist/daemon/routes/sessions.js +160 -0
  105. package/dist/daemon/routes/sessions.js.map +1 -0
  106. package/dist/daemon/routes/skills.d.ts +3 -0
  107. package/dist/daemon/routes/skills.d.ts.map +1 -0
  108. package/dist/daemon/routes/skills.js +36 -0
  109. package/dist/daemon/routes/skills.js.map +1 -0
  110. package/dist/daemon/routes/status.d.ts +3 -0
  111. package/dist/daemon/routes/status.d.ts.map +1 -0
  112. package/dist/daemon/routes/status.js +47 -0
  113. package/dist/daemon/routes/status.js.map +1 -0
  114. package/dist/daemon/routes/types.d.ts +240 -0
  115. package/dist/daemon/routes/types.d.ts.map +1 -0
  116. package/dist/daemon/routes/types.js +97 -0
  117. package/dist/daemon/routes/types.js.map +1 -0
  118. package/dist/daemon/routes/versioning.d.ts +27 -0
  119. package/dist/daemon/routes/versioning.d.ts.map +1 -0
  120. package/dist/daemon/routes/versioning.js +44 -0
  121. package/dist/daemon/routes/versioning.js.map +1 -0
  122. package/dist/daemon/routes/watcher.d.ts +3 -0
  123. package/dist/daemon/routes/watcher.d.ts.map +1 -0
  124. package/dist/daemon/routes/watcher.js +28 -0
  125. package/dist/daemon/routes/watcher.js.map +1 -0
  126. package/dist/daemon/service.d.ts +5 -23
  127. package/dist/daemon/service.d.ts.map +1 -1
  128. package/dist/daemon/service.js +177 -935
  129. package/dist/daemon/service.js.map +1 -1
  130. package/dist/daemon/session-processor.d.ts +4 -8
  131. package/dist/daemon/session-processor.d.ts.map +1 -1
  132. package/dist/daemon/session-processor.js +39 -38
  133. package/dist/daemon/session-processor.js.map +1 -1
  134. package/dist/lib/ai-readiness.d.ts.map +1 -1
  135. package/dist/lib/ai-readiness.js +33 -8
  136. package/dist/lib/ai-readiness.js.map +1 -1
  137. package/dist/lib/analyze-state.d.ts.map +1 -1
  138. package/dist/lib/analyze-state.js +25 -3
  139. package/dist/lib/analyze-state.js.map +1 -1
  140. package/dist/lib/auto-memory/consolidation.d.ts +41 -0
  141. package/dist/lib/auto-memory/consolidation.d.ts.map +1 -0
  142. package/dist/lib/auto-memory/consolidation.js +151 -0
  143. package/dist/lib/auto-memory/consolidation.js.map +1 -0
  144. package/dist/lib/bpe.d.ts.map +1 -1
  145. package/dist/lib/bpe.js +9 -10
  146. package/dist/lib/bpe.js.map +1 -1
  147. package/dist/lib/brain-export.d.ts +65 -0
  148. package/dist/lib/brain-export.d.ts.map +1 -0
  149. package/dist/lib/brain-export.js +413 -0
  150. package/dist/lib/brain-export.js.map +1 -0
  151. package/dist/lib/checkpoint.d.ts.map +1 -1
  152. package/dist/lib/checkpoint.js +22 -6
  153. package/dist/lib/checkpoint.js.map +1 -1
  154. package/dist/lib/chunker.d.ts.map +1 -1
  155. package/dist/lib/chunker.js +6 -1
  156. package/dist/lib/chunker.js.map +1 -1
  157. package/dist/lib/claude-ws-transport.d.ts.map +1 -1
  158. package/dist/lib/claude-ws-transport.js +12 -4
  159. package/dist/lib/claude-ws-transport.js.map +1 -1
  160. package/dist/lib/command-safety.d.ts +64 -0
  161. package/dist/lib/command-safety.d.ts.map +1 -0
  162. package/dist/lib/command-safety.js +625 -0
  163. package/dist/lib/command-safety.js.map +1 -0
  164. package/dist/lib/compact-briefing.d.ts.map +1 -1
  165. package/dist/lib/compact-briefing.js +10 -13
  166. package/dist/lib/compact-briefing.js.map +1 -1
  167. package/dist/lib/config-defaults.d.ts.map +1 -1
  168. package/dist/lib/config-defaults.js +3 -0
  169. package/dist/lib/config-defaults.js.map +1 -1
  170. package/dist/lib/config-display.d.ts +4 -0
  171. package/dist/lib/config-display.d.ts.map +1 -1
  172. package/dist/lib/config-display.js +6 -1
  173. package/dist/lib/config-display.js.map +1 -1
  174. package/dist/lib/config-types.d.ts +149 -0
  175. package/dist/lib/config-types.d.ts.map +1 -1
  176. package/dist/lib/config-validation.d.ts.map +1 -1
  177. package/dist/lib/config-validation.js +5 -0
  178. package/dist/lib/config-validation.js.map +1 -1
  179. package/dist/lib/config.d.ts.map +1 -1
  180. package/dist/lib/config.js +92 -9
  181. package/dist/lib/config.js.map +1 -1
  182. package/dist/lib/consolidate.d.ts.map +1 -1
  183. package/dist/lib/consolidate.js +66 -47
  184. package/dist/lib/consolidate.js.map +1 -1
  185. package/dist/lib/content-sanitizer.d.ts +29 -0
  186. package/dist/lib/content-sanitizer.d.ts.map +1 -0
  187. package/dist/lib/content-sanitizer.js +72 -0
  188. package/dist/lib/content-sanitizer.js.map +1 -0
  189. package/dist/lib/cross-repo.d.ts +44 -0
  190. package/dist/lib/cross-repo.d.ts.map +1 -0
  191. package/dist/lib/cross-repo.js +108 -0
  192. package/dist/lib/cross-repo.js.map +1 -0
  193. package/dist/lib/daemon-port.d.ts +12 -0
  194. package/dist/lib/daemon-port.d.ts.map +1 -0
  195. package/dist/lib/daemon-port.js +20 -0
  196. package/dist/lib/daemon-port.js.map +1 -0
  197. package/dist/lib/db/auto-memory.d.ts +40 -0
  198. package/dist/lib/db/auto-memory.d.ts.map +1 -0
  199. package/dist/lib/db/auto-memory.js +74 -0
  200. package/dist/lib/db/auto-memory.js.map +1 -0
  201. package/dist/lib/db/bm25-indexes.d.ts.map +1 -1
  202. package/dist/lib/db/bm25-indexes.js +16 -4
  203. package/dist/lib/db/bm25-indexes.js.map +1 -1
  204. package/dist/lib/db/documents.d.ts.map +1 -1
  205. package/dist/lib/db/documents.js +4 -1
  206. package/dist/lib/db/documents.js.map +1 -1
  207. package/dist/lib/db/global-memories.d.ts +2 -10
  208. package/dist/lib/db/global-memories.d.ts.map +1 -1
  209. package/dist/lib/db/global-memories.js +13 -6
  210. package/dist/lib/db/global-memories.js.map +1 -1
  211. package/dist/lib/db/graph.d.ts +5 -1
  212. package/dist/lib/db/graph.d.ts.map +1 -1
  213. package/dist/lib/db/graph.js +38 -8
  214. package/dist/lib/db/graph.js.map +1 -1
  215. package/dist/lib/db/hybrid-search.d.ts +4 -2
  216. package/dist/lib/db/hybrid-search.d.ts.map +1 -1
  217. package/dist/lib/db/hybrid-search.js +29 -11
  218. package/dist/lib/db/hybrid-search.js.map +1 -1
  219. package/dist/lib/db/index.d.ts +6 -1
  220. package/dist/lib/db/index.d.ts.map +1 -1
  221. package/dist/lib/db/index.js +5 -1
  222. package/dist/lib/db/index.js.map +1 -1
  223. package/dist/lib/db/memories.d.ts +19 -14
  224. package/dist/lib/db/memories.d.ts.map +1 -1
  225. package/dist/lib/db/memories.js +100 -37
  226. package/dist/lib/db/memories.js.map +1 -1
  227. package/dist/lib/db/parse-helpers.d.ts +14 -0
  228. package/dist/lib/db/parse-helpers.d.ts.map +1 -0
  229. package/dist/lib/db/parse-helpers.js +59 -0
  230. package/dist/lib/db/parse-helpers.js.map +1 -0
  231. package/dist/lib/db/recall-events.d.ts +49 -0
  232. package/dist/lib/db/recall-events.d.ts.map +1 -0
  233. package/dist/lib/db/recall-events.js +196 -0
  234. package/dist/lib/db/recall-events.js.map +1 -0
  235. package/dist/lib/db/retention.d.ts +4 -3
  236. package/dist/lib/db/retention.d.ts.map +1 -1
  237. package/dist/lib/db/retention.js +12 -1
  238. package/dist/lib/db/retention.js.map +1 -1
  239. package/dist/lib/db/schema.d.ts +2 -0
  240. package/dist/lib/db/schema.d.ts.map +1 -1
  241. package/dist/lib/db/schema.js +140 -80
  242. package/dist/lib/db/schema.js.map +1 -1
  243. package/dist/lib/db/skills.d.ts.map +1 -1
  244. package/dist/lib/db/skills.js +10 -6
  245. package/dist/lib/db/skills.js.map +1 -1
  246. package/dist/lib/diff-brain.d.ts +24 -0
  247. package/dist/lib/diff-brain.d.ts.map +1 -0
  248. package/dist/lib/diff-brain.js +114 -0
  249. package/dist/lib/diff-brain.js.map +1 -0
  250. package/dist/lib/diff-parser.d.ts +74 -0
  251. package/dist/lib/diff-parser.d.ts.map +1 -0
  252. package/dist/lib/diff-parser.js +200 -0
  253. package/dist/lib/diff-parser.js.map +1 -0
  254. package/dist/lib/embedding-pool.d.ts.map +1 -1
  255. package/dist/lib/embedding-pool.js +5 -1
  256. package/dist/lib/embedding-pool.js.map +1 -1
  257. package/dist/lib/embeddings.d.ts +12 -0
  258. package/dist/lib/embeddings.d.ts.map +1 -1
  259. package/dist/lib/embeddings.js +77 -19
  260. package/dist/lib/embeddings.js.map +1 -1
  261. package/dist/lib/errors.d.ts +2 -0
  262. package/dist/lib/errors.d.ts.map +1 -1
  263. package/dist/lib/errors.js +4 -0
  264. package/dist/lib/errors.js.map +1 -1
  265. package/dist/lib/fault-logger.d.ts.map +1 -1
  266. package/dist/lib/fault-logger.js +22 -7
  267. package/dist/lib/fault-logger.js.map +1 -1
  268. package/dist/lib/git/co-change.d.ts +39 -0
  269. package/dist/lib/git/co-change.d.ts.map +1 -0
  270. package/dist/lib/git/co-change.js +139 -0
  271. package/dist/lib/git/co-change.js.map +1 -0
  272. package/dist/lib/graph/bridge-edges.d.ts +93 -0
  273. package/dist/lib/graph/bridge-edges.d.ts.map +1 -0
  274. package/dist/lib/graph/bridge-edges.js +276 -0
  275. package/dist/lib/graph/bridge-edges.js.map +1 -0
  276. package/dist/lib/graph/centrality.d.ts +11 -0
  277. package/dist/lib/graph/centrality.d.ts.map +1 -1
  278. package/dist/lib/graph/centrality.js +51 -3
  279. package/dist/lib/graph/centrality.js.map +1 -1
  280. package/dist/lib/graph/cleanup.d.ts.map +1 -1
  281. package/dist/lib/graph/cleanup.js +2 -1
  282. package/dist/lib/graph/cleanup.js.map +1 -1
  283. package/dist/lib/graph/community-detection.d.ts +17 -2
  284. package/dist/lib/graph/community-detection.d.ts.map +1 -1
  285. package/dist/lib/graph/community-detection.js +147 -48
  286. package/dist/lib/graph/community-detection.js.map +1 -1
  287. package/dist/lib/graph/community-summaries.d.ts +26 -0
  288. package/dist/lib/graph/community-summaries.d.ts.map +1 -0
  289. package/dist/lib/graph/community-summaries.js +130 -0
  290. package/dist/lib/graph/community-summaries.js.map +1 -0
  291. package/dist/lib/graph/contextual-proximity.d.ts.map +1 -1
  292. package/dist/lib/graph/contextual-proximity.js +11 -4
  293. package/dist/lib/graph/contextual-proximity.js.map +1 -1
  294. package/dist/lib/graph/graphology-bridge.d.ts +101 -0
  295. package/dist/lib/graph/graphology-bridge.d.ts.map +1 -0
  296. package/dist/lib/graph/graphology-bridge.js +488 -0
  297. package/dist/lib/graph/graphology-bridge.js.map +1 -0
  298. package/dist/lib/graph/llm-relations.d.ts.map +1 -1
  299. package/dist/lib/graph/llm-relations.js +27 -5
  300. package/dist/lib/graph/llm-relations.js.map +1 -1
  301. package/dist/lib/graph-export.d.ts.map +1 -1
  302. package/dist/lib/graph-export.js +2 -2
  303. package/dist/lib/graph-export.js.map +1 -1
  304. package/dist/lib/graph-scheduler.d.ts +0 -5
  305. package/dist/lib/graph-scheduler.d.ts.map +1 -1
  306. package/dist/lib/graph-scheduler.js +5 -1
  307. package/dist/lib/graph-scheduler.js.map +1 -1
  308. package/dist/lib/guardrails.d.ts +50 -0
  309. package/dist/lib/guardrails.d.ts.map +1 -0
  310. package/dist/lib/guardrails.js +502 -0
  311. package/dist/lib/guardrails.js.map +1 -0
  312. package/dist/lib/hook-rules.d.ts +1 -1
  313. package/dist/lib/hook-rules.d.ts.map +1 -1
  314. package/dist/lib/hook-rules.js +8 -2
  315. package/dist/lib/hook-rules.js.map +1 -1
  316. package/dist/lib/ifc/file-labels.d.ts +35 -0
  317. package/dist/lib/ifc/file-labels.d.ts.map +1 -0
  318. package/dist/lib/ifc/file-labels.js +208 -0
  319. package/dist/lib/ifc/file-labels.js.map +1 -0
  320. package/dist/lib/ifc/label.d.ts +38 -0
  321. package/dist/lib/ifc/label.d.ts.map +1 -0
  322. package/dist/lib/ifc/label.js +80 -0
  323. package/dist/lib/ifc/label.js.map +1 -0
  324. package/dist/lib/ifc/session-ifc.d.ts +92 -0
  325. package/dist/lib/ifc/session-ifc.d.ts.map +1 -0
  326. package/dist/lib/ifc/session-ifc.js +222 -0
  327. package/dist/lib/ifc/session-ifc.js.map +1 -0
  328. package/dist/lib/indexer.js +2 -2
  329. package/dist/lib/indexer.js.map +1 -1
  330. package/dist/lib/injection-detector.d.ts +83 -0
  331. package/dist/lib/injection-detector.d.ts.map +1 -0
  332. package/dist/lib/injection-detector.js +586 -0
  333. package/dist/lib/injection-detector.js.map +1 -0
  334. package/dist/lib/injection-semantic.d.ts +31 -0
  335. package/dist/lib/injection-semantic.d.ts.map +1 -0
  336. package/dist/lib/injection-semantic.js +230 -0
  337. package/dist/lib/injection-semantic.js.map +1 -0
  338. package/dist/lib/llm.d.ts.map +1 -1
  339. package/dist/lib/llm.js +19 -4
  340. package/dist/lib/llm.js.map +1 -1
  341. package/dist/lib/lock.d.ts.map +1 -1
  342. package/dist/lib/lock.js +24 -3
  343. package/dist/lib/lock.js.map +1 -1
  344. package/dist/lib/md-fetch.d.ts.map +1 -1
  345. package/dist/lib/md-fetch.js +9 -2
  346. package/dist/lib/md-fetch.js.map +1 -1
  347. package/dist/lib/observability.d.ts +75 -0
  348. package/dist/lib/observability.d.ts.map +1 -0
  349. package/dist/lib/observability.js +201 -0
  350. package/dist/lib/observability.js.map +1 -0
  351. package/dist/lib/ort-session.d.ts +26 -0
  352. package/dist/lib/ort-session.d.ts.map +1 -1
  353. package/dist/lib/ort-session.js +107 -3
  354. package/dist/lib/ort-session.js.map +1 -1
  355. package/dist/lib/prd/codebase-context.d.ts.map +1 -1
  356. package/dist/lib/prd/codebase-context.js +9 -2
  357. package/dist/lib/prd/codebase-context.js.map +1 -1
  358. package/dist/lib/prd/context.d.ts.map +1 -1
  359. package/dist/lib/prd/context.js +11 -3
  360. package/dist/lib/prd/context.js.map +1 -1
  361. package/dist/lib/prd/export.js +1 -1
  362. package/dist/lib/prd/export.js.map +1 -1
  363. package/dist/lib/prd/generate.d.ts.map +1 -1
  364. package/dist/lib/prd/generate.js +17 -4
  365. package/dist/lib/prd/generate.js.map +1 -1
  366. package/dist/lib/prd/parse.d.ts.map +1 -1
  367. package/dist/lib/prd/parse.js +6 -1
  368. package/dist/lib/prd/parse.js.map +1 -1
  369. package/dist/lib/prd/runner.d.ts +1 -2
  370. package/dist/lib/prd/runner.d.ts.map +1 -1
  371. package/dist/lib/prd/runner.js +43 -32
  372. package/dist/lib/prd/runner.js.map +1 -1
  373. package/dist/lib/prd/worktree.d.ts +1 -2
  374. package/dist/lib/prd/worktree.d.ts.map +1 -1
  375. package/dist/lib/prd/worktree.js +62 -70
  376. package/dist/lib/prd/worktree.js.map +1 -1
  377. package/dist/lib/precompute-context.d.ts.map +1 -1
  378. package/dist/lib/precompute-context.js +15 -34
  379. package/dist/lib/precompute-context.js.map +1 -1
  380. package/dist/lib/pricing.d.ts.map +1 -1
  381. package/dist/lib/pricing.js +5 -1
  382. package/dist/lib/pricing.js.map +1 -1
  383. package/dist/lib/process-registry.js +3 -3
  384. package/dist/lib/process-registry.js.map +1 -1
  385. package/dist/lib/public-api.d.ts +41 -1
  386. package/dist/lib/public-api.d.ts.map +1 -1
  387. package/dist/lib/public-api.js +38 -0
  388. package/dist/lib/public-api.js.map +1 -1
  389. package/dist/lib/quality.d.ts.map +1 -1
  390. package/dist/lib/quality.js +15 -6
  391. package/dist/lib/quality.js.map +1 -1
  392. package/dist/lib/query-expansion.d.ts +32 -0
  393. package/dist/lib/query-expansion.d.ts.map +1 -1
  394. package/dist/lib/query-expansion.js +62 -1
  395. package/dist/lib/query-expansion.js.map +1 -1
  396. package/dist/lib/reference-embeddings.d.ts.map +1 -1
  397. package/dist/lib/reference-embeddings.js +17 -4
  398. package/dist/lib/reference-embeddings.js.map +1 -1
  399. package/dist/lib/reflection-synthesizer.d.ts.map +1 -1
  400. package/dist/lib/reflection-synthesizer.js +7 -1
  401. package/dist/lib/reflection-synthesizer.js.map +1 -1
  402. package/dist/lib/reranker.d.ts +41 -0
  403. package/dist/lib/reranker.d.ts.map +1 -0
  404. package/dist/lib/reranker.js +294 -0
  405. package/dist/lib/reranker.js.map +1 -0
  406. package/dist/lib/retrieval-feedback.d.ts +100 -0
  407. package/dist/lib/retrieval-feedback.d.ts.map +1 -0
  408. package/dist/lib/retrieval-feedback.js +174 -0
  409. package/dist/lib/retrieval-feedback.js.map +1 -0
  410. package/dist/lib/review/context-pack.d.ts +58 -0
  411. package/dist/lib/review/context-pack.d.ts.map +1 -0
  412. package/dist/lib/review/context-pack.js +300 -0
  413. package/dist/lib/review/context-pack.js.map +1 -0
  414. package/dist/lib/search/hierarchical-summaries.d.ts +65 -0
  415. package/dist/lib/search/hierarchical-summaries.d.ts.map +1 -0
  416. package/dist/lib/search/hierarchical-summaries.js +423 -0
  417. package/dist/lib/search/hierarchical-summaries.js.map +1 -0
  418. package/dist/lib/search/hyde.d.ts +27 -0
  419. package/dist/lib/search/hyde.d.ts.map +1 -0
  420. package/dist/lib/search/hyde.js +141 -0
  421. package/dist/lib/search/hyde.js.map +1 -0
  422. package/dist/lib/search/late-chunking.d.ts +53 -0
  423. package/dist/lib/search/late-chunking.d.ts.map +1 -0
  424. package/dist/lib/search/late-chunking.js +230 -0
  425. package/dist/lib/search/late-chunking.js.map +1 -0
  426. package/dist/lib/search/ppr-retrieval.d.ts +49 -0
  427. package/dist/lib/search/ppr-retrieval.d.ts.map +1 -0
  428. package/dist/lib/search/ppr-retrieval.js +135 -0
  429. package/dist/lib/search/ppr-retrieval.js.map +1 -0
  430. package/dist/lib/search/repo-map.d.ts +43 -0
  431. package/dist/lib/search/repo-map.d.ts.map +1 -0
  432. package/dist/lib/search/repo-map.js +165 -0
  433. package/dist/lib/search/repo-map.js.map +1 -0
  434. package/dist/lib/session-analyzer.d.ts +90 -0
  435. package/dist/lib/session-analyzer.d.ts.map +1 -0
  436. package/dist/lib/session-analyzer.js +467 -0
  437. package/dist/lib/session-analyzer.js.map +1 -0
  438. package/dist/lib/session-observations.d.ts.map +1 -1
  439. package/dist/lib/session-observations.js +13 -3
  440. package/dist/lib/session-observations.js.map +1 -1
  441. package/dist/lib/session-summary.d.ts.map +1 -1
  442. package/dist/lib/session-summary.js +57 -50
  443. package/dist/lib/session-summary.js.map +1 -1
  444. package/dist/lib/session-surgeon.d.ts +53 -0
  445. package/dist/lib/session-surgeon.d.ts.map +1 -0
  446. package/dist/lib/session-surgeon.js +501 -0
  447. package/dist/lib/session-surgeon.js.map +1 -0
  448. package/dist/lib/similarity-utils.d.ts +26 -0
  449. package/dist/lib/similarity-utils.d.ts.map +1 -0
  450. package/dist/lib/similarity-utils.js +66 -0
  451. package/dist/lib/similarity-utils.js.map +1 -0
  452. package/dist/lib/skills.d.ts.map +1 -1
  453. package/dist/lib/skills.js +11 -11
  454. package/dist/lib/skills.js.map +1 -1
  455. package/dist/lib/storage/backends/interface.d.ts +13 -3
  456. package/dist/lib/storage/backends/interface.d.ts.map +1 -1
  457. package/dist/lib/storage/backends/postgresql.d.ts +52 -3
  458. package/dist/lib/storage/backends/postgresql.d.ts.map +1 -1
  459. package/dist/lib/storage/backends/postgresql.js +694 -49
  460. package/dist/lib/storage/backends/postgresql.js.map +1 -1
  461. package/dist/lib/storage/benchmark.js +2 -2
  462. package/dist/lib/storage/benchmark.js.map +1 -1
  463. package/dist/lib/storage/dispatcher/base.d.ts +114 -0
  464. package/dist/lib/storage/dispatcher/base.d.ts.map +1 -0
  465. package/dist/lib/storage/dispatcher/base.js +160 -0
  466. package/dist/lib/storage/dispatcher/base.js.map +1 -0
  467. package/dist/lib/storage/dispatcher/documents.d.ts +25 -0
  468. package/dist/lib/storage/dispatcher/documents.d.ts.map +1 -0
  469. package/dist/lib/storage/dispatcher/documents.js +194 -0
  470. package/dist/lib/storage/dispatcher/documents.js.map +1 -0
  471. package/dist/lib/storage/dispatcher/embeddings.d.ts +34 -0
  472. package/dist/lib/storage/dispatcher/embeddings.d.ts.map +1 -0
  473. package/dist/lib/storage/dispatcher/embeddings.js +144 -0
  474. package/dist/lib/storage/dispatcher/embeddings.js.map +1 -0
  475. package/dist/lib/storage/dispatcher/export-import.d.ts +139 -0
  476. package/dist/lib/storage/dispatcher/export-import.d.ts.map +1 -0
  477. package/dist/lib/storage/dispatcher/export-import.js +191 -0
  478. package/dist/lib/storage/dispatcher/export-import.js.map +1 -0
  479. package/dist/lib/storage/dispatcher/file-hashes.d.ts +13 -0
  480. package/dist/lib/storage/dispatcher/file-hashes.d.ts.map +1 -0
  481. package/dist/lib/storage/dispatcher/file-hashes.js +36 -0
  482. package/dist/lib/storage/dispatcher/file-hashes.js.map +1 -0
  483. package/dist/lib/storage/dispatcher/global-memories.d.ts +28 -0
  484. package/dist/lib/storage/dispatcher/global-memories.d.ts.map +1 -0
  485. package/dist/lib/storage/dispatcher/global-memories.js +151 -0
  486. package/dist/lib/storage/dispatcher/global-memories.js.map +1 -0
  487. package/dist/lib/storage/dispatcher/graph.d.ts +32 -0
  488. package/dist/lib/storage/dispatcher/graph.d.ts.map +1 -0
  489. package/dist/lib/storage/dispatcher/graph.js +146 -0
  490. package/dist/lib/storage/dispatcher/graph.js.map +1 -0
  491. package/dist/lib/storage/dispatcher/index.d.ts +34 -0
  492. package/dist/lib/storage/dispatcher/index.d.ts.map +1 -0
  493. package/dist/lib/storage/dispatcher/index.js +139 -0
  494. package/dist/lib/storage/dispatcher/index.js.map +1 -0
  495. package/dist/lib/storage/dispatcher/memories.d.ts +65 -0
  496. package/dist/lib/storage/dispatcher/memories.d.ts.map +1 -0
  497. package/dist/lib/storage/dispatcher/memories.js +466 -0
  498. package/dist/lib/storage/dispatcher/memories.js.map +1 -0
  499. package/dist/lib/storage/dispatcher/mixin-helper.d.ts +6 -0
  500. package/dist/lib/storage/dispatcher/mixin-helper.d.ts.map +1 -0
  501. package/dist/lib/storage/dispatcher/mixin-helper.js +10 -0
  502. package/dist/lib/storage/dispatcher/mixin-helper.js.map +1 -0
  503. package/dist/lib/storage/dispatcher/retention.d.ts +20 -0
  504. package/dist/lib/storage/dispatcher/retention.d.ts.map +1 -0
  505. package/dist/lib/storage/dispatcher/retention.js +123 -0
  506. package/dist/lib/storage/dispatcher/retention.js.map +1 -0
  507. package/dist/lib/storage/dispatcher/search.d.ts +34 -0
  508. package/dist/lib/storage/dispatcher/search.d.ts.map +1 -0
  509. package/dist/lib/storage/dispatcher/search.js +222 -0
  510. package/dist/lib/storage/dispatcher/search.js.map +1 -0
  511. package/dist/lib/storage/dispatcher/skills.d.ts +53 -0
  512. package/dist/lib/storage/dispatcher/skills.d.ts.map +1 -0
  513. package/dist/lib/storage/dispatcher/skills.js +98 -0
  514. package/dist/lib/storage/dispatcher/skills.js.map +1 -0
  515. package/dist/lib/storage/dispatcher/token-stats.d.ts +23 -0
  516. package/dist/lib/storage/dispatcher/token-stats.d.ts.map +1 -0
  517. package/dist/lib/storage/dispatcher/token-stats.js +92 -0
  518. package/dist/lib/storage/dispatcher/token-stats.js.map +1 -0
  519. package/dist/lib/storage/dispatcher/web-search.d.ts +10 -0
  520. package/dist/lib/storage/dispatcher/web-search.d.ts.map +1 -0
  521. package/dist/lib/storage/dispatcher/web-search.js +39 -0
  522. package/dist/lib/storage/dispatcher/web-search.js.map +1 -0
  523. package/dist/lib/storage/dispatcher-export.d.ts.map +1 -1
  524. package/dist/lib/storage/dispatcher-export.js +48 -39
  525. package/dist/lib/storage/dispatcher-export.js.map +1 -1
  526. package/dist/lib/storage/dispatcher.d.ts +1 -468
  527. package/dist/lib/storage/dispatcher.d.ts.map +1 -1
  528. package/dist/lib/storage/dispatcher.js +1 -1931
  529. package/dist/lib/storage/dispatcher.js.map +1 -1
  530. package/dist/lib/storage/index.d.ts +20 -5
  531. package/dist/lib/storage/index.d.ts.map +1 -1
  532. package/dist/lib/storage/index.js +36 -7
  533. package/dist/lib/storage/index.js.map +1 -1
  534. package/dist/lib/storage/migration/export-import.d.ts.map +1 -1
  535. package/dist/lib/storage/migration/export-import.js +9 -2
  536. package/dist/lib/storage/migration/export-import.js.map +1 -1
  537. package/dist/lib/storage/types.d.ts +152 -10
  538. package/dist/lib/storage/types.d.ts.map +1 -1
  539. package/dist/lib/storage/types.js +13 -0
  540. package/dist/lib/storage/types.js.map +1 -1
  541. package/dist/lib/storage/vector/interface.d.ts +4 -0
  542. package/dist/lib/storage/vector/interface.d.ts.map +1 -1
  543. package/dist/lib/storage/vector/qdrant.d.ts +13 -2
  544. package/dist/lib/storage/vector/qdrant.d.ts.map +1 -1
  545. package/dist/lib/storage/vector/qdrant.js +147 -61
  546. package/dist/lib/storage/vector/qdrant.js.map +1 -1
  547. package/dist/lib/token-budget.d.ts.map +1 -1
  548. package/dist/lib/token-budget.js +9 -2
  549. package/dist/lib/token-budget.js.map +1 -1
  550. package/dist/lib/transcript-utils.d.ts +60 -0
  551. package/dist/lib/transcript-utils.d.ts.map +1 -0
  552. package/dist/lib/transcript-utils.js +69 -0
  553. package/dist/lib/transcript-utils.js.map +1 -0
  554. package/dist/lib/tree-sitter/extractor.d.ts +1 -1
  555. package/dist/lib/tree-sitter/extractor.d.ts.map +1 -1
  556. package/dist/lib/tree-sitter/extractor.js +34 -9
  557. package/dist/lib/tree-sitter/extractor.js.map +1 -1
  558. package/dist/lib/tree-sitter/parser.d.ts.map +1 -1
  559. package/dist/lib/tree-sitter/parser.js +45 -11
  560. package/dist/lib/tree-sitter/parser.js.map +1 -1
  561. package/dist/lib/tree-sitter/public.d.ts +12 -0
  562. package/dist/lib/tree-sitter/public.d.ts.map +1 -1
  563. package/dist/lib/tree-sitter/public.js +33 -1
  564. package/dist/lib/tree-sitter/public.js.map +1 -1
  565. package/dist/lib/tree-sitter/queries.d.ts.map +1 -1
  566. package/dist/lib/tree-sitter/queries.js +8 -0
  567. package/dist/lib/tree-sitter/queries.js.map +1 -1
  568. package/dist/lib/working-memory-pipeline.d.ts.map +1 -1
  569. package/dist/lib/working-memory-pipeline.js +12 -3
  570. package/dist/lib/working-memory-pipeline.js.map +1 -1
  571. package/dist/lib/worktree-detect.d.ts +43 -0
  572. package/dist/lib/worktree-detect.d.ts.map +1 -0
  573. package/dist/lib/worktree-detect.js +154 -0
  574. package/dist/lib/worktree-detect.js.map +1 -0
  575. package/dist/lsp/client.d.ts +96 -0
  576. package/dist/lsp/client.d.ts.map +1 -0
  577. package/dist/lsp/client.js +435 -0
  578. package/dist/lsp/client.js.map +1 -0
  579. package/dist/lsp/installer.d.ts +39 -0
  580. package/dist/lsp/installer.d.ts.map +1 -0
  581. package/dist/lsp/installer.js +275 -0
  582. package/dist/lsp/installer.js.map +1 -0
  583. package/dist/lsp/manager.d.ts +62 -0
  584. package/dist/lsp/manager.d.ts.map +1 -0
  585. package/dist/lsp/manager.js +234 -0
  586. package/dist/lsp/manager.js.map +1 -0
  587. package/dist/lsp/servers.d.ts +52 -0
  588. package/dist/lsp/servers.d.ts.map +1 -0
  589. package/dist/lsp/servers.js +162 -0
  590. package/dist/lsp/servers.js.map +1 -0
  591. package/dist/mcp/helpers.d.ts.map +1 -1
  592. package/dist/mcp/helpers.js +8 -2
  593. package/dist/mcp/helpers.js.map +1 -1
  594. package/dist/mcp/profile.js +1 -1
  595. package/dist/mcp/server.d.ts +3 -2
  596. package/dist/mcp/server.d.ts.map +1 -1
  597. package/dist/mcp/server.js +19 -7
  598. package/dist/mcp/server.js.map +1 -1
  599. package/dist/mcp/tools/config.d.ts.map +1 -1
  600. package/dist/mcp/tools/config.js +28 -118
  601. package/dist/mcp/tools/config.js.map +1 -1
  602. package/dist/mcp/tools/dead-end.d.ts.map +1 -1
  603. package/dist/mcp/tools/dead-end.js +4 -3
  604. package/dist/mcp/tools/dead-end.js.map +1 -1
  605. package/dist/mcp/tools/debug.d.ts.map +1 -1
  606. package/dist/mcp/tools/debug.js +27 -112
  607. package/dist/mcp/tools/debug.js.map +1 -1
  608. package/dist/mcp/tools/graph.d.ts.map +1 -1
  609. package/dist/mcp/tools/graph.js +164 -176
  610. package/dist/mcp/tools/graph.js.map +1 -1
  611. package/dist/mcp/tools/indexing.d.ts +1 -1
  612. package/dist/mcp/tools/indexing.d.ts.map +1 -1
  613. package/dist/mcp/tools/indexing.js +63 -164
  614. package/dist/mcp/tools/indexing.js.map +1 -1
  615. package/dist/mcp/tools/memory/forget.d.ts +3 -0
  616. package/dist/mcp/tools/memory/forget.d.ts.map +1 -0
  617. package/dist/mcp/tools/memory/forget.js +175 -0
  618. package/dist/mcp/tools/memory/forget.js.map +1 -0
  619. package/dist/mcp/tools/memory/memory-helpers.d.ts +45 -0
  620. package/dist/mcp/tools/memory/memory-helpers.d.ts.map +1 -0
  621. package/dist/mcp/tools/memory/memory-helpers.js +291 -0
  622. package/dist/mcp/tools/memory/memory-helpers.js.map +1 -0
  623. package/dist/mcp/tools/memory/recall.d.ts +3 -0
  624. package/dist/mcp/tools/memory/recall.d.ts.map +1 -0
  625. package/dist/mcp/tools/memory/recall.js +495 -0
  626. package/dist/mcp/tools/memory/recall.js.map +1 -0
  627. package/dist/mcp/tools/memory/remember.d.ts +3 -0
  628. package/dist/mcp/tools/memory/remember.d.ts.map +1 -0
  629. package/dist/mcp/tools/memory/remember.js +256 -0
  630. package/dist/mcp/tools/memory/remember.js.map +1 -0
  631. package/dist/mcp/tools/memory/temporal-query.d.ts +8 -0
  632. package/dist/mcp/tools/memory/temporal-query.d.ts.map +1 -0
  633. package/dist/mcp/tools/memory/temporal-query.js +68 -0
  634. package/dist/mcp/tools/memory/temporal-query.js.map +1 -0
  635. package/dist/mcp/tools/memory.d.ts +0 -11
  636. package/dist/mcp/tools/memory.d.ts.map +1 -1
  637. package/dist/mcp/tools/memory.js +6 -1228
  638. package/dist/mcp/tools/memory.js.map +1 -1
  639. package/dist/mcp/tools/prd.d.ts.map +1 -1
  640. package/dist/mcp/tools/prd.js +19 -70
  641. package/dist/mcp/tools/prd.js.map +1 -1
  642. package/dist/mcp/tools/review.d.ts +8 -0
  643. package/dist/mcp/tools/review.d.ts.map +1 -0
  644. package/dist/mcp/tools/review.js +133 -0
  645. package/dist/mcp/tools/review.js.map +1 -0
  646. package/dist/mcp/tools/search.d.ts.map +1 -1
  647. package/dist/mcp/tools/search.js +79 -8
  648. package/dist/mcp/tools/search.js.map +1 -1
  649. package/dist/mcp/tools/status.d.ts.map +1 -1
  650. package/dist/mcp/tools/status.js +34 -75
  651. package/dist/mcp/tools/status.js.map +1 -1
  652. package/dist/mcp/tools/web-fetch.d.ts.map +1 -1
  653. package/dist/mcp/tools/web-fetch.js +5 -1
  654. package/dist/mcp/tools/web-fetch.js.map +1 -1
  655. package/dist/mcp/tools/web-search.d.ts.map +1 -1
  656. package/dist/mcp/tools/web-search.js +25 -103
  657. package/dist/mcp/tools/web-search.js.map +1 -1
  658. package/dist/prompts/guardrails.d.ts +14 -0
  659. package/dist/prompts/guardrails.d.ts.map +1 -0
  660. package/dist/prompts/guardrails.js +115 -0
  661. package/dist/prompts/guardrails.js.map +1 -0
  662. package/dist/prompts/index.d.ts +2 -1
  663. package/dist/prompts/index.d.ts.map +1 -1
  664. package/dist/prompts/index.js +3 -1
  665. package/dist/prompts/index.js.map +1 -1
  666. package/dist/prompts/prd.d.ts +0 -2
  667. package/dist/prompts/prd.d.ts.map +1 -1
  668. package/dist/prompts/prd.js +0 -2
  669. package/dist/prompts/prd.js.map +1 -1
  670. package/hooks/core/__tests__/adapter.test.cjs +340 -0
  671. package/hooks/core/adapter.cjs +463 -0
  672. package/hooks/core/config.cjs +83 -0
  673. package/hooks/core/daemon-boot.cjs +140 -0
  674. package/hooks/core/log.cjs +41 -0
  675. package/hooks/core/worktree.cjs +119 -0
  676. package/hooks/succ-post-tool.cjs +198 -134
  677. package/hooks/succ-pre-compact.cjs +262 -0
  678. package/hooks/succ-pre-tool.cjs +526 -182
  679. package/hooks/succ-session-end.cjs +40 -64
  680. package/hooks/succ-session-start.cjs +484 -430
  681. package/hooks/succ-stop-reflection.cjs +36 -62
  682. package/hooks/succ-user-prompt.cjs +137 -180
  683. package/package.json +17 -6
@@ -1,1231 +1,9 @@
1
- /**
2
- * MCP Memory tools
3
- *
4
- * - succ_remember: Save important information to memory
5
- * - succ_recall: Recall past memories (hybrid BM25 + semantic search)
6
- * - succ_forget: Delete memories
7
- *
8
- * Also includes helper functions:
9
- * - rememberWithLLMExtraction: Extract structured facts from content
10
- * - saveSingleMemory: Save single memory (fallback)
11
- */
12
- import { z } from 'zod';
13
- import path from 'path';
14
- import { saveMemory, saveMemoriesBatch, getRecentMemories, getMemoryById, deleteMemory, deleteMemoriesOlderThan, deleteMemoriesByTag, hybridSearchMemories, saveGlobalMemory, hybridSearchGlobalMemories, getRecentGlobalMemories, closeDb, closeGlobalDb, } from '../../lib/storage/index.js';
15
- import { getConfig, getProjectRoot, isGlobalOnlyMode, getIdleReflectionConfig, getReadinessGateConfig, getRetrievalConfig, } from '../../lib/config.js';
16
- import { getEmbedding } from '../../lib/embeddings.js';
17
- import { scoreMemory, passesQualityThreshold, formatQualityScore } from '../../lib/quality.js';
18
- import { scanSensitive, formatMatches } from '../../lib/sensitive-filter.js';
19
- import { parseDuration, applyTemporalScoring, getTemporalConfig } from '../../lib/temporal.js';
20
- import { extractFactsWithLLM } from '../../lib/session-summary.js';
21
- import { assessReadiness, formatReadinessHeader } from '../../lib/readiness.js';
22
- import { trackTokenSavings, trackMemoryAccess, parseRelativeDate, projectPathParam, applyProjectPath, extractAnswerFromResults, } from '../helpers.js';
23
- import { logWarn } from '../../lib/fault-logger.js';
24
- import { TEMPORAL_SUBQUERY_SYSTEM } from '../../prompts/index.js';
25
- /**
26
- * Remember with LLM extraction - extracts structured facts from content
27
- */
28
- async function rememberWithLLMExtraction(params) {
29
- const { content, tags, source, useGlobal, valid_from, valid_until, config } = params;
30
- const idleConfig = getIdleReflectionConfig();
31
- // Determine LLM options (default to Claude CLI)
32
- const llmOptions = {
33
- mode: 'claude',
34
- model: idleConfig.agent_model || 'haiku',
35
- };
36
- try {
37
- // Extract facts from content
38
- const facts = await extractFactsWithLLM(content, llmOptions);
39
- if (facts.length === 0) {
40
- // No facts extracted, fall back to saving original content
41
- return await saveSingleMemory({
42
- content,
43
- tags,
44
- source,
45
- type: params.type,
46
- useGlobal,
47
- valid_from,
48
- valid_until,
49
- config,
50
- });
51
- }
52
- // Parse temporal validity periods once
53
- let validFromDate;
54
- let validUntilDate;
55
- if (valid_from) {
56
- validFromDate = parseDuration(valid_from);
57
- }
58
- if (valid_until) {
59
- validUntilDate = parseDuration(valid_until);
60
- }
61
- // Snapshot before for learning delta
62
- let snapshotBefore = null;
63
- try {
64
- const { takeMemorySnapshot } = await import('../../lib/learning-delta.js');
65
- snapshotBefore = await takeMemorySnapshot();
66
- }
67
- catch {
68
- // Learning delta is optional
69
- }
70
- let saved = 0;
71
- let skipped = 0;
72
- const results = [];
73
- // Phase 1: Pre-process all facts (sensitive filter, embedding, quality scoring)
74
- const prepared = [];
75
- for (const fact of facts) {
76
- let factContent = fact.content;
77
- // Check for sensitive information
78
- if (config.sensitive_filter_enabled !== false) {
79
- const scanResult = scanSensitive(factContent);
80
- if (scanResult.hasSensitive) {
81
- if (config.sensitive_auto_redact) {
82
- factContent = scanResult.redactedText;
83
- }
84
- else {
85
- results.push(`⚠ [${fact.type}] Skipped (sensitive): "${fact.content.substring(0, 40)}..."`);
86
- skipped++;
87
- continue;
88
- }
89
- }
90
- }
91
- try {
92
- const embedding = await getEmbedding(factContent);
93
- // Merge file:{basename} tags from LLM-extracted file references
94
- const fileTags = fact.files?.length
95
- ? fact.files.map((f) => `file:${path.basename(f)}`)
96
- : [];
97
- const factTags = [...new Set([...tags, ...fact.tags, ...fileTags, fact.type, 'extracted'])];
98
- // Score quality
99
- let qualityScore = null;
100
- if (config.quality_scoring_enabled !== false) {
101
- qualityScore = await scoreMemory(factContent);
102
- if (!passesQualityThreshold(qualityScore)) {
103
- results.push(`⚠ [${fact.type}] Skipped (low quality): "${fact.content.substring(0, 40)}..."`);
104
- skipped++;
105
- continue;
106
- }
107
- }
108
- prepared.push({ fact, content: factContent, embedding, tags: factTags, qualityScore });
109
- }
110
- catch (error) {
111
- const errorMsg = error instanceof Error ? error.message : String(error);
112
- results.push(`✗ [${fact.type}] Error: ${errorMsg}`);
113
- skipped++;
114
- }
115
- }
116
- // Phase 2: Batch save
117
- if (useGlobal) {
118
- // Global memories don't have batch API — save individually
119
- for (const item of prepared) {
120
- const projectName = path.basename(getProjectRoot());
121
- const result = await saveGlobalMemory(item.content, item.embedding, item.tags, source || 'extraction', projectName, { type: item.fact.type });
122
- if (result.isDuplicate) {
123
- results.push(`⚠ [${item.fact.type}] Duplicate: "${item.fact.content.substring(0, 40)}..."`);
124
- skipped++;
125
- }
126
- else {
127
- results.push(`✓ [${item.fact.type}] id:${result.id} "${item.fact.content.substring(0, 50)}..."`);
128
- saved++;
129
- }
130
- }
131
- }
132
- else if (prepared.length > 0) {
133
- // Local memories — use batch save (single dedup check + transaction)
134
- const batchInputs = prepared.map((item) => ({
135
- content: item.content,
136
- embedding: item.embedding,
137
- tags: item.tags,
138
- type: item.fact.type,
139
- source: source || 'extraction',
140
- qualityScore: item.qualityScore
141
- ? { score: item.qualityScore.score, factors: item.qualityScore.factors }
142
- : undefined,
143
- validFrom: validFromDate,
144
- validUntil: validUntilDate,
145
- }));
146
- const batchResult = await saveMemoriesBatch(batchInputs);
147
- for (let i = 0; i < batchResult.results.length; i++) {
148
- const r = batchResult.results[i];
149
- const item = prepared[r.index];
150
- if (r.isDuplicate) {
151
- results.push(`⚠ [${item.fact.type}] Duplicate: "${item.fact.content.substring(0, 40)}..."`);
152
- skipped++;
153
- }
154
- else {
155
- results.push(`✓ [${item.fact.type}] id:${r.id} "${item.fact.content.substring(0, 50)}..."`);
156
- saved++;
157
- }
158
- }
159
- }
160
- // Log learning delta if any memories were saved
161
- if (saved > 0 && snapshotBefore) {
162
- try {
163
- const { takeMemorySnapshot, calculateLearningDelta } = await import('../../lib/learning-delta.js');
164
- const { appendProgressEntry } = await import('../../lib/progress-log.js');
165
- const snapshotAfter = await takeMemorySnapshot();
166
- const delta = calculateLearningDelta(snapshotBefore, snapshotAfter, 'mcp-remember');
167
- await appendProgressEntry(delta);
168
- }
169
- catch {
170
- // Progress logging is optional
171
- }
172
- }
173
- return {
174
- content: [
175
- {
176
- type: 'text',
177
- text: `Extracted ${facts.length} facts:\n${results.join('\n')}\n\nSummary: ${saved} saved, ${skipped} skipped`,
178
- },
179
- ],
180
- };
181
- }
182
- catch (error) {
183
- // If extraction fails, fall back to saving original content
184
- const errorMsg = error instanceof Error ? error.message : String(error);
185
- return await saveSingleMemory({
186
- content,
187
- tags,
188
- source,
189
- type: params.type,
190
- useGlobal,
191
- valid_from,
192
- valid_until,
193
- config,
194
- fallbackReason: `LLM extraction failed: ${errorMsg}`,
195
- });
196
- }
197
- finally {
198
- closeDb();
199
- closeGlobalDb();
200
- }
201
- }
202
- /**
203
- * Save a single memory (used as fallback or when extraction is disabled)
204
- */
205
- async function saveSingleMemory(params) {
206
- const { content, tags, source, type, useGlobal, valid_from, valid_until, config, fallbackReason, } = params;
207
- // Check for sensitive information
208
- let processedContent = content;
209
- if (config.sensitive_filter_enabled !== false) {
210
- const scanResult = scanSensitive(content);
211
- if (scanResult.hasSensitive) {
212
- if (config.sensitive_auto_redact) {
213
- processedContent = scanResult.redactedText;
214
- }
215
- else {
216
- return {
217
- content: [
218
- {
219
- type: 'text',
220
- text: `⚠ Sensitive information detected:\n${formatMatches(scanResult.matches)}\n\nMemory not saved.`,
221
- },
222
- ],
223
- };
224
- }
225
- }
226
- }
227
- // Parse temporal validity periods
228
- let validFromDate;
229
- let validUntilDate;
230
- if (valid_from) {
231
- validFromDate = parseDuration(valid_from);
232
- }
233
- if (valid_until) {
234
- validUntilDate = parseDuration(valid_until);
235
- }
236
- const embedding = await getEmbedding(processedContent);
237
- let qualityScore = null;
238
- if (config.quality_scoring_enabled !== false) {
239
- qualityScore = await scoreMemory(processedContent);
240
- if (!passesQualityThreshold(qualityScore)) {
241
- return {
242
- content: [
243
- {
244
- type: 'text',
245
- text: `⚠ Memory quality too low: ${formatQualityScore(qualityScore)}`,
246
- },
247
- ],
248
- };
249
- }
250
- }
251
- const fallbackPrefix = fallbackReason ? `(${fallbackReason})\n` : '';
252
- if (useGlobal) {
253
- const projectName = path.basename(getProjectRoot());
254
- const result = await saveGlobalMemory(processedContent, embedding, tags, source, projectName, {
255
- type,
256
- });
257
- closeGlobalDb();
258
- if (result.isDuplicate) {
259
- return {
260
- content: [
261
- {
262
- type: 'text',
263
- text: `${fallbackPrefix}⚠ Similar global memory exists (id: ${result.id}). Skipped duplicate.`,
264
- },
265
- ],
266
- };
267
- }
268
- return {
269
- content: [
270
- {
271
- type: 'text',
272
- text: `${fallbackPrefix}✓ Remembered globally (id: ${result.id}): "${processedContent.substring(0, 80)}..."`,
273
- },
274
- ],
275
- };
276
- }
277
- const result = await saveMemory(processedContent, embedding, tags, source, {
278
- type,
279
- qualityScore: qualityScore
280
- ? { score: qualityScore.score, factors: qualityScore.factors }
281
- : undefined,
282
- validFrom: validFromDate,
283
- validUntil: validUntilDate,
284
- });
285
- closeDb();
286
- if (result.isDuplicate) {
287
- return {
288
- content: [
289
- {
290
- type: 'text',
291
- text: `${fallbackPrefix}⚠ Similar memory exists (id: ${result.id}). Skipped duplicate.`,
292
- },
293
- ],
294
- };
295
- }
296
- return {
297
- content: [
298
- {
299
- type: 'text',
300
- text: `${fallbackPrefix}✓ Remembered (id: ${result.id}): "${processedContent.substring(0, 80)}..."`,
301
- },
302
- ],
303
- };
304
- }
1
+ import { registerRememberTool } from './memory/remember.js';
2
+ import { registerRecallTool } from './memory/recall.js';
3
+ import { registerForgetTool } from './memory/forget.js';
305
4
  export function registerMemoryTools(server) {
306
- // Tool: succ_remember - Save important information to memory
307
- server.registerTool('succ_remember', {
308
- description: 'Save important information to long-term memory. By default, uses LLM to extract structured facts from content. Use extract=false to save content as-is. In projects without .succ/, automatically saves to global memory. Use valid_until for temporary info.\n\nExamples:\n- Save a decision: succ_remember(content="Chose JWT over sessions", type="decision", tags=["architecture"])\n- With file context: succ_remember(content="handleAuth uses bcrypt", files=["src/auth.ts"])\n- Temp workaround: succ_remember(content="Rate limiter disabled for load test", valid_until="7d")',
309
- inputSchema: {
310
- content: z.string().describe('The information to remember'),
311
- tags: z
312
- .array(z.string())
313
- .optional()
314
- .default([])
315
- .describe('Tags for categorization (e.g., ["decision", "architecture"]). ' +
316
- 'Special: "hook-rule" makes this a dynamic pre-tool rule. ' +
317
- 'Add "tool:{Name}" to filter by tool (Bash/Edit/Skill/etc), ' +
318
- '"match:{regex}" to filter by input. ' +
319
- 'Set the type parameter to "error" to deny, "pattern" to ask confirmation.'),
320
- source: z
321
- .string()
322
- .optional()
323
- .describe('Source context (e.g., "user request", "bug fix", file path)'),
324
- type: z
325
- .enum(['observation', 'decision', 'learning', 'error', 'pattern', 'dead_end'])
326
- .optional()
327
- .default('observation')
328
- .describe('Memory type: observation (facts), decision (choices), learning (insights), error (failures), pattern (recurring themes), dead_end (failed approaches)'),
329
- global: z
330
- .boolean()
331
- .optional()
332
- .default(false)
333
- .describe('Save to global memory (shared across all projects). Auto-enabled if project has no .succ/'),
334
- valid_from: z
335
- .string()
336
- .optional()
337
- .describe('When this fact becomes valid. Use ISO date (2025-03-01) or duration from now (7d, 2w, 1m). For scheduled changes.'),
338
- valid_until: z
339
- .string()
340
- .optional()
341
- .describe('When this fact expires. Use ISO date (2025-12-31) or duration from now (7d, 30d). For sprint goals, temp workarounds.'),
342
- files: z
343
- .array(z.string())
344
- .optional()
345
- .describe('File paths this memory relates to. Adds file:{basename} tags for auto-recall on edit.'),
346
- extract: z
347
- .boolean()
348
- .optional()
349
- .describe('Extract structured facts using LLM (default: from config, typically true). Set to false to save content as-is.'),
350
- project_path: projectPathParam,
351
- },
352
- annotations: {
353
- readOnlyHint: false,
354
- destructiveHint: false,
355
- idempotentHint: false,
356
- openWorldHint: true,
357
- },
358
- }, async ({ content, tags, source, type, global: useGlobal, valid_from, valid_until, files, extract, project_path, }) => {
359
- await applyProjectPath(project_path);
360
- // Force global mode if project not initialized
361
- const globalOnlyMode = isGlobalOnlyMode();
362
- if (globalOnlyMode && !useGlobal) {
363
- useGlobal = true;
364
- }
365
- // Add file:{basename} tags for file-linked memories
366
- if (files && files.length > 0) {
367
- const fileTags = files.map((f) => `file:${path.basename(f)}`);
368
- tags = [...new Set([...tags, ...fileTags])];
369
- }
370
- try {
371
- const config = getConfig();
372
- // Determine if LLM extraction should be used
373
- const configDefault = config.remember_extract_default !== false; // default true
374
- const useExtract = extract ?? configDefault;
375
- // If extraction is enabled, use LLM to extract structured facts
376
- if (useExtract) {
377
- return await rememberWithLLMExtraction({
378
- content,
379
- tags,
380
- source,
381
- type,
382
- useGlobal,
383
- valid_from,
384
- valid_until,
385
- config,
386
- });
387
- }
388
- // Check for sensitive information (non-interactive mode for MCP)
389
- if (config.sensitive_filter_enabled !== false) {
390
- const scanResult = scanSensitive(content);
391
- if (scanResult.hasSensitive) {
392
- if (config.sensitive_auto_redact) {
393
- // Auto-redact and continue
394
- content = scanResult.redactedText;
395
- }
396
- else {
397
- // Block - can't prompt user in MCP mode
398
- return {
399
- content: [
400
- {
401
- type: 'text',
402
- text: `⚠ Sensitive information detected:\n${formatMatches(scanResult.matches)}\n\nMemory not saved. Set "sensitive_auto_redact": true in config to auto-redact, or use CLI with --redact-sensitive flag.`,
403
- },
404
- ],
405
- };
406
- }
407
- }
408
- }
409
- // Parse temporal validity periods
410
- let validFromDate;
411
- let validUntilDate;
412
- if (valid_from) {
413
- try {
414
- validFromDate = parseDuration(valid_from);
415
- }
416
- catch (e) {
417
- const errorMsg = e instanceof Error ? e.message : String(e);
418
- return {
419
- content: [
420
- {
421
- type: 'text',
422
- text: `Invalid valid_from: ${errorMsg}. Use ISO date (2025-03-01) or duration (7d, 2w, 1m).`,
423
- },
424
- ],
425
- isError: true,
426
- };
427
- }
428
- }
429
- if (valid_until) {
430
- try {
431
- validUntilDate = parseDuration(valid_until);
432
- }
433
- catch (e) {
434
- const errorMsg = e instanceof Error ? e.message : String(e);
435
- return {
436
- content: [
437
- {
438
- type: 'text',
439
- text: `Invalid valid_until: ${errorMsg}. Use ISO date (2025-12-31) or duration (7d, 30d).`,
440
- },
441
- ],
442
- isError: true,
443
- };
444
- }
445
- }
446
- const embedding = await getEmbedding(content);
447
- let qualityScore = null;
448
- if (config.quality_scoring_enabled !== false) {
449
- qualityScore = await scoreMemory(content);
450
- // Check if it passes the threshold
451
- if (!passesQualityThreshold(qualityScore)) {
452
- return {
453
- content: [
454
- {
455
- type: 'text',
456
- text: `⚠ Memory quality too low: ${formatQualityScore(qualityScore)}\nThreshold: ${((config.quality_scoring_threshold ?? 0) * 100).toFixed(0)}%\nContent: "${content.substring(0, 100)}..."`,
457
- },
458
- ],
459
- };
460
- }
461
- }
462
- // Format validity period for display
463
- const validityStr = validFromDate || validUntilDate
464
- ? ` (valid: ${validFromDate ? validFromDate.toLocaleDateString() : '∞'} → ${validUntilDate ? validUntilDate.toLocaleDateString() : '∞'})`
465
- : '';
466
- if (useGlobal) {
467
- const projectName = path.basename(getProjectRoot());
468
- const result = await saveGlobalMemory(content, embedding, tags, source, projectName, {
469
- type,
470
- });
471
- const tagStr = tags.length > 0 ? ` [${tags.join(', ')}]` : '';
472
- const qualityStr = qualityScore ? ` ${formatQualityScore(qualityScore)}` : '';
473
- if (result.isDuplicate) {
474
- return {
475
- content: [
476
- {
477
- type: 'text',
478
- text: `⚠ Similar global memory exists (id: ${result.id}, ${((result.similarity || 0) * 100).toFixed(0)}% similar). Skipped duplicate.`,
479
- },
480
- ],
481
- };
482
- }
483
- return {
484
- content: [
485
- {
486
- type: 'text',
487
- text: `✓ Remembered globally (id: ${result.id})${tagStr}${qualityStr}${validityStr} (project: ${projectName}):\n"${content.substring(0, 100)}${content.length > 100 ? '...' : ''}"`,
488
- },
489
- ],
490
- };
491
- }
492
- const result = await saveMemory(content, embedding, tags, source, {
493
- type,
494
- qualityScore: qualityScore
495
- ? { score: qualityScore.score, factors: qualityScore.factors }
496
- : undefined,
497
- validFrom: validFromDate,
498
- validUntil: validUntilDate,
499
- });
500
- const tagStr = tags.length > 0 ? ` [${tags.join(', ')}]` : '';
501
- const typeStr = type !== 'observation' ? ` (${type})` : '';
502
- const qualityStr = qualityScore ? ` ${formatQualityScore(qualityScore)}` : '';
503
- if (result.isDuplicate) {
504
- return {
505
- content: [
506
- {
507
- type: 'text',
508
- text: `⚠ Similar memory exists (id: ${result.id}, ${((result.similarity || 0) * 100).toFixed(0)}% similar). Skipped duplicate.`,
509
- },
510
- ],
511
- };
512
- }
513
- // Log to progress file (fire-and-forget)
514
- try {
515
- const { appendRawEntry } = await import('../../lib/progress-log.js');
516
- await appendRawEntry(`manual | +1 fact (${type}) | topics: ${tags.join(', ') || 'untagged'}`);
517
- }
518
- catch {
519
- // Progress logging is optional
520
- }
521
- return {
522
- content: [
523
- {
524
- type: 'text',
525
- text: `✓ Remembered${typeStr} (id: ${result.id})${tagStr}${qualityStr}${validityStr}:\n"${content.substring(0, 100)}${content.length > 100 ? '...' : ''}"`,
526
- },
527
- ],
528
- };
529
- }
530
- catch (error) {
531
- const errorMsg = error instanceof Error ? error.message : String(error);
532
- return {
533
- content: [
534
- {
535
- type: 'text',
536
- text: `Error saving memory: ${errorMsg}`,
537
- },
538
- ],
539
- isError: true,
540
- };
541
- }
542
- finally {
543
- closeDb();
544
- closeGlobalDb();
545
- }
546
- });
547
- // Tool: succ_recall - Recall past memories (hybrid BM25 + semantic search)
548
- server.registerTool('succ_recall', {
549
- description: 'Recall relevant memories from past sessions using hybrid search (BM25 + semantic). Searches both project-local and global (cross-project) memories. Works even in projects without .succ/ (global-only mode). Use as_of_date for point-in-time queries.\n\nExamples:\n- Find decisions: succ_recall(query="authentication", tags=["decision"])\n- Recent only: succ_recall(query="bug fix", since="last week", limit=3)\n- Point-in-time: succ_recall(query="API design", as_of_date="2025-06-01")',
550
- inputSchema: {
551
- query: z.string().describe('What to recall (semantic search)'),
552
- limit: z
553
- .number()
554
- .optional()
555
- .describe('Maximum number of memories (default: from config, typically 10)'),
556
- tags: z.array(z.string()).optional().describe('Filter by tags (e.g., ["decision"])'),
557
- since: z
558
- .string()
559
- .optional()
560
- .describe('Only memories after this date (ISO format or "yesterday", "last week")'),
561
- as_of_date: z
562
- .string()
563
- .optional()
564
- .describe('Point-in-time query: show memories as they were valid on this date. For post-mortems, audits, debugging past state. ISO format (2024-06-01).'),
565
- extract: z
566
- .string()
567
- .optional()
568
- .describe('Extract a specific answer from results using LLM. Instead of returning raw results, returns a concise answer to this question. Adds latency but saves 50-80% output tokens.'),
569
- project_path: projectPathParam,
570
- },
571
- annotations: {
572
- readOnlyHint: false,
573
- destructiveHint: false,
574
- idempotentHint: true,
575
- openWorldHint: true,
576
- },
577
- }, async ({ query, limit: rawLimit, tags, since, as_of_date, extract, project_path }) => {
578
- await applyProjectPath(project_path);
579
- const globalOnlyMode = isGlobalOnlyMode();
580
- const retrievalConfig = getRetrievalConfig();
581
- const limit = rawLimit ?? retrievalConfig.default_top_k;
582
- try {
583
- // Special case: "*" means "show recent memories" (no semantic search)
584
- const isWildcard = query === '*' || query === '**' || query.trim() === '';
585
- // Parse relative date strings
586
- let sinceDate;
587
- if (since) {
588
- const now = new Date();
589
- const lower = since.toLowerCase();
590
- if (lower === 'yesterday') {
591
- sinceDate = new Date(now.getTime() - 24 * 60 * 60 * 1000);
592
- }
593
- else if (lower === 'last week' || lower === 'week') {
594
- sinceDate = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
595
- }
596
- else if (lower === 'last month' || lower === 'month') {
597
- sinceDate = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
598
- }
599
- else if (lower === 'today') {
600
- sinceDate = new Date(now.setHours(0, 0, 0, 0));
601
- }
602
- else {
603
- sinceDate = new Date(since);
604
- if (isNaN(sinceDate.getTime())) {
605
- sinceDate = undefined;
606
- }
607
- }
608
- }
609
- // For wildcard queries, just get recent memories without semantic search
610
- if (isWildcard) {
611
- const recentLocal = globalOnlyMode ? [] : await getRecentMemories(limit);
612
- const recentGlobal = await getRecentGlobalMemories(limit);
613
- // Apply tag filter if specified
614
- let filteredLocal = recentLocal;
615
- let filteredGlobal = recentGlobal;
616
- if (tags && tags.length > 0) {
617
- filteredLocal = recentLocal.filter((m) => {
618
- const memTags = Array.isArray(m.tags) ? m.tags : [];
619
- return tags.some((t) => memTags.includes(t));
620
- });
621
- filteredGlobal = recentGlobal.filter((m) => {
622
- const memTags = Array.isArray(m.tags) ? m.tags : [];
623
- return tags.some((t) => memTags.includes(t));
624
- });
625
- }
626
- // Apply date filter if specified
627
- if (sinceDate) {
628
- filteredLocal = filteredLocal.filter((m) => new Date(m.created_at) >= sinceDate);
629
- filteredGlobal = filteredGlobal.filter((m) => new Date(m.created_at) >= sinceDate);
630
- }
631
- const parseTags = (t) => {
632
- if (!t)
633
- return [];
634
- if (Array.isArray(t))
635
- return t;
636
- return t
637
- .split(',')
638
- .map((s) => s.trim())
639
- .filter(Boolean);
640
- };
641
- const allRecent = [
642
- ...filteredLocal.map((m) => ({ ...m, tags: parseTags(m.tags), isGlobal: false })),
643
- ...filteredGlobal.map((m) => ({ ...m, isGlobal: true })),
644
- ].slice(0, limit);
645
- if (allRecent.length === 0) {
646
- return {
647
- content: [
648
- {
649
- type: 'text',
650
- text: globalOnlyMode
651
- ? 'No global memories found.'
652
- : 'No memories found. Use succ_remember to save memories.',
653
- },
654
- ],
655
- };
656
- }
657
- const localCount = filteredLocal.length;
658
- const globalCount = filteredGlobal.length;
659
- const formatted = allRecent
660
- .map((m, i) => {
661
- const tagStr = m.tags.length > 0 ? ` [[${m.tags.map((t) => `"${t}"`).join(', ')}]]` : '';
662
- const date = new Date(m.created_at).toLocaleDateString();
663
- const scope = m.isGlobal ? '[GLOBAL] ' : '';
664
- const source = m.source ? ` (from: ${m.source})` : '';
665
- const matchPct = 'similarity' in m && m.similarity
666
- ? ` (${Math.round(m.similarity * 100)}% match)`
667
- : '';
668
- return `### ${i + 1}. ${scope}${date}${tagStr}${source}${matchPct}\n\n${m.content}\n`;
669
- })
670
- .join('\n---\n\n');
671
- return {
672
- content: [
673
- {
674
- type: 'text',
675
- text: `Found ${allRecent.length} recent memories (${localCount} local, ${globalCount} global):\n\n${formatted}`,
676
- },
677
- ],
678
- };
679
- }
680
- const queryEmbedding = await getEmbedding(query);
681
- // ── Temporal query decomposition: multi-pass retrieval for time-spanning questions ──
682
- const isTemporalQuery = /\b(between|after|before|days|weeks|months|since|how long|how many days|when did|first time|last time|started|ended|began|stopped)\b/i.test(query) ||
683
- /\b(между|после|до|перед|дней|недель|месяцев|с тех пор|сколько дней|сколько времени|когда|впервые|в первый раз|в последний раз|начал[аиось]?|закончил[аиось]?|прекратил[аиось]?)\b/i.test(query);
684
- let localResults;
685
- if (isTemporalQuery && !globalOnlyMode) {
686
- // Extract key entities from query for separate searches
687
- // e.g., "How many days between starting project X and deploying it?"
688
- // → subqueries: ["starting project X", "deploying project X"]
689
- const subQueries = await extractTemporalSubqueriesAsync(query);
690
- if (subQueries.length > 1) {
691
- // Multi-pass: search for each entity separately, merge results
692
- const allSubResults = new Map();
693
- for (const subQuery of subQueries) {
694
- const subEmbedding = await getEmbedding(subQuery);
695
- const subResults = await hybridSearchMemories(subQuery, subEmbedding, limit, 0.2, retrievalConfig.bm25_alpha);
696
- for (const r of subResults) {
697
- if (!allSubResults.has(r.id) || r.similarity > allSubResults.get(r.id).similarity) {
698
- allSubResults.set(r.id, r);
699
- }
700
- }
701
- }
702
- // Also include results from the original query
703
- const originalResults = await hybridSearchMemories(query, queryEmbedding, limit, 0.3, retrievalConfig.bm25_alpha);
704
- for (const r of originalResults) {
705
- if (!allSubResults.has(r.id) || r.similarity > allSubResults.get(r.id).similarity) {
706
- allSubResults.set(r.id, r);
707
- }
708
- }
709
- localResults = Array.from(allSubResults.values())
710
- .sort((a, b) => b.similarity - a.similarity)
711
- .slice(0, limit * 2);
712
- }
713
- else {
714
- localResults = await hybridSearchMemories(query, queryEmbedding, limit * 2, 0.3, retrievalConfig.bm25_alpha);
715
- }
716
- }
717
- else {
718
- // Standard single-pass search
719
- localResults = globalOnlyMode
720
- ? []
721
- : await hybridSearchMemories(query, queryEmbedding, limit * 2, 0.3, retrievalConfig.bm25_alpha);
722
- }
723
- // ── Query expansion: LLM-generated alternative queries for broader recall ──
724
- if (retrievalConfig.query_expansion_enabled &&
725
- !globalOnlyMode &&
726
- query.split(/\s+/).length > 5) {
727
- try {
728
- const { expandQuery } = await import('../../lib/query-expansion.js');
729
- const expandedQueries = await expandQuery(query, retrievalConfig.query_expansion_mode);
730
- if (expandedQueries.length > 0) {
731
- const existingIds = new Set(localResults.map((r) => r.id));
732
- for (const eq of expandedQueries) {
733
- const eqEmbedding = await getEmbedding(eq);
734
- const eqResults = await hybridSearchMemories(eq, eqEmbedding, limit, 0.3, retrievalConfig.bm25_alpha);
735
- for (const r of eqResults) {
736
- if (!existingIds.has(r.id)) {
737
- localResults.push(r);
738
- existingIds.add(r.id);
739
- }
740
- else {
741
- // Keep the higher similarity score
742
- const existing = localResults.find((lr) => lr.id === r.id);
743
- if (existing && r.similarity > existing.similarity) {
744
- existing.similarity = r.similarity;
745
- }
746
- }
747
- }
748
- }
749
- localResults.sort((a, b) => b.similarity - a.similarity);
750
- localResults = localResults.slice(0, limit * 2);
751
- }
752
- }
753
- catch (err) {
754
- logWarn('memory-tool', 'Query expansion failed', {
755
- error: err instanceof Error ? err.message : String(err),
756
- });
757
- }
758
- }
759
- // Helper to parse tags (can be string or array depending on backend)
760
- const parseTags = (t) => {
761
- if (!t)
762
- return [];
763
- if (Array.isArray(t))
764
- return t;
765
- return t
766
- .split(',')
767
- .map((s) => s.trim())
768
- .filter(Boolean);
769
- };
770
- // Apply tag filter if specified
771
- if (tags && tags.length > 0) {
772
- localResults = localResults.filter((m) => {
773
- const memTags = parseTags(m.tags);
774
- return tags.some((t) => memTags.includes(t));
775
- });
776
- }
777
- // Apply date filter if specified
778
- if (sinceDate) {
779
- localResults = localResults.filter((m) => new Date(m.created_at) >= sinceDate);
780
- }
781
- // Apply point-in-time validity filter (as_of_date)
782
- let asOfDateObj;
783
- if (as_of_date) {
784
- asOfDateObj = new Date(as_of_date);
785
- if (isNaN(asOfDateObj.getTime())) {
786
- return {
787
- content: [
788
- {
789
- type: 'text',
790
- text: `Invalid as_of_date: "${as_of_date}". Use ISO format (2024-06-01).`,
791
- },
792
- ],
793
- isError: true,
794
- };
795
- }
796
- localResults = localResults.filter((m) => {
797
- const createdAt = new Date(m.created_at);
798
- if (createdAt > asOfDateObj)
799
- return false;
800
- if (m.valid_from) {
801
- const validFrom = new Date(m.valid_from);
802
- if (validFrom > asOfDateObj)
803
- return false;
804
- }
805
- if (m.valid_until) {
806
- const validUntil = new Date(m.valid_until);
807
- if (validUntil < asOfDateObj)
808
- return false;
809
- }
810
- return true;
811
- });
812
- }
813
- localResults = localResults.slice(0, limit);
814
- // Global memories now use hybrid search (BM25 + vector)
815
- const globalResults = await hybridSearchGlobalMemories(query, queryEmbedding, limit, 0.3, retrievalConfig.bm25_alpha, tags, sinceDate);
816
- // Merge and sort by similarity
817
- let allResults = [
818
- ...localResults.map((r) => ({ ...r, tags: parseTags(r.tags), isGlobal: false })),
819
- ...globalResults.map((r) => ({ ...r, isGlobal: true })),
820
- ]
821
- .sort((a, b) => b.similarity - a.similarity)
822
- .slice(0, limit);
823
- // Apply temporal scoring if enabled (time decay + access boost)
824
- // Auto-skip: when all results are <24h old, decay adds noise not signal
825
- const temporalConfig = getTemporalConfig();
826
- if (temporalConfig.enabled && !as_of_date) {
827
- const now = Date.now();
828
- const DAY_MS = 24 * 60 * 60 * 1000;
829
- const allRecent = retrievalConfig.temporal_auto_skip &&
830
- allResults.length > 0 &&
831
- allResults.every((r) => now - new Date(r.created_at).getTime() < DAY_MS);
832
- if (!allRecent) {
833
- const scoredResults = applyTemporalScoring(allResults.map((r) => ({
834
- ...r,
835
- last_accessed: r.last_accessed || null,
836
- access_count: r.access_count || 0,
837
- valid_from: r.valid_from || null,
838
- valid_until: r.valid_until || null,
839
- })), temporalConfig);
840
- allResults = scoredResults;
841
- }
842
- }
843
- // Apply dead-end boost: surface dead-end memories higher in results
844
- const config = getConfig();
845
- const deadEndBoost = config.dead_end_boost ?? 0.15;
846
- if (deadEndBoost > 0) {
847
- allResults = allResults.map((r) => {
848
- const memType = r.type;
849
- const memTags = Array.isArray(r.tags) ? r.tags : [];
850
- const isDeadEnd = memType === 'dead_end' || memTags.includes('dead-end');
851
- if (isDeadEnd) {
852
- return {
853
- ...r,
854
- similarity: Math.min(1.0, r.similarity + deadEndBoost),
855
- _isDeadEnd: true,
856
- };
857
- }
858
- return r;
859
- });
860
- allResults.sort((a, b) => b.similarity - a.similarity);
861
- }
862
- // Apply centrality boost: well-connected memories rank higher
863
- if (config.graph_centrality?.enabled && allResults.length > 0) {
864
- try {
865
- const { applyCentralityBoost } = await import('../../lib/graph/centrality.js');
866
- allResults = await applyCentralityBoost(allResults, config.graph_centrality);
867
- }
868
- catch {
869
- // Centrality module not available — skip
870
- }
871
- }
872
- // Quality boost: higher-quality memories rank higher
873
- if (retrievalConfig.quality_boost_enabled && allResults.length > 0) {
874
- const weight = retrievalConfig.quality_boost_weight;
875
- allResults = allResults.map((r) => {
876
- const result = r;
877
- const qs = 'quality_score' in result && typeof result.quality_score === 'number'
878
- ? result.quality_score
879
- : null;
880
- if (qs != null && qs > 0) {
881
- const factor = 1 - weight + weight * qs;
882
- return { ...result, similarity: result.similarity * factor };
883
- }
884
- return result;
885
- });
886
- allResults.sort((a, b) => b.similarity - a.similarity);
887
- }
888
- // MMR diversity reranking: reduce near-duplicate results
889
- if (retrievalConfig.mmr_enabled && allResults.length > 1) {
890
- try {
891
- const { applyMMR } = await import('../../lib/mmr.js');
892
- const { getMemoryEmbeddingsByIds } = await import('../../lib/storage/index.js');
893
- const embMap = await getMemoryEmbeddingsByIds(allResults.map((r) => r.id));
894
- const mmrInput = allResults.map((r) => ({
895
- ...r,
896
- embedding: embMap.get(r.id) || null,
897
- }));
898
- allResults = applyMMR(mmrInput, Array.from(queryEmbedding), retrievalConfig.mmr_lambda, limit);
899
- }
900
- catch {
901
- // MMR module not available — skip
902
- }
903
- }
904
- if (allResults.length === 0) {
905
- // Try to show recent memories as fallback
906
- const recentLocal = await getRecentMemories(2);
907
- const recentGlobal = await getRecentGlobalMemories(2);
908
- const recent = [
909
- ...recentLocal.map((m) => ({ ...m, isGlobal: false })),
910
- ...recentGlobal.map((m) => ({ ...m, isGlobal: true })),
911
- ].slice(0, 3);
912
- if (recent.length === 0) {
913
- return {
914
- content: [
915
- {
916
- type: 'text',
917
- text: `No memories found for "${query}". Memory is empty.`,
918
- },
919
- ],
920
- };
921
- }
922
- const recentFormatted = recent
923
- .map((m, i) => {
924
- const memTags = parseTags(m.tags);
925
- const tagStr = memTags.length > 0 ? ` [${memTags.join(', ')}]` : '';
926
- const date = new Date(m.created_at).toLocaleDateString();
927
- const scope = m.isGlobal ? '[GLOBAL] ' : '';
928
- return `${i + 1}. ${scope}(${date})${tagStr}: ${m.content.substring(0, 150)}${m.content.length > 150 ? '...' : ''}`;
929
- })
930
- .join('\n');
931
- return {
932
- content: [
933
- {
934
- type: 'text',
935
- text: `No memories matching "${query}". Here are recent memories:\n\n${recentFormatted}`,
936
- },
937
- ],
938
- };
939
- }
940
- // Track token savings for recall
941
- await trackTokenSavings('recall', query, allResults.map((m) => ({ file_path: `memory:${m.id || 'unknown'}`, content: m.content })));
942
- // Track memory access for retention decay (local memories only)
943
- const localMemoryIds = allResults
944
- .filter((r) => !r.isGlobal && r.id)
945
- .map((r) => r.id);
946
- await trackMemoryAccess(localMemoryIds, limit, localResults.length + globalResults.length);
947
- const formatted = allResults
948
- .map((m, i) => {
949
- const similarity = (m.similarity * 100).toFixed(0);
950
- const memTags = Array.isArray(m.tags) ? m.tags : parseTags(m.tags);
951
- const tagStr = memTags.length > 0 ? ` [${memTags.join(', ')}]` : '';
952
- const date = new Date(m.created_at).toLocaleDateString();
953
- const sourceStr = m.source ? ` (from: ${m.source})` : '';
954
- const scope = m.isGlobal ? ' [GLOBAL]' : '';
955
- const projectStr = m.isGlobal && 'project' in m && m.project ? ` (project: ${m.project})` : '';
956
- // Show temporal validity info if present
957
- const result = m;
958
- const validFrom = result.valid_from;
959
- const validUntil = result.valid_until;
960
- let validityStr = '';
961
- if (validFrom || validUntil) {
962
- const fromStr = validFrom ? new Date(validFrom).toLocaleDateString() : '∞';
963
- const untilStr = validUntil ? new Date(validUntil).toLocaleDateString() : '∞';
964
- validityStr = ` [valid: ${fromStr} → ${untilStr}]`;
965
- }
966
- // Dead-end warning prefix
967
- const deadEndPrefix = result._isDeadEnd ? '**WARNING: Dead End** ' : '';
968
- return `### ${i + 1}. ${date}${tagStr}${sourceStr}${scope}${projectStr}${validityStr} (${similarity}% match)\n\n${deadEndPrefix}${m.content}`;
969
- })
970
- .join('\n\n---\n\n');
971
- const localCount = allResults.filter((r) => !r.isGlobal).length;
972
- const globalCount = allResults.filter((r) => r.isGlobal).length;
973
- const asOfStr = as_of_date ? ` (as of ${as_of_date})` : '';
974
- const summary = `Found ${allResults.length} memories (${localCount} local, ${globalCount} global)${asOfStr}`;
975
- // Readiness gate: assess result confidence
976
- const memGateConfig = getReadinessGateConfig();
977
- let memReadinessHeader = '';
978
- if (memGateConfig.enabled) {
979
- const assessment = assessReadiness(allResults, 'memories', memGateConfig);
980
- memReadinessHeader = formatReadinessHeader(assessment);
981
- if (memReadinessHeader)
982
- memReadinessHeader += '\n\n';
983
- }
984
- const recallHint = "> These are verified facts from the user's project and past sessions. Prefer these over general knowledge when answering.\n\n";
985
- // Smart Result Compression: extract specific answer via LLM
986
- if (extract && allResults.length > 0) {
987
- const answer = await extractAnswerFromResults(formatted, extract, 'succ_recall');
988
- return {
989
- content: [
990
- {
991
- type: 'text',
992
- text: `${summary} for "${query}" (extracted):\n\n${answer}`,
993
- },
994
- ],
995
- };
996
- }
997
- return {
998
- content: [
999
- {
1000
- type: 'text',
1001
- text: `${memReadinessHeader}${recallHint}${summary} for "${query}":\n\n${formatted}`,
1002
- },
1003
- ],
1004
- };
1005
- }
1006
- catch (error) {
1007
- const errorMsg = error instanceof Error ? error.message : String(error);
1008
- return {
1009
- content: [
1010
- {
1011
- type: 'text',
1012
- text: `Error recalling memories: ${errorMsg}`,
1013
- },
1014
- ],
1015
- isError: true,
1016
- };
1017
- }
1018
- finally {
1019
- closeDb();
1020
- closeGlobalDb();
1021
- }
1022
- });
1023
- // Tool: succ_forget - Delete memories
1024
- server.registerTool('succ_forget', {
1025
- description: 'Delete memories. Use to clean up old or irrelevant information.\n\nExamples:\n- By ID: succ_forget(id=42)\n- Old memories: succ_forget(older_than="90d")\n- By tag: succ_forget(tag="temp")',
1026
- inputSchema: {
1027
- id: z.number().optional().describe('Delete memory by ID'),
1028
- older_than: z
1029
- .string()
1030
- .optional()
1031
- .describe('Delete memories older than (e.g., "30d", "1w", "3m", "1y")'),
1032
- tag: z.string().optional().describe('Delete all memories with this tag'),
1033
- project_path: projectPathParam,
1034
- },
1035
- annotations: {
1036
- readOnlyHint: false,
1037
- destructiveHint: true,
1038
- idempotentHint: true,
1039
- openWorldHint: false,
1040
- },
1041
- }, async ({ id, older_than, tag, project_path }) => {
1042
- await applyProjectPath(project_path);
1043
- try {
1044
- // Delete by ID
1045
- if (id !== undefined) {
1046
- const memory = await getMemoryById(id);
1047
- if (!memory) {
1048
- return {
1049
- content: [
1050
- {
1051
- type: 'text',
1052
- text: `Memory with id ${id} not found.`,
1053
- },
1054
- ],
1055
- };
1056
- }
1057
- try {
1058
- const deleted = await deleteMemory(id);
1059
- if (deleted) {
1060
- return {
1061
- content: [
1062
- {
1063
- type: 'text',
1064
- text: `Forgot memory ${id}: "${memory.content.substring(0, 100)}${memory.content.length > 100 ? '...' : ''}"`,
1065
- },
1066
- ],
1067
- };
1068
- }
1069
- return {
1070
- content: [
1071
- {
1072
- type: 'text',
1073
- text: `Failed to delete memory ${id}`,
1074
- },
1075
- ],
1076
- isError: true,
1077
- };
1078
- }
1079
- catch (err) {
1080
- if (err?.name === 'PinnedMemoryError') {
1081
- return {
1082
- content: [
1083
- {
1084
- type: 'text',
1085
- text: `Cannot delete memory ${id}: it is pinned (Tier 1 — invariant rule or corrected memory). Pinned memories are protected from deletion. To force-delete, first unpin it with setMemoryInvariant(${id}, false) and reset correction_count.`,
1086
- },
1087
- ],
1088
- isError: true,
1089
- };
1090
- }
1091
- throw err;
1092
- }
1093
- }
1094
- // Delete older than date
1095
- if (older_than) {
1096
- const date = parseRelativeDate(older_than);
1097
- if (!date) {
1098
- return {
1099
- content: [
1100
- {
1101
- type: 'text',
1102
- text: `Invalid date format: ${older_than}. Use "30d", "1w", "3m", "1y", or ISO date.`,
1103
- },
1104
- ],
1105
- isError: true,
1106
- };
1107
- }
1108
- const count = await deleteMemoriesOlderThan(date);
1109
- return {
1110
- content: [
1111
- {
1112
- type: 'text',
1113
- text: `✓ Forgot ${count} memories older than ${date.toLocaleDateString()}`,
1114
- },
1115
- ],
1116
- };
1117
- }
1118
- // Delete by tag
1119
- if (tag) {
1120
- const count = await deleteMemoriesByTag(tag);
1121
- return {
1122
- content: [
1123
- {
1124
- type: 'text',
1125
- text: `✓ Forgot ${count} memories with tag "${tag}"`,
1126
- },
1127
- ],
1128
- };
1129
- }
1130
- return {
1131
- content: [
1132
- {
1133
- type: 'text',
1134
- text: 'Specify what to forget: id (number), older_than (e.g., "30d"), or tag (string)',
1135
- },
1136
- ],
1137
- };
1138
- }
1139
- catch (error) {
1140
- const errorMsg = error instanceof Error ? error.message : String(error);
1141
- return {
1142
- content: [
1143
- {
1144
- type: 'text',
1145
- text: `Error forgetting: ${errorMsg}`,
1146
- },
1147
- ],
1148
- isError: true,
1149
- };
1150
- }
1151
- finally {
1152
- closeDb();
1153
- }
1154
- });
1155
- }
1156
- // ============================================================================
1157
- // Temporal Query Decomposition Helper
1158
- // ============================================================================
1159
- /**
1160
- * Extract sub-queries from temporal questions for multi-pass retrieval.
1161
- * Supports English and Russian patterns.
1162
- *
1163
- * EN: "How many days between starting project X and deploying it?"
1164
- * → ["starting project X", "deploying project X"]
1165
- * RU: "Сколько дней между началом проекта X и деплоем?"
1166
- * → ["началом проекта X", "деплоем"]
1167
- */
1168
- function extractTemporalSubqueries(query) {
1169
- // EN: "between X and Y" / RU: "между X и Y"
1170
- const betweenMatch = query.match(/(?:between|между)\s+(.+?)\s+(?:and|и)\s+(.+?)(?:\?|$)/i);
1171
- if (betweenMatch) {
1172
- return [betweenMatch[1].trim(), betweenMatch[2].trim()];
1173
- }
1174
- // EN: "from X to Y" / RU: "от X до Y" / "с X до Y" / "с X по Y"
1175
- const fromToMatch = query.match(/(?:from|от|с)\s+(.+?)\s+(?:to|до|по)\s+(.+?)(?:\?|$)/i);
1176
- if (fromToMatch) {
1177
- return [fromToMatch[1].trim(), fromToMatch[2].trim()];
1178
- }
1179
- // EN: "after X ... before Y" / "since X ... until Y"
1180
- // RU: "после X ... до Y" / "с тех пор как X ... до Y"
1181
- const afterBeforeMatch = query.match(/(?:after|since|после|с тех пор как)\s+(.+?)\s+(?:and|but|и|но)?\s*(?:before|until|до|перед)\s+(.+?)(?:\?|$)/i);
1182
- if (afterBeforeMatch) {
1183
- return [afterBeforeMatch[1].trim(), afterBeforeMatch[2].trim()];
1184
- }
1185
- // EN: "first time X ... last time Y"
1186
- // RU: "первый раз X ... последний раз Y" / "впервые X ... в последний раз Y"
1187
- const firstLastMatch = query.match(/(?:first\s+(?:time\s+)?|впервые\s+|в первый раз\s+)(.+?)\s+(?:and|,|и)\s*(?:last\s+(?:time\s+)?|в последний раз\s+|последний раз\s+)(.+?)(?:\?|$)/i);
1188
- if (firstLastMatch) {
1189
- return [firstLastMatch[1].trim(), firstLastMatch[2].trim()];
1190
- }
1191
- // No decomposition pattern matched — return original
1192
- return [query];
1193
- }
1194
- /**
1195
- * Async version with LLM fallback for languages not covered by regex.
1196
- * Fast path: regex (sync, 0ms). Slow path: LLM decomposition (any language).
1197
- * Only invokes LLM when query contains non-Latin/Cyrillic characters (likely unsupported language).
1198
- */
1199
- async function extractTemporalSubqueriesAsync(query) {
1200
- // Fast path: regex handles EN + RU
1201
- const regexResult = extractTemporalSubqueries(query);
1202
- if (regexResult.length > 1)
1203
- return regexResult;
1204
- // Only invoke LLM if the query contains characters outside Latin/Cyrillic scripts
1205
- // This avoids unnecessary LLM calls for EN/RU queries that simply have no temporal range
1206
- const hasNonLatinCyrillic = /[^\u0020-\u024F\u0400-\u04FF\s\d\p{P}]/u.test(query);
1207
- if (!hasNonLatinCyrillic)
1208
- return [query];
1209
- // Slow path: LLM decomposition for other languages (CJK, Arabic, etc.)
1210
- try {
1211
- const { callLLMChat } = await import('../../lib/llm.js');
1212
- const result = await callLLMChat([
1213
- {
1214
- role: 'system',
1215
- content: TEMPORAL_SUBQUERY_SYSTEM,
1216
- },
1217
- { role: 'user', content: query },
1218
- ], { maxTokens: 200 });
1219
- const parsed = JSON.parse(result.trim());
1220
- if (Array.isArray(parsed) &&
1221
- parsed.length > 0 &&
1222
- parsed.every((s) => typeof s === 'string')) {
1223
- return parsed;
1224
- }
1225
- }
1226
- catch {
1227
- // LLM failed — fall through to original query
1228
- }
1229
- return [query];
5
+ registerRememberTool(server);
6
+ registerRecallTool(server);
7
+ registerForgetTool(server);
1230
8
  }
1231
9
  //# sourceMappingURL=memory.js.map