claude-memory-layer 1.0.27 → 1.0.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (331) hide show
  1. package/.env.example +7 -0
  2. package/AGENTS.md +11 -0
  3. package/README.md +374 -49
  4. package/benchmarks/replay/anonymized-real-sessions.json +48 -0
  5. package/dist/cli/index.js +10097 -6003
  6. package/dist/cli/index.js.map +4 -4
  7. package/dist/core/index.js +9745 -5587
  8. package/dist/core/index.js.map +4 -4
  9. package/dist/hooks/post-tool-use.js +6545 -5270
  10. package/dist/hooks/post-tool-use.js.map +4 -4
  11. package/dist/hooks/semantic-daemon.js +6646 -5354
  12. package/dist/hooks/semantic-daemon.js.map +4 -4
  13. package/dist/hooks/session-end.js +6618 -5347
  14. package/dist/hooks/session-end.js.map +4 -4
  15. package/dist/hooks/session-start.js +6619 -5354
  16. package/dist/hooks/session-start.js.map +4 -4
  17. package/dist/hooks/stop.js +6614 -5325
  18. package/dist/hooks/stop.js.map +4 -4
  19. package/dist/hooks/user-prompt-submit.js +6702 -5356
  20. package/dist/hooks/user-prompt-submit.js.map +4 -4
  21. package/dist/index.js +13537 -0
  22. package/dist/index.js.map +7 -0
  23. package/dist/mcp/index.js +20770 -0
  24. package/dist/mcp/index.js.map +7 -0
  25. package/dist/server/api/index.js +6632 -5319
  26. package/dist/server/api/index.js.map +4 -4
  27. package/dist/server/index.js +6667 -5340
  28. package/dist/server/index.js.map +4 -4
  29. package/dist/services/memory-service.js +6568 -5350
  30. package/dist/services/memory-service.js.map +4 -4
  31. package/dist/ui/assets/js/bootstrap.js +244 -0
  32. package/dist/ui/assets/js/chat.js +373 -0
  33. package/dist/ui/assets/js/disclosure.js +232 -0
  34. package/dist/ui/assets/js/modals.js +298 -0
  35. package/dist/ui/assets/js/overview.js +655 -0
  36. package/dist/ui/assets/js/state.js +72 -0
  37. package/dist/ui/assets/js/views.js +468 -0
  38. package/dist/ui/index.html +43 -1
  39. package/dist/ui/index.ts +3 -0
  40. package/dist/ui/style.css +222 -0
  41. package/docs/ARCHITECTURE_COMPARISON_AND_RECOMMENDATIONS.md +627 -0
  42. package/docs/HERMES_MEMORY_INGESTION_ANALYSIS.md +440 -0
  43. package/docs/MEMORY_USEFULNESS_AUDIT.md +371 -0
  44. package/docs/MEMORY_USEFULNESS_AUDIT_RAW.json +80 -0
  45. package/docs/MEMSEARCH_PROJECT_STRUCTURE_ANALYSIS.md +333 -0
  46. package/docs/PRODUCT_VALIDATION_MATRIX.md +82 -0
  47. package/docs/PROJECT_STRUCTURE_ANALYSIS.md +421 -0
  48. package/docs/REFACTORING_MILESTONES_AND_ISSUES.md +501 -0
  49. package/docs/REFACTORING_PLAN_THIN_CORE.md +414 -0
  50. package/docs/REFERENCE_PROJECT_ANALYSES.md +25 -0
  51. package/docs/SUPERLOCALMEMORY_PROJECT_STRUCTURE_ANALYSIS.md +452 -0
  52. package/docs/TARGET_ARCHITECTURE_AND_FOLDER_STRUCTURE.md +446 -0
  53. package/docs/architecture/comparison-index.md +47 -0
  54. package/docs/reports/codex-real-data-validation-20260505T040447Z.md +46 -0
  55. package/package.json +12 -5
  56. package/scripts/build.ts +25 -8
  57. package/scripts/generate-session-qrels.ts +126 -0
  58. package/scripts/postinstall-embedding-backend.cjs +142 -0
  59. package/scripts/replay-retrieval-benchmark.ts +69 -0
  60. package/specs/thin-core-refactor/context.md +275 -0
  61. package/specs/thin-core-refactor/plan.md +536 -0
  62. package/specs/thin-core-refactor/spec.md +465 -0
  63. package/src/adapters/claude/capture/index.ts +3 -0
  64. package/src/adapters/claude/context/index.ts +3 -0
  65. package/src/adapters/claude/hooks/index.ts +21 -0
  66. package/src/adapters/claude/hooks/post-tool-use.ts +239 -0
  67. package/src/adapters/claude/hooks/prompt-injection-policy.ts +104 -0
  68. package/src/adapters/claude/hooks/semantic-daemon-client.ts +209 -0
  69. package/src/adapters/claude/hooks/semantic-daemon.ts +283 -0
  70. package/src/adapters/claude/hooks/session-end.ts +59 -0
  71. package/src/adapters/claude/hooks/session-start.ts +73 -0
  72. package/src/adapters/claude/hooks/stop.ts +128 -0
  73. package/src/adapters/claude/hooks/user-prompt-submit.ts +361 -0
  74. package/src/adapters/claude/index.ts +4 -0
  75. package/src/adapters/claude/transcript/index.ts +4 -0
  76. package/src/adapters/claude/transcript/transcript-reader.ts +57 -0
  77. package/src/adapters/claude/transcript/turn-reconstructor.ts +65 -0
  78. package/src/apps/cli/claude-settings-hooks.ts +138 -0
  79. package/src/apps/cli/codex-import-runner.ts +125 -0
  80. package/src/apps/cli/codex-validation-output.ts +95 -0
  81. package/src/apps/cli/hermes-import-runner.ts +130 -0
  82. package/src/apps/cli/hermes-validation-output.ts +91 -0
  83. package/src/apps/cli/index.ts +1731 -0
  84. package/src/apps/cli/mcp-install.ts +106 -0
  85. package/src/apps/cli/retrieval-disclosure-output.ts +196 -0
  86. package/src/apps/dashboard/assets/js/bootstrap.js +244 -0
  87. package/src/apps/dashboard/assets/js/chat.js +373 -0
  88. package/src/apps/dashboard/assets/js/disclosure.js +232 -0
  89. package/src/apps/dashboard/assets/js/modals.js +298 -0
  90. package/src/apps/dashboard/assets/js/overview.js +655 -0
  91. package/src/apps/dashboard/assets/js/state.js +72 -0
  92. package/src/apps/dashboard/assets/js/views.js +468 -0
  93. package/src/{ui → apps/dashboard}/index.html +43 -1
  94. package/src/apps/dashboard/index.ts +3 -0
  95. package/src/{ui → apps/dashboard}/style.css +222 -0
  96. package/src/apps/index.ts +5 -0
  97. package/src/apps/server/api/chat.ts +244 -0
  98. package/src/apps/server/api/citations.ts +105 -0
  99. package/src/apps/server/api/events.ts +137 -0
  100. package/src/apps/server/api/health.ts +53 -0
  101. package/src/apps/server/api/index.ts +26 -0
  102. package/src/apps/server/api/projects.ts +74 -0
  103. package/src/apps/server/api/search.ts +184 -0
  104. package/src/apps/server/api/sessions.ts +115 -0
  105. package/src/apps/server/api/stats.ts +723 -0
  106. package/src/apps/server/api/turns.ts +143 -0
  107. package/src/apps/server/api/utils.ts +65 -0
  108. package/src/apps/server/index.ts +111 -0
  109. package/src/cli/index.ts +2 -1311
  110. package/src/cli/retrieval-disclosure-output.ts +2 -0
  111. package/src/compat/index.ts +5 -0
  112. package/src/core/derive/fact-deriver.ts +170 -0
  113. package/src/core/derive/index.ts +2 -0
  114. package/src/core/derive/summary-deriver.ts +76 -0
  115. package/src/core/embedder.ts +4 -152
  116. package/src/core/engine/embedding-maintenance-service.ts +187 -0
  117. package/src/core/engine/endless-memory-services.ts +4 -0
  118. package/src/core/engine/index.ts +19 -0
  119. package/src/core/engine/memory-engine-services.ts +170 -0
  120. package/src/core/engine/memory-ingest-service.ts +317 -0
  121. package/src/core/engine/memory-query-service.ts +173 -0
  122. package/src/core/engine/memory-runtime-service.ts +162 -0
  123. package/src/core/engine/memory-service-composition.ts +231 -0
  124. package/src/core/engine/retrieval-analytics-service.ts +181 -0
  125. package/src/core/engine/retrieval-disclosure-service.ts +420 -0
  126. package/src/core/engine/retrieval-orchestrator.ts +377 -0
  127. package/src/core/engine/retrieval-services.ts +176 -0
  128. package/src/core/engine/shared-memory-services.ts +4 -0
  129. package/src/core/entity-repo.ts +1 -3
  130. package/src/core/event-store.ts +3 -3
  131. package/src/core/evidence-aligner.ts +2 -2
  132. package/src/core/external-market-context.ts +582 -0
  133. package/src/core/graduation.ts +2 -3
  134. package/src/core/index.ts +21 -0
  135. package/src/core/matcher.ts +2 -4
  136. package/src/core/model/memory-fact.ts +30 -0
  137. package/src/core/model/memory-rule.ts +14 -0
  138. package/src/core/model/memory-summary.ts +21 -0
  139. package/src/core/model/raw-event.ts +28 -0
  140. package/src/core/model/retrieval-result.ts +35 -0
  141. package/src/core/privacy/filter.ts +21 -10
  142. package/src/core/product-validation-matrix.ts +314 -0
  143. package/src/core/progressive-retriever.ts +1 -2
  144. package/src/core/registry/project-path.ts +54 -0
  145. package/src/core/registry/session-registry.ts +69 -0
  146. package/src/core/replay-evaluator.ts +625 -0
  147. package/src/core/retrieval-benchmark.ts +117 -0
  148. package/src/core/retrieval-quality.ts +109 -0
  149. package/src/core/retriever.ts +53 -15
  150. package/src/core/session-qrels.ts +360 -0
  151. package/src/core/shared-event-store.ts +1 -1
  152. package/src/core/sqlite-event-store.ts +35 -11
  153. package/src/core/task/blocker-resolver.ts +2 -2
  154. package/src/core/task/task-resolver.ts +0 -1
  155. package/src/core/vector-outbox.ts +1 -10
  156. package/src/core/vector-worker.ts +1 -1
  157. package/src/extensions/endless-memory/endless-memory-services.ts +350 -0
  158. package/src/extensions/endless-memory/index.ts +1 -0
  159. package/src/extensions/index.ts +5 -0
  160. package/src/extensions/mcp/handlers.ts +960 -0
  161. package/src/extensions/mcp/index.ts +48 -0
  162. package/src/extensions/mcp/tools.ts +252 -0
  163. package/src/extensions/shared-memory/index.ts +1 -0
  164. package/src/extensions/shared-memory/shared-memory-services.ts +211 -0
  165. package/src/extensions/vector/embedder.ts +197 -0
  166. package/src/extensions/vector/index.ts +1 -0
  167. package/src/hooks/post-tool-use.ts +3 -236
  168. package/src/hooks/semantic-daemon-client.ts +1 -208
  169. package/src/hooks/semantic-daemon.ts +6 -271
  170. package/src/hooks/session-end.ts +4 -79
  171. package/src/hooks/session-start.ts +4 -73
  172. package/src/hooks/stop.ts +3 -173
  173. package/src/hooks/user-prompt-submit.ts +3 -338
  174. package/src/index.ts +13 -0
  175. package/src/mcp/handlers.ts +2 -212
  176. package/src/mcp/index.ts +3 -46
  177. package/src/mcp/tools.ts +2 -78
  178. package/src/server/api/chat.ts +2 -244
  179. package/src/server/api/citations.ts +2 -105
  180. package/src/server/api/events.ts +2 -137
  181. package/src/server/api/health.ts +2 -53
  182. package/src/server/api/index.ts +2 -26
  183. package/src/server/api/projects.ts +2 -74
  184. package/src/server/api/search.ts +2 -102
  185. package/src/server/api/sessions.ts +2 -115
  186. package/src/server/api/stats.ts +2 -724
  187. package/src/server/api/turns.ts +2 -143
  188. package/src/server/api/utils.ts +2 -46
  189. package/src/server/index.ts +2 -100
  190. package/src/services/bootstrap-organizer.ts +46 -26
  191. package/src/services/codex-session-history-importer.ts +521 -29
  192. package/src/services/hermes-session-history-importer.ts +733 -0
  193. package/src/services/memory-service-config.ts +36 -0
  194. package/src/services/memory-service-registry.ts +150 -0
  195. package/src/services/memory-service.ts +211 -1325
  196. package/src/services/session-history-importer.ts +58 -14
  197. package/tests/README.md +23 -0
  198. package/tests/adapters/claude/claude-semantic-daemon-adapter.test.ts +54 -0
  199. package/tests/adapters/claude/claude-transcript-reconstructor.test.ts +98 -0
  200. package/tests/adapters/claude-hook-prompt-injection-policy.test.ts +99 -0
  201. package/tests/apps/app-layer-boundary.test.ts +48 -0
  202. package/tests/apps/claude-settings-hooks.test.ts +107 -0
  203. package/tests/apps/cli-disclosure-output.test.ts +212 -0
  204. package/tests/apps/codex-import-runner.test.ts +99 -0
  205. package/tests/apps/codex-validation-output.test.ts +100 -0
  206. package/tests/apps/hermes-import-runner.test.ts +99 -0
  207. package/tests/apps/mcp-install-command.test.ts +59 -0
  208. package/tests/apps/package-build-entrypoints.test.ts +30 -0
  209. package/tests/apps/postinstall-embedding-backend.test.ts +167 -0
  210. package/tests/apps/search-api-disclosure.test.ts +162 -0
  211. package/tests/apps/stats-api-lightweight.test.ts +67 -0
  212. package/tests/apps/ui-disclosure-output.test.ts +140 -0
  213. package/tests/{bootstrap-organizer.test.ts → core/bootstrap-organizer.test.ts} +1 -1
  214. package/tests/{canonical-key.test.ts → core/canonical-key.test.ts} +1 -1
  215. package/tests/core/codex-session-history-importer-validation.test.ts +185 -0
  216. package/tests/{consolidation-worker.test.ts → core/consolidation-worker.test.ts} +2 -2
  217. package/tests/core/embedding-maintenance-service.test.ts +282 -0
  218. package/tests/{evidence-aligner.test.ts → core/evidence-aligner.test.ts} +1 -1
  219. package/tests/core/external-market-context.test.ts +209 -0
  220. package/tests/core/fact-deriver.test.ts +79 -0
  221. package/tests/core/hermes-session-history-importer-validation.test.ts +609 -0
  222. package/tests/{ingest-interceptor.test.ts → core/ingest-interceptor.test.ts} +1 -1
  223. package/tests/{markdown-mirror.test.ts → core/markdown-mirror.test.ts} +2 -2
  224. package/tests/{matcher.test.ts → core/matcher.test.ts} +1 -1
  225. package/tests/{md-mirror.test.ts → core/md-mirror.test.ts} +2 -2
  226. package/tests/core/memory-engine-services.test.ts +240 -0
  227. package/tests/core/memory-ingest-service.test.ts +296 -0
  228. package/tests/core/memory-query-service.test.ts +129 -0
  229. package/tests/core/memory-runtime-service.test.ts +201 -0
  230. package/tests/core/memory-service-composition.test.ts +192 -0
  231. package/tests/core/memory-service-config.test.ts +41 -0
  232. package/tests/core/memory-service-facade.test.ts +30 -0
  233. package/tests/core/memory-service-registry.test.ts +206 -0
  234. package/tests/core/product-validation-matrix.test.ts +61 -0
  235. package/tests/core/project-registry.test.ts +78 -0
  236. package/tests/core/replay-evaluator.test.ts +181 -0
  237. package/tests/core/retrieval-analytics-service.test.ts +210 -0
  238. package/tests/core/retrieval-benchmark.test.ts +93 -0
  239. package/tests/core/retrieval-disclosure-service.test.ts +264 -0
  240. package/tests/core/retrieval-orchestrator.test.ts +403 -0
  241. package/tests/core/retrieval-quality.test.ts +31 -0
  242. package/tests/core/retrieval-services.test.ts +185 -0
  243. package/tests/{retriever-fallback-chain.test.ts → core/retriever-fallback-chain.test.ts} +3 -3
  244. package/tests/{retriever-strategy-scope.test.ts → core/retriever-strategy-scope.test.ts} +70 -3
  245. package/tests/{retriever.memu-adoption.test.ts → core/retriever.memu-adoption.test.ts} +3 -3
  246. package/tests/core/session-history-importer-filter.test.ts +78 -0
  247. package/tests/core/session-qrels.test.ts +250 -0
  248. package/tests/{sqlite-event-store-replication.test.ts → core/sqlite-event-store-replication.test.ts} +36 -1
  249. package/tests/core/summary-deriver.test.ts +66 -0
  250. package/tests/extensions/embedder-warning-suppression.test.ts +53 -0
  251. package/tests/extensions/endless-memory-extension-boundary.test.ts +17 -0
  252. package/tests/extensions/endless-memory-services.test.ts +325 -0
  253. package/tests/extensions/mcp-context-tools.test.ts +905 -0
  254. package/tests/extensions/mcp-extension-boundary.test.ts +21 -0
  255. package/tests/extensions/mcp-package-build.test.ts +22 -0
  256. package/tests/extensions/mcp-project-aware-tools.test.ts +102 -0
  257. package/tests/extensions/shared-memory-extension-boundary.test.ts +24 -0
  258. package/tests/extensions/shared-memory-services.test.ts +309 -0
  259. package/tests/extensions/vector-extension-boundary.test.ts +21 -0
  260. package/.claude/settings.local.json +0 -25
  261. package/.npm-cache/_cacache/content-v2/sha512/04/76/c098f88dfe584a2b80870bff7421b05d17d3d9ee1027f77772332a22d3f93a9a57101a2855107f6ad82077a818bba912b2bc317f2361b5ddb09ad284d9ce +0 -0
  262. package/.npm-cache/_cacache/content-v2/sha512/60/25/d2ecd39cfc7cab58351162814be77f935c6d6491c10c3745d456da7ddb2117ffd90c10e53fe3c0f1ed16b403307841543634504398b16ee4e6b6dd8e0c45 +0 -0
  263. package/.npm-cache/_cacache/index-v5/2b/9a/7f8f40206ed8a2e0a84efaa953ccaed1f5d001e14b931083f2e7a0738007 +0 -2
  264. package/.npm-cache/_cacache/index-v5/2e/d9/fcfa5c6a6abdc2a3644ab84a95936047298c465a2f47ee03db8f7fe1e946 +0 -3
  265. package/.npm-cache/_cacache/index-v5/a9/42/e519633356d12d3d2f19da66a8301016d496c8f5c3e0554124aaa62dc043 +0 -2
  266. package/.npm-cache/_logs/2026-02-26T12_04_52_729Z-debug-0.log +0 -256
  267. package/.npm-cache/_logs/2026-02-26T12_05_36_835Z-debug-0.log +0 -18
  268. package/.npm-cache/_logs/2026-02-26T12_05_45_982Z-debug-0.log +0 -32
  269. package/.npm-cache/_logs/2026-02-26T12_05_48_515Z-debug-0.log +0 -260
  270. package/.npm-cache/_logs/2026-02-26T12_05_53_567Z-debug-0.log +0 -69
  271. package/.npm-cache/_update-notifier-last-checked +0 -0
  272. package/bootstrap-kb/decisions/decisions.md +0 -244
  273. package/bootstrap-kb/glossary/glossary.md +0 -46
  274. package/bootstrap-kb/modules/.claude-plugin.md +0 -22
  275. package/bootstrap-kb/modules/agents.md.md +0 -15
  276. package/bootstrap-kb/modules/claude.md.md +0 -15
  277. package/bootstrap-kb/modules/context.md.md +0 -15
  278. package/bootstrap-kb/modules/docs.md +0 -18
  279. package/bootstrap-kb/modules/handoff.md.md +0 -15
  280. package/bootstrap-kb/modules/package-lock.json.md +0 -15
  281. package/bootstrap-kb/modules/package.json.md +0 -15
  282. package/bootstrap-kb/modules/plan.md.md +0 -15
  283. package/bootstrap-kb/modules/readme.md.md +0 -15
  284. package/bootstrap-kb/modules/scripts.md +0 -26
  285. package/bootstrap-kb/modules/spec.md.md +0 -15
  286. package/bootstrap-kb/modules/specs.md +0 -20
  287. package/bootstrap-kb/modules/src.md +0 -51
  288. package/bootstrap-kb/modules/tests.md +0 -42
  289. package/bootstrap-kb/modules/tsconfig.json.md +0 -15
  290. package/bootstrap-kb/modules/vitest.config.ts.md +0 -15
  291. package/bootstrap-kb/overview/overview.md +0 -40
  292. package/bootstrap-kb/sources/manifest.json +0 -950
  293. package/bootstrap-kb/sources/manifest.md +0 -227
  294. package/bootstrap-kb/timeline/timeline.md +0 -57
  295. package/claude-memory-layer-1.0.14.tgz +0 -0
  296. package/d.sh +0 -3
  297. package/deploy.sh +0 -3
  298. package/dist/ui/app.js +0 -2101
  299. package/memory/.claude-plugin/commands/2026-02-25.md +0 -263
  300. package/memory/_index.md +0 -419
  301. package/memory/agent_response/uncategorized/2026-02-26.md +0 -176
  302. package/memory/agent_response/uncategorized/2026-03-03.md +0 -14
  303. package/memory/agent_response/uncategorized/2026-03-04.md +0 -1421
  304. package/memory/agent_response/uncategorized/2026-03-05.md +0 -157
  305. package/memory/default/uncategorized/2026-02-25.md +0 -4839
  306. package/memory/session_summary/uncategorized/2026-02-26.md +0 -13
  307. package/memory/session_summary/uncategorized/2026-03-03.md +0 -5
  308. package/memory/session_summary/uncategorized/2026-03-04.md +0 -50
  309. package/memory/specs/20260207-dashboard-upgrade/2026-02-25.md +0 -142
  310. package/memory/specs/citations-system/2026-02-25.md +0 -1121
  311. package/memory/specs/endless-mode/2026-02-25.md +0 -1392
  312. package/memory/specs/entity-edge-model/2026-02-25.md +0 -1263
  313. package/memory/specs/evidence-aligner-v2/2026-02-25.md +0 -1028
  314. package/memory/specs/mcp-desktop-integration/2026-02-25.md +0 -1334
  315. package/memory/specs/post-tool-use-hook/2026-02-25.md +0 -1164
  316. package/memory/specs/private-tags/2026-02-25.md +0 -1057
  317. package/memory/specs/progressive-disclosure/2026-02-25.md +0 -1436
  318. package/memory/specs/task-entity-system/2026-02-25.md +0 -924
  319. package/memory/specs/vector-outbox-v2/2026-02-25.md +0 -1510
  320. package/memory/specs/web-viewer-ui/2026-02-25.md +0 -1709
  321. package/memory/tool_observation/uncategorized/2026-02-26.md +0 -209
  322. package/memory/tool_observation/uncategorized/2026-03-03.md +0 -21
  323. package/memory/tool_observation/uncategorized/2026-03-04.md +0 -1033
  324. package/memory/tool_observation/uncategorized/2026-03-05.md +0 -33
  325. package/memory/user_prompt/uncategorized/2026-02-26.md +0 -25
  326. package/memory/user_prompt/uncategorized/2026-03-04.md +0 -634
  327. package/memory/user_prompt/uncategorized/2026-03-05.md +0 -6
  328. package/specs/optional-duckdb/context.md +0 -77
  329. package/specs/optional-duckdb/plan.md +0 -142
  330. package/specs/optional-duckdb/spec.md +0 -35
  331. package/src/ui/app.js +0 -2101
@@ -0,0 +1,283 @@
1
+ import * as fs from 'fs';
2
+ import * as net from 'net';
3
+ import * as os from 'os';
4
+ import * as path from 'path';
5
+ import { DISABLED_SHARED_STORE_CONFIG, MemoryService } from '../../../services/memory-service.js';
6
+ import { getProjectStoragePath } from '../../../core/registry/project-path.js';
7
+ import { getSessionProject } from '../../../core/registry/session-registry.js';
8
+
9
+ export interface SemanticDaemonRequest {
10
+ type?: 'retrieve';
11
+ sessionId?: string;
12
+ prompt?: string;
13
+ topK?: number;
14
+ minScore?: number;
15
+ }
16
+
17
+ export interface SemanticMemory {
18
+ type: string;
19
+ content: string;
20
+ id?: string;
21
+ score?: number;
22
+ }
23
+
24
+ export interface SemanticDaemonResponse {
25
+ ok: boolean;
26
+ memories?: SemanticMemory[];
27
+ error?: string;
28
+ }
29
+
30
+ const SOCKET_PATH = process.env.CLAUDE_MEMORY_SEMANTIC_SOCKET || path.join(
31
+ os.homedir(),
32
+ '.claude-code',
33
+ 'memory',
34
+ 'semantic-daemon.sock'
35
+ );
36
+
37
+ const IDLE_TIMEOUT_MS = parseInt(process.env.CLAUDE_MEMORY_SEMANTIC_DAEMON_IDLE_MS || '600000');
38
+ const serviceCache = new Map<string, MemoryService>();
39
+
40
+ let server: net.Server | null = null;
41
+ let idleTimer: NodeJS.Timeout | null = null;
42
+ let shuttingDown = false;
43
+ let processHandlersInstalled = false;
44
+
45
+ function scheduleIdleShutdown(): void {
46
+ if (idleTimer) {
47
+ clearTimeout(idleTimer);
48
+ }
49
+
50
+ idleTimer = setTimeout(() => {
51
+ shutdown(0).catch(() => {
52
+ process.exit(0);
53
+ });
54
+ }, IDLE_TIMEOUT_MS);
55
+ idleTimer.unref();
56
+ }
57
+
58
+ export function parseSemanticDaemonRequest(raw: string): SemanticDaemonRequest {
59
+ try {
60
+ return JSON.parse(raw) as SemanticDaemonRequest;
61
+ } catch {
62
+ return {};
63
+ }
64
+ }
65
+
66
+ export function isValidSemanticDaemonRequest(
67
+ input: SemanticDaemonRequest
68
+ ): input is Required<SemanticDaemonRequest> {
69
+ return input.type === 'retrieve'
70
+ && typeof input.sessionId === 'string'
71
+ && input.sessionId.length > 0
72
+ && typeof input.prompt === 'string'
73
+ && input.prompt.length > 0
74
+ && Number.isFinite(input.topK)
75
+ && Number.isFinite(input.minScore);
76
+ }
77
+
78
+ export function makeSemanticDaemonErrorResponse(error: unknown): SemanticDaemonResponse {
79
+ return { ok: false, error: error instanceof Error ? error.message : 'unknown daemon error' };
80
+ }
81
+
82
+ export function isVectorSessionFilterError(error: unknown): boolean {
83
+ const message = error instanceof Error ? error.message.toLowerCase() : '';
84
+ return message.includes('no field named sessionid');
85
+ }
86
+
87
+ function getServiceForSession(sessionId: string): MemoryService {
88
+ const projectInfo = getSessionProject(sessionId);
89
+ const key = projectInfo?.projectHash || '__global__';
90
+
91
+ if (serviceCache.has(key)) {
92
+ return serviceCache.get(key)!;
93
+ }
94
+
95
+ const service = new MemoryService({
96
+ storagePath: projectInfo
97
+ ? getProjectStoragePath(projectInfo.projectPath)
98
+ : path.join(os.homedir(), '.claude-code', 'memory'),
99
+ projectHash: projectInfo?.projectHash,
100
+ projectPath: projectInfo?.projectPath,
101
+ readOnly: false,
102
+ embeddingOnly: true,
103
+ analyticsEnabled: false,
104
+ sharedStoreConfig: DISABLED_SHARED_STORE_CONFIG
105
+ });
106
+
107
+ serviceCache.set(key, service);
108
+ return service;
109
+ }
110
+
111
+ export async function handleSemanticDaemonRequest(raw: string): Promise<SemanticDaemonResponse> {
112
+ const input = parseSemanticDaemonRequest(raw);
113
+ if (!isValidSemanticDaemonRequest(input)) {
114
+ return { ok: false, error: 'invalid request' };
115
+ }
116
+
117
+ try {
118
+ const service = getServiceForSession(input.sessionId);
119
+ let result;
120
+ try {
121
+ result = await service.retrieveMemories(input.prompt, {
122
+ topK: input.topK,
123
+ minScore: input.minScore,
124
+ sessionId: input.sessionId,
125
+ intentRewrite: true,
126
+ adaptiveRerank: true,
127
+ projectScopeMode: 'strict'
128
+ });
129
+ } catch (error) {
130
+ if (!isVectorSessionFilterError(error)) {
131
+ throw error;
132
+ }
133
+
134
+ // LanceDB field-case mismatch can fail sessionId filtering.
135
+ // Retry without session filter and keep project strict scoping.
136
+ result = await service.retrieveMemories(input.prompt, {
137
+ topK: input.topK,
138
+ minScore: input.minScore,
139
+ intentRewrite: true,
140
+ adaptiveRerank: true,
141
+ projectScopeMode: 'strict'
142
+ });
143
+ }
144
+
145
+ const memories = result.memories.map((m) => ({
146
+ type: m.event.eventType,
147
+ content: m.event.content,
148
+ id: m.event.id,
149
+ score: m.score
150
+ }));
151
+
152
+ return { ok: true, memories };
153
+ } catch (error) {
154
+ return makeSemanticDaemonErrorResponse(error);
155
+ }
156
+ }
157
+
158
+ function createServer(): net.Server {
159
+ return net.createServer({ allowHalfOpen: true }, (socket) => {
160
+ scheduleIdleShutdown();
161
+ socket.setEncoding('utf8');
162
+
163
+ let requestRaw = '';
164
+
165
+ socket.on('data', (chunk) => {
166
+ requestRaw += chunk;
167
+ if (requestRaw.length > 1024 * 1024) {
168
+ socket.end(JSON.stringify({ ok: false, error: 'request too large' }));
169
+ }
170
+ });
171
+
172
+ socket.on('end', async () => {
173
+ const response = await handleSemanticDaemonRequest(requestRaw);
174
+ socket.end(JSON.stringify(response));
175
+ scheduleIdleShutdown();
176
+ });
177
+
178
+ socket.on('error', () => {
179
+ // Ignore per-socket errors to keep daemon process alive.
180
+ });
181
+ });
182
+ }
183
+
184
+ async function socketInUse(p: string): Promise<boolean> {
185
+ if (!fs.existsSync(p)) return false;
186
+ return new Promise((resolve) => {
187
+ let settled = false;
188
+ const client = net.createConnection(p);
189
+ const done = (alive: boolean) => {
190
+ if (settled) return;
191
+ settled = true;
192
+ client.destroy();
193
+ resolve(alive);
194
+ };
195
+ client.on('connect', () => done(true));
196
+ client.on('error', () => done(false));
197
+ setTimeout(() => done(false), 120).unref();
198
+ });
199
+ }
200
+
201
+ async function listenServer(): Promise<void> {
202
+ const socketDir = path.dirname(SOCKET_PATH);
203
+ if (!fs.existsSync(socketDir)) {
204
+ fs.mkdirSync(socketDir, { recursive: true });
205
+ }
206
+
207
+ if (await socketInUse(SOCKET_PATH)) {
208
+ process.exit(0);
209
+ }
210
+
211
+ if (fs.existsSync(SOCKET_PATH)) {
212
+ try {
213
+ fs.unlinkSync(SOCKET_PATH);
214
+ } catch {
215
+ // Ignore stale socket unlink failures.
216
+ }
217
+ }
218
+
219
+ server = createServer();
220
+
221
+ await new Promise<void>((resolve, reject) => {
222
+ if (!server) {
223
+ reject(new Error('daemon server not initialized'));
224
+ return;
225
+ }
226
+
227
+ server.once('error', reject);
228
+ server.listen(SOCKET_PATH, () => {
229
+ server?.off('error', reject);
230
+ resolve();
231
+ });
232
+ });
233
+ }
234
+
235
+ async function shutdown(code: number): Promise<void> {
236
+ if (shuttingDown) return;
237
+ shuttingDown = true;
238
+
239
+ if (idleTimer) {
240
+ clearTimeout(idleTimer);
241
+ }
242
+ idleTimer = null;
243
+
244
+ const closePromises: Promise<void>[] = [];
245
+ for (const service of serviceCache.values()) {
246
+ closePromises.push(service.shutdown().catch(() => undefined));
247
+ }
248
+ await Promise.all(closePromises);
249
+ serviceCache.clear();
250
+
251
+ if (server) {
252
+ await new Promise<void>((resolve) => {
253
+ server?.close(() => resolve());
254
+ });
255
+ }
256
+ server = null;
257
+
258
+ if (fs.existsSync(SOCKET_PATH)) {
259
+ try {
260
+ fs.unlinkSync(SOCKET_PATH);
261
+ } catch {
262
+ // Ignore socket cleanup failure.
263
+ }
264
+ }
265
+
266
+ process.exit(code);
267
+ }
268
+
269
+ function installProcessHandlers(): void {
270
+ if (processHandlersInstalled) return;
271
+ processHandlersInstalled = true;
272
+
273
+ process.on('SIGINT', () => { shutdown(0).catch(() => process.exit(0)); });
274
+ process.on('SIGTERM', () => { shutdown(0).catch(() => process.exit(0)); });
275
+ process.on('uncaughtException', () => { shutdown(1).catch(() => process.exit(1)); });
276
+ process.on('unhandledRejection', () => { shutdown(1).catch(() => process.exit(1)); });
277
+ }
278
+
279
+ export async function main(): Promise<void> {
280
+ installProcessHandlers();
281
+ await listenServer();
282
+ scheduleIdleShutdown();
283
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Session End Hook
3
+ * Called when session ends - generates and stores session summary
4
+ */
5
+
6
+ import { getLightweightMemoryService } from '../../../services/memory-service.js';
7
+ import type { SessionEndInput } from '../../../core/types.js';
8
+ import { generateSessionSummary } from '../transcript/turn-reconstructor.js';
9
+
10
+ export async function main(): Promise<void> {
11
+ // Read input from stdin
12
+ const inputData = await readStdin();
13
+ const input: SessionEndInput = JSON.parse(inputData);
14
+
15
+ // Use lightweight service (SQLite only, no embedder/vector - FAST!)
16
+ const memoryService = getLightweightMemoryService(input.session_id);
17
+
18
+ try {
19
+ // Get session history
20
+ const sessionEvents = await memoryService.getSessionHistory(input.session_id);
21
+
22
+ if (sessionEvents.length > 0) {
23
+ // Generate a simple session summary
24
+ const summary = generateSessionSummary(sessionEvents);
25
+
26
+ // Store session summary
27
+ await memoryService.storeSessionSummary(input.session_id, summary);
28
+
29
+ // End session with summary
30
+ await memoryService.endSession(input.session_id, summary);
31
+
32
+ // Evaluate helpfulness of memory retrievals in this session
33
+ try {
34
+ await memoryService.evaluateSessionHelpfulness(input.session_id);
35
+ } catch { /* non-critical */ }
36
+
37
+ // Process any pending embeddings
38
+ await memoryService.processPendingEmbeddings();
39
+ }
40
+
41
+ console.log(JSON.stringify({}));
42
+ } catch (error) {
43
+ console.error('Memory hook error:', error);
44
+ console.log(JSON.stringify({}));
45
+ }
46
+ }
47
+
48
+ function readStdin(): Promise<string> {
49
+ return new Promise((resolve) => {
50
+ let data = '';
51
+ process.stdin.setEncoding('utf8');
52
+ process.stdin.on('data', (chunk) => {
53
+ data += chunk;
54
+ });
55
+ process.stdin.on('end', () => {
56
+ resolve(data);
57
+ });
58
+ });
59
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Session Start Hook
3
+ * Called when a new Claude Code session starts
4
+ */
5
+
6
+ import { getLightweightMemoryService } from '../../../services/memory-service.js';
7
+ import { registerSession } from '../../../core/registry/session-registry.js';
8
+ import { ensureDaemonRunning } from './semantic-daemon-client.js';
9
+ import type { SessionStartInput, SessionStartOutput } from '../../../core/types.js';
10
+
11
+ export async function main(): Promise<void> {
12
+ // Read input from stdin
13
+ const inputData = await readStdin();
14
+ const input: SessionStartInput = JSON.parse(inputData);
15
+
16
+ // Register session with project path for other hooks to find
17
+ registerSession(input.session_id, input.cwd);
18
+
19
+ // Start semantic daemon in the background (non-blocking) so VectorWorker
20
+ // can process any pending embedding_outbox items immediately.
21
+ ensureDaemonRunning().catch(() => {
22
+ // Ignore - daemon will start on first prompt if needed
23
+ });
24
+
25
+ // Use lightweight service to avoid starting background workers in hook process
26
+ const memoryService = getLightweightMemoryService(input.session_id);
27
+
28
+ try {
29
+ // Start session in memory service
30
+ await memoryService.startSession(input.session_id, input.cwd);
31
+
32
+ // Backfill session summaries for recent sessions that ended without Stop hook
33
+ // (crash, force-close, etc.). Run in background - non-blocking.
34
+ memoryService.backfillMissingSummaries(input.session_id, 5).catch(() => {});
35
+
36
+ // Get recent context for this project (now automatically scoped)
37
+ const recentEvents = await memoryService.getRecentEvents(10);
38
+
39
+ let context = '';
40
+ if (recentEvents.length > 0) {
41
+ context = `## Previous Session Context\n\nYou have worked on this project before. Here are some relevant memories:\n\n`;
42
+ for (const event of recentEvents.slice(0, 3)) {
43
+ const date = event.timestamp.toISOString().split('T')[0];
44
+ context += `- **${date}**: ${event.content.slice(0, 150)}...\n`;
45
+ }
46
+ }
47
+
48
+ const output: SessionStartOutput = { context };
49
+ console.log(JSON.stringify(output));
50
+ } catch (error) {
51
+ console.error('Memory hook error:', error);
52
+ console.log(JSON.stringify({ context: '' }));
53
+ } finally {
54
+ try {
55
+ await memoryService.close();
56
+ } catch {
57
+ // Best-effort cleanup
58
+ }
59
+ }
60
+ }
61
+
62
+ function readStdin(): Promise<string> {
63
+ return new Promise((resolve) => {
64
+ let data = '';
65
+ process.stdin.setEncoding('utf8');
66
+ process.stdin.on('data', (chunk) => {
67
+ data += chunk;
68
+ });
69
+ process.stdin.on('end', () => {
70
+ resolve(data);
71
+ });
72
+ });
73
+ }
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Stop Hook
3
+ * Called when agent stops - reads transcript and stores assistant responses
4
+ *
5
+ * Actual Claude Code input format:
6
+ * {
7
+ * session_id, transcript_path, cwd, permission_mode,
8
+ * hook_event_name: "Stop", stop_hook_active
9
+ * }
10
+ *
11
+ * NOTE: Claude Code does NOT send messages in the Stop hook.
12
+ * We read them from the transcript JSONL file instead.
13
+ */
14
+
15
+ import { getLightweightMemoryService } from '../../../services/memory-service.js';
16
+ import { applyPrivacyFilter } from '../../../core/privacy/index.js';
17
+ import { readTurnState, clearTurnState, writeLastAssistantSnippet } from '../../../core/turn-state.js';
18
+ import type { StopInput, Config } from '../../../core/types.js';
19
+ import { extractAssistantMessages } from '../transcript/turn-reconstructor.js';
20
+
21
+ // Default privacy config
22
+ const DEFAULT_PRIVACY_CONFIG: Config['privacy'] = {
23
+ excludePatterns: ['password', 'secret', 'api_key', 'token', 'bearer'],
24
+ anonymize: false,
25
+ privateTags: {
26
+ enabled: true,
27
+ marker: '[PRIVATE]',
28
+ preserveLineCount: false,
29
+ supportedFormats: ['xml']
30
+ }
31
+ };
32
+
33
+ export async function main(): Promise<void> {
34
+ // Read input from stdin
35
+ const inputData = await readStdin();
36
+ const input: StopInput = JSON.parse(inputData);
37
+
38
+ // Use lightweight service (SQLite only, no embedder/vector - FAST!)
39
+ const memoryService = getLightweightMemoryService(input.session_id);
40
+
41
+ try {
42
+ // Read current turn_id from state file
43
+ const turnId = readTurnState(input.session_id);
44
+
45
+ // Read assistant messages from transcript
46
+ const assistantMessages = await extractAssistantMessages(input.transcript_path);
47
+
48
+ const MIN_AGENT_RESPONSE_LEN = parseInt(
49
+ process.env.CLAUDE_MEMORY_AGENT_RESPONSE_MIN_LEN || '150'
50
+ );
51
+ const lastIdx = assistantMessages.length - 1;
52
+
53
+ // Store each assistant response
54
+ for (let i = 0; i < assistantMessages.length; i++) {
55
+ const text = assistantMessages[i];
56
+ const isLast = i === lastIdx;
57
+
58
+ // Apply privacy filter
59
+ const filterResult = applyPrivacyFilter(text, DEFAULT_PRIVACY_CONFIG);
60
+ let content = filterResult.content;
61
+
62
+ // Truncate very long responses
63
+ if (content.length > 5000) {
64
+ content = content.slice(0, 5000) + '...[truncated]';
65
+ }
66
+
67
+ // Skip very short responses (likely just tool calls or transition messages)
68
+ // Always store the last message (may be the final answer)
69
+ if (!isLast && content.trim().length < MIN_AGENT_RESPONSE_LEN) continue;
70
+
71
+ await memoryService.storeAgentResponse(
72
+ input.session_id,
73
+ content,
74
+ {
75
+ privacy: filterResult.metadata,
76
+ ...(turnId ? { turnId } : {})
77
+ }
78
+ );
79
+ }
80
+
81
+ // Save last assistant response snippet for next-turn retrieval context enrichment
82
+ if (assistantMessages.length > 0) {
83
+ const lastMessage = assistantMessages[assistantMessages.length - 1];
84
+ writeLastAssistantSnippet(input.session_id, lastMessage);
85
+ }
86
+
87
+ // Clean up turn state file after processing
88
+ clearTurnState(input.session_id);
89
+
90
+ // Evaluate helpfulness of retrieved memories for this session
91
+ try {
92
+ await memoryService.evaluateSessionHelpfulness(input.session_id);
93
+ } catch {
94
+ // non-critical
95
+ }
96
+
97
+ // Generate session summary from recent events (rule-based, no LLM needed)
98
+ try {
99
+ await memoryService.generateSessionSummary(input.session_id);
100
+ } catch {
101
+ // non-critical
102
+ }
103
+
104
+ // Embeddings enqueued in SQLite - will be processed by vector worker when server runs
105
+ await memoryService.processPendingEmbeddings();
106
+
107
+ // Output empty (stop hook doesn't return context)
108
+ console.log(JSON.stringify({}));
109
+ } catch (error) {
110
+ if (process.env.CLAUDE_MEMORY_DEBUG) {
111
+ console.error('Stop hook error:', error);
112
+ }
113
+ console.log(JSON.stringify({}));
114
+ }
115
+ }
116
+
117
+ function readStdin(): Promise<string> {
118
+ return new Promise((resolve) => {
119
+ let data = '';
120
+ process.stdin.setEncoding('utf8');
121
+ process.stdin.on('data', (chunk) => {
122
+ data += chunk;
123
+ });
124
+ process.stdin.on('end', () => {
125
+ resolve(data);
126
+ });
127
+ });
128
+ }