claude-memory-layer 1.0.26 → 1.0.28

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 (328) hide show
  1. package/.env.example +7 -0
  2. package/AGENTS.md +11 -0
  3. package/README.md +184 -41
  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 +9 -5
  56. package/scripts/build.ts +25 -8
  57. package/scripts/generate-session-qrels.ts +126 -0
  58. package/scripts/replay-retrieval-benchmark.ts +69 -0
  59. package/specs/thin-core-refactor/context.md +275 -0
  60. package/specs/thin-core-refactor/plan.md +536 -0
  61. package/specs/thin-core-refactor/spec.md +465 -0
  62. package/src/adapters/claude/capture/index.ts +3 -0
  63. package/src/adapters/claude/context/index.ts +3 -0
  64. package/src/adapters/claude/hooks/index.ts +21 -0
  65. package/src/adapters/claude/hooks/post-tool-use.ts +239 -0
  66. package/src/adapters/claude/hooks/prompt-injection-policy.ts +104 -0
  67. package/src/adapters/claude/hooks/semantic-daemon-client.ts +209 -0
  68. package/src/adapters/claude/hooks/semantic-daemon.ts +283 -0
  69. package/src/adapters/claude/hooks/session-end.ts +59 -0
  70. package/src/adapters/claude/hooks/session-start.ts +73 -0
  71. package/src/adapters/claude/hooks/stop.ts +128 -0
  72. package/src/adapters/claude/hooks/user-prompt-submit.ts +361 -0
  73. package/src/adapters/claude/index.ts +4 -0
  74. package/src/adapters/claude/transcript/index.ts +4 -0
  75. package/src/adapters/claude/transcript/transcript-reader.ts +57 -0
  76. package/src/adapters/claude/transcript/turn-reconstructor.ts +65 -0
  77. package/src/apps/cli/claude-settings-hooks.ts +138 -0
  78. package/src/apps/cli/codex-import-runner.ts +125 -0
  79. package/src/apps/cli/codex-validation-output.ts +95 -0
  80. package/src/apps/cli/hermes-import-runner.ts +130 -0
  81. package/src/apps/cli/hermes-validation-output.ts +91 -0
  82. package/src/apps/cli/index.ts +1731 -0
  83. package/src/apps/cli/mcp-install.ts +106 -0
  84. package/src/apps/cli/retrieval-disclosure-output.ts +196 -0
  85. package/src/apps/dashboard/assets/js/bootstrap.js +244 -0
  86. package/src/apps/dashboard/assets/js/chat.js +373 -0
  87. package/src/apps/dashboard/assets/js/disclosure.js +232 -0
  88. package/src/apps/dashboard/assets/js/modals.js +298 -0
  89. package/src/apps/dashboard/assets/js/overview.js +655 -0
  90. package/src/apps/dashboard/assets/js/state.js +72 -0
  91. package/src/apps/dashboard/assets/js/views.js +468 -0
  92. package/src/{ui → apps/dashboard}/index.html +43 -1
  93. package/src/apps/dashboard/index.ts +3 -0
  94. package/src/{ui → apps/dashboard}/style.css +222 -0
  95. package/src/apps/index.ts +5 -0
  96. package/src/apps/server/api/chat.ts +244 -0
  97. package/src/apps/server/api/citations.ts +105 -0
  98. package/src/apps/server/api/events.ts +137 -0
  99. package/src/apps/server/api/health.ts +53 -0
  100. package/src/apps/server/api/index.ts +26 -0
  101. package/src/apps/server/api/projects.ts +74 -0
  102. package/src/apps/server/api/search.ts +184 -0
  103. package/src/apps/server/api/sessions.ts +115 -0
  104. package/src/apps/server/api/stats.ts +723 -0
  105. package/src/apps/server/api/turns.ts +143 -0
  106. package/src/apps/server/api/utils.ts +65 -0
  107. package/src/apps/server/index.ts +111 -0
  108. package/src/cli/index.ts +2 -1311
  109. package/src/cli/retrieval-disclosure-output.ts +2 -0
  110. package/src/compat/index.ts +5 -0
  111. package/src/core/derive/fact-deriver.ts +170 -0
  112. package/src/core/derive/index.ts +2 -0
  113. package/src/core/derive/summary-deriver.ts +76 -0
  114. package/src/core/embedder.ts +4 -152
  115. package/src/core/engine/embedding-maintenance-service.ts +187 -0
  116. package/src/core/engine/endless-memory-services.ts +4 -0
  117. package/src/core/engine/index.ts +19 -0
  118. package/src/core/engine/memory-engine-services.ts +170 -0
  119. package/src/core/engine/memory-ingest-service.ts +317 -0
  120. package/src/core/engine/memory-query-service.ts +173 -0
  121. package/src/core/engine/memory-runtime-service.ts +162 -0
  122. package/src/core/engine/memory-service-composition.ts +231 -0
  123. package/src/core/engine/retrieval-analytics-service.ts +181 -0
  124. package/src/core/engine/retrieval-disclosure-service.ts +420 -0
  125. package/src/core/engine/retrieval-orchestrator.ts +377 -0
  126. package/src/core/engine/retrieval-services.ts +176 -0
  127. package/src/core/engine/shared-memory-services.ts +4 -0
  128. package/src/core/entity-repo.ts +1 -3
  129. package/src/core/event-store.ts +3 -3
  130. package/src/core/evidence-aligner.ts +2 -2
  131. package/src/core/external-market-context.ts +582 -0
  132. package/src/core/graduation.ts +2 -3
  133. package/src/core/index.ts +21 -0
  134. package/src/core/matcher.ts +2 -4
  135. package/src/core/model/memory-fact.ts +30 -0
  136. package/src/core/model/memory-rule.ts +14 -0
  137. package/src/core/model/memory-summary.ts +21 -0
  138. package/src/core/model/raw-event.ts +28 -0
  139. package/src/core/model/retrieval-result.ts +35 -0
  140. package/src/core/privacy/filter.ts +21 -10
  141. package/src/core/product-validation-matrix.ts +314 -0
  142. package/src/core/progressive-retriever.ts +1 -2
  143. package/src/core/registry/project-path.ts +54 -0
  144. package/src/core/registry/session-registry.ts +69 -0
  145. package/src/core/replay-evaluator.ts +625 -0
  146. package/src/core/retrieval-benchmark.ts +117 -0
  147. package/src/core/retrieval-quality.ts +109 -0
  148. package/src/core/retriever.ts +53 -15
  149. package/src/core/session-qrels.ts +360 -0
  150. package/src/core/shared-event-store.ts +1 -1
  151. package/src/core/sqlite-event-store.ts +35 -11
  152. package/src/core/task/blocker-resolver.ts +2 -2
  153. package/src/core/task/task-resolver.ts +0 -1
  154. package/src/core/vector-outbox.ts +1 -10
  155. package/src/core/vector-worker.ts +1 -1
  156. package/src/extensions/endless-memory/endless-memory-services.ts +350 -0
  157. package/src/extensions/endless-memory/index.ts +1 -0
  158. package/src/extensions/index.ts +5 -0
  159. package/src/extensions/mcp/handlers.ts +960 -0
  160. package/src/extensions/mcp/index.ts +48 -0
  161. package/src/extensions/mcp/tools.ts +252 -0
  162. package/src/extensions/shared-memory/index.ts +1 -0
  163. package/src/extensions/shared-memory/shared-memory-services.ts +211 -0
  164. package/src/extensions/vector/embedder.ts +197 -0
  165. package/src/extensions/vector/index.ts +1 -0
  166. package/src/hooks/post-tool-use.ts +3 -236
  167. package/src/hooks/semantic-daemon-client.ts +1 -208
  168. package/src/hooks/semantic-daemon.ts +6 -271
  169. package/src/hooks/session-end.ts +4 -79
  170. package/src/hooks/session-start.ts +4 -73
  171. package/src/hooks/stop.ts +3 -173
  172. package/src/hooks/user-prompt-submit.ts +3 -338
  173. package/src/index.ts +13 -0
  174. package/src/mcp/handlers.ts +2 -212
  175. package/src/mcp/index.ts +3 -46
  176. package/src/mcp/tools.ts +2 -78
  177. package/src/server/api/chat.ts +2 -244
  178. package/src/server/api/citations.ts +2 -105
  179. package/src/server/api/events.ts +2 -137
  180. package/src/server/api/health.ts +2 -53
  181. package/src/server/api/index.ts +2 -26
  182. package/src/server/api/projects.ts +2 -74
  183. package/src/server/api/search.ts +2 -102
  184. package/src/server/api/sessions.ts +2 -115
  185. package/src/server/api/stats.ts +2 -724
  186. package/src/server/api/turns.ts +2 -143
  187. package/src/server/api/utils.ts +2 -46
  188. package/src/server/index.ts +2 -100
  189. package/src/services/bootstrap-organizer.ts +46 -26
  190. package/src/services/codex-session-history-importer.ts +521 -29
  191. package/src/services/hermes-session-history-importer.ts +733 -0
  192. package/src/services/memory-service-config.ts +36 -0
  193. package/src/services/memory-service-registry.ts +150 -0
  194. package/src/services/memory-service.ts +211 -1325
  195. package/src/services/session-history-importer.ts +58 -14
  196. package/tests/README.md +23 -0
  197. package/tests/adapters/claude/claude-semantic-daemon-adapter.test.ts +54 -0
  198. package/tests/adapters/claude/claude-transcript-reconstructor.test.ts +98 -0
  199. package/tests/adapters/claude-hook-prompt-injection-policy.test.ts +99 -0
  200. package/tests/apps/app-layer-boundary.test.ts +48 -0
  201. package/tests/apps/claude-settings-hooks.test.ts +107 -0
  202. package/tests/apps/cli-disclosure-output.test.ts +212 -0
  203. package/tests/apps/codex-import-runner.test.ts +99 -0
  204. package/tests/apps/codex-validation-output.test.ts +100 -0
  205. package/tests/apps/hermes-import-runner.test.ts +99 -0
  206. package/tests/apps/mcp-install-command.test.ts +59 -0
  207. package/tests/apps/package-build-entrypoints.test.ts +30 -0
  208. package/tests/apps/search-api-disclosure.test.ts +162 -0
  209. package/tests/apps/stats-api-lightweight.test.ts +67 -0
  210. package/tests/apps/ui-disclosure-output.test.ts +140 -0
  211. package/tests/{bootstrap-organizer.test.ts → core/bootstrap-organizer.test.ts} +1 -1
  212. package/tests/{canonical-key.test.ts → core/canonical-key.test.ts} +1 -1
  213. package/tests/core/codex-session-history-importer-validation.test.ts +185 -0
  214. package/tests/{consolidation-worker.test.ts → core/consolidation-worker.test.ts} +2 -2
  215. package/tests/core/embedding-maintenance-service.test.ts +282 -0
  216. package/tests/{evidence-aligner.test.ts → core/evidence-aligner.test.ts} +1 -1
  217. package/tests/core/external-market-context.test.ts +209 -0
  218. package/tests/core/fact-deriver.test.ts +79 -0
  219. package/tests/core/hermes-session-history-importer-validation.test.ts +609 -0
  220. package/tests/{ingest-interceptor.test.ts → core/ingest-interceptor.test.ts} +1 -1
  221. package/tests/{markdown-mirror.test.ts → core/markdown-mirror.test.ts} +2 -2
  222. package/tests/{matcher.test.ts → core/matcher.test.ts} +1 -1
  223. package/tests/{md-mirror.test.ts → core/md-mirror.test.ts} +2 -2
  224. package/tests/core/memory-engine-services.test.ts +240 -0
  225. package/tests/core/memory-ingest-service.test.ts +296 -0
  226. package/tests/core/memory-query-service.test.ts +129 -0
  227. package/tests/core/memory-runtime-service.test.ts +201 -0
  228. package/tests/core/memory-service-composition.test.ts +192 -0
  229. package/tests/core/memory-service-config.test.ts +41 -0
  230. package/tests/core/memory-service-facade.test.ts +30 -0
  231. package/tests/core/memory-service-registry.test.ts +206 -0
  232. package/tests/core/product-validation-matrix.test.ts +61 -0
  233. package/tests/core/project-registry.test.ts +78 -0
  234. package/tests/core/replay-evaluator.test.ts +181 -0
  235. package/tests/core/retrieval-analytics-service.test.ts +210 -0
  236. package/tests/core/retrieval-benchmark.test.ts +93 -0
  237. package/tests/core/retrieval-disclosure-service.test.ts +264 -0
  238. package/tests/core/retrieval-orchestrator.test.ts +403 -0
  239. package/tests/core/retrieval-quality.test.ts +31 -0
  240. package/tests/core/retrieval-services.test.ts +185 -0
  241. package/tests/{retriever-fallback-chain.test.ts → core/retriever-fallback-chain.test.ts} +3 -3
  242. package/tests/{retriever-strategy-scope.test.ts → core/retriever-strategy-scope.test.ts} +70 -3
  243. package/tests/{retriever.memu-adoption.test.ts → core/retriever.memu-adoption.test.ts} +3 -3
  244. package/tests/core/session-history-importer-filter.test.ts +78 -0
  245. package/tests/core/session-qrels.test.ts +250 -0
  246. package/tests/{sqlite-event-store-replication.test.ts → core/sqlite-event-store-replication.test.ts} +36 -1
  247. package/tests/core/summary-deriver.test.ts +66 -0
  248. package/tests/extensions/embedder-warning-suppression.test.ts +53 -0
  249. package/tests/extensions/endless-memory-extension-boundary.test.ts +17 -0
  250. package/tests/extensions/endless-memory-services.test.ts +325 -0
  251. package/tests/extensions/mcp-context-tools.test.ts +905 -0
  252. package/tests/extensions/mcp-extension-boundary.test.ts +21 -0
  253. package/tests/extensions/mcp-package-build.test.ts +22 -0
  254. package/tests/extensions/mcp-project-aware-tools.test.ts +102 -0
  255. package/tests/extensions/shared-memory-extension-boundary.test.ts +24 -0
  256. package/tests/extensions/shared-memory-services.test.ts +309 -0
  257. package/tests/extensions/vector-extension-boundary.test.ts +21 -0
  258. package/.claude/settings.local.json +0 -25
  259. package/.npm-cache/_cacache/content-v2/sha512/04/76/c098f88dfe584a2b80870bff7421b05d17d3d9ee1027f77772332a22d3f93a9a57101a2855107f6ad82077a818bba912b2bc317f2361b5ddb09ad284d9ce +0 -0
  260. package/.npm-cache/_cacache/content-v2/sha512/60/25/d2ecd39cfc7cab58351162814be77f935c6d6491c10c3745d456da7ddb2117ffd90c10e53fe3c0f1ed16b403307841543634504398b16ee4e6b6dd8e0c45 +0 -0
  261. package/.npm-cache/_cacache/index-v5/2b/9a/7f8f40206ed8a2e0a84efaa953ccaed1f5d001e14b931083f2e7a0738007 +0 -2
  262. package/.npm-cache/_cacache/index-v5/2e/d9/fcfa5c6a6abdc2a3644ab84a95936047298c465a2f47ee03db8f7fe1e946 +0 -3
  263. package/.npm-cache/_cacache/index-v5/a9/42/e519633356d12d3d2f19da66a8301016d496c8f5c3e0554124aaa62dc043 +0 -2
  264. package/.npm-cache/_logs/2026-02-26T12_04_52_729Z-debug-0.log +0 -256
  265. package/.npm-cache/_logs/2026-02-26T12_05_36_835Z-debug-0.log +0 -18
  266. package/.npm-cache/_logs/2026-02-26T12_05_45_982Z-debug-0.log +0 -32
  267. package/.npm-cache/_logs/2026-02-26T12_05_48_515Z-debug-0.log +0 -260
  268. package/.npm-cache/_logs/2026-02-26T12_05_53_567Z-debug-0.log +0 -69
  269. package/.npm-cache/_update-notifier-last-checked +0 -0
  270. package/bootstrap-kb/decisions/decisions.md +0 -244
  271. package/bootstrap-kb/glossary/glossary.md +0 -46
  272. package/bootstrap-kb/modules/.claude-plugin.md +0 -22
  273. package/bootstrap-kb/modules/agents.md.md +0 -15
  274. package/bootstrap-kb/modules/claude.md.md +0 -15
  275. package/bootstrap-kb/modules/context.md.md +0 -15
  276. package/bootstrap-kb/modules/docs.md +0 -18
  277. package/bootstrap-kb/modules/handoff.md.md +0 -15
  278. package/bootstrap-kb/modules/package-lock.json.md +0 -15
  279. package/bootstrap-kb/modules/package.json.md +0 -15
  280. package/bootstrap-kb/modules/plan.md.md +0 -15
  281. package/bootstrap-kb/modules/readme.md.md +0 -15
  282. package/bootstrap-kb/modules/scripts.md +0 -26
  283. package/bootstrap-kb/modules/spec.md.md +0 -15
  284. package/bootstrap-kb/modules/specs.md +0 -20
  285. package/bootstrap-kb/modules/src.md +0 -51
  286. package/bootstrap-kb/modules/tests.md +0 -42
  287. package/bootstrap-kb/modules/tsconfig.json.md +0 -15
  288. package/bootstrap-kb/modules/vitest.config.ts.md +0 -15
  289. package/bootstrap-kb/overview/overview.md +0 -40
  290. package/bootstrap-kb/sources/manifest.json +0 -950
  291. package/bootstrap-kb/sources/manifest.md +0 -227
  292. package/bootstrap-kb/timeline/timeline.md +0 -57
  293. package/claude-memory-layer-1.0.14.tgz +0 -0
  294. package/d.sh +0 -3
  295. package/deploy.sh +0 -3
  296. package/dist/ui/app.js +0 -2101
  297. package/memory/.claude-plugin/commands/2026-02-25.md +0 -263
  298. package/memory/_index.md +0 -418
  299. package/memory/agent_response/uncategorized/2026-02-26.md +0 -176
  300. package/memory/agent_response/uncategorized/2026-03-03.md +0 -14
  301. package/memory/agent_response/uncategorized/2026-03-04.md +0 -1421
  302. package/memory/agent_response/uncategorized/2026-03-05.md +0 -48
  303. package/memory/default/uncategorized/2026-02-25.md +0 -4839
  304. package/memory/session_summary/uncategorized/2026-02-26.md +0 -13
  305. package/memory/session_summary/uncategorized/2026-03-03.md +0 -5
  306. package/memory/session_summary/uncategorized/2026-03-04.md +0 -50
  307. package/memory/specs/20260207-dashboard-upgrade/2026-02-25.md +0 -142
  308. package/memory/specs/citations-system/2026-02-25.md +0 -1121
  309. package/memory/specs/endless-mode/2026-02-25.md +0 -1392
  310. package/memory/specs/entity-edge-model/2026-02-25.md +0 -1263
  311. package/memory/specs/evidence-aligner-v2/2026-02-25.md +0 -1028
  312. package/memory/specs/mcp-desktop-integration/2026-02-25.md +0 -1334
  313. package/memory/specs/post-tool-use-hook/2026-02-25.md +0 -1164
  314. package/memory/specs/private-tags/2026-02-25.md +0 -1057
  315. package/memory/specs/progressive-disclosure/2026-02-25.md +0 -1436
  316. package/memory/specs/task-entity-system/2026-02-25.md +0 -924
  317. package/memory/specs/vector-outbox-v2/2026-02-25.md +0 -1510
  318. package/memory/specs/web-viewer-ui/2026-02-25.md +0 -1709
  319. package/memory/tool_observation/uncategorized/2026-02-26.md +0 -209
  320. package/memory/tool_observation/uncategorized/2026-03-03.md +0 -21
  321. package/memory/tool_observation/uncategorized/2026-03-04.md +0 -1033
  322. package/memory/tool_observation/uncategorized/2026-03-05.md +0 -29
  323. package/memory/user_prompt/uncategorized/2026-02-26.md +0 -25
  324. package/memory/user_prompt/uncategorized/2026-03-04.md +0 -634
  325. package/specs/optional-duckdb/context.md +0 -77
  326. package/specs/optional-duckdb/plan.md +0 -142
  327. package/specs/optional-duckdb/spec.md +0 -35
  328. package/src/ui/app.js +0 -2101
@@ -1526,3 +1526,225 @@ body {
1526
1526
  @media (max-width: 768px) {
1527
1527
  .chat-panel { width: 100%; }
1528
1528
  }
1529
+
1530
+ /* Progressive Retrieval Disclosure */
1531
+ .disclosure-card {
1532
+ margin-top: 24px;
1533
+ }
1534
+
1535
+ .disclosure-controls,
1536
+ .disclosure-search-row,
1537
+ .disclosure-layout,
1538
+ .disclosure-result-head,
1539
+ .disclosure-reasons,
1540
+ .disclosure-context-item {
1541
+ display: flex;
1542
+ gap: 8px;
1543
+ align-items: center;
1544
+ }
1545
+
1546
+ .disclosure-controls {
1547
+ flex-wrap: wrap;
1548
+ justify-content: flex-end;
1549
+ }
1550
+
1551
+ .disclosure-toggle {
1552
+ font-size: 12px;
1553
+ color: var(--text-muted);
1554
+ display: inline-flex;
1555
+ gap: 6px;
1556
+ align-items: center;
1557
+ }
1558
+
1559
+ .project-dropdown.compact {
1560
+ width: 92px;
1561
+ padding: 7px 10px;
1562
+ font-size: 12px;
1563
+ }
1564
+
1565
+ .search-input.compact {
1566
+ width: 70px;
1567
+ padding-left: 10px;
1568
+ }
1569
+
1570
+ .disclosure-search-row {
1571
+ align-items: stretch;
1572
+ margin-bottom: 8px;
1573
+ }
1574
+
1575
+ .disclosure-search-wrapper {
1576
+ flex: 1;
1577
+ }
1578
+
1579
+ .disclosure-status {
1580
+ min-height: 18px;
1581
+ font-size: 12px;
1582
+ color: var(--text-muted);
1583
+ margin-bottom: 10px;
1584
+ }
1585
+
1586
+ .disclosure-layout {
1587
+ align-items: stretch;
1588
+ gap: 12px;
1589
+ }
1590
+
1591
+ .disclosure-results,
1592
+ .disclosure-drilldown {
1593
+ flex: 1;
1594
+ min-width: 0;
1595
+ display: flex;
1596
+ flex-direction: column;
1597
+ gap: 8px;
1598
+ }
1599
+
1600
+ .disclosure-drilldown {
1601
+ background: rgba(0, 0, 0, 0.14);
1602
+ border: 1px solid rgba(255, 255, 255, 0.06);
1603
+ border-radius: 12px;
1604
+ padding: 12px;
1605
+ }
1606
+
1607
+ .disclosure-empty {
1608
+ color: var(--text-muted);
1609
+ font-size: 13px;
1610
+ text-align: center;
1611
+ padding: 18px;
1612
+ }
1613
+
1614
+ .disclosure-empty.compact {
1615
+ text-align: left;
1616
+ padding: 6px 0;
1617
+ }
1618
+
1619
+ .disclosure-meta {
1620
+ font-size: 11px;
1621
+ color: var(--text-muted);
1622
+ padding: 0 2px 4px;
1623
+ }
1624
+
1625
+ .disclosure-result {
1626
+ width: 100%;
1627
+ text-align: left;
1628
+ border: 1px solid rgba(255, 255, 255, 0.06);
1629
+ background: rgba(255, 255, 255, 0.025);
1630
+ border-radius: 12px;
1631
+ color: var(--text-secondary);
1632
+ padding: 10px;
1633
+ cursor: pointer;
1634
+ transition: all 0.18s ease;
1635
+ }
1636
+
1637
+ .disclosure-result:hover,
1638
+ .disclosure-result.active {
1639
+ border-color: var(--accent-primary);
1640
+ background: rgba(123, 97, 255, 0.10);
1641
+ }
1642
+
1643
+ .disclosure-result-head {
1644
+ justify-content: space-between;
1645
+ margin-bottom: 6px;
1646
+ }
1647
+
1648
+ .disclosure-score {
1649
+ font-size: 11px;
1650
+ color: var(--text-muted);
1651
+ }
1652
+
1653
+ .disclosure-title {
1654
+ font-size: 13px;
1655
+ font-weight: 600;
1656
+ color: var(--text-primary);
1657
+ margin-bottom: 4px;
1658
+ overflow: hidden;
1659
+ text-overflow: ellipsis;
1660
+ white-space: nowrap;
1661
+ }
1662
+
1663
+ .disclosure-snippet {
1664
+ font-size: 12px;
1665
+ color: var(--text-secondary);
1666
+ display: -webkit-box;
1667
+ -webkit-line-clamp: 2;
1668
+ -webkit-box-orient: vertical;
1669
+ overflow: hidden;
1670
+ margin-bottom: 8px;
1671
+ }
1672
+
1673
+ .disclosure-reasons {
1674
+ flex-wrap: wrap;
1675
+ }
1676
+
1677
+ .disclosure-source-ref {
1678
+ display: flex;
1679
+ flex-direction: column;
1680
+ gap: 6px;
1681
+ margin-bottom: 6px;
1682
+ }
1683
+
1684
+ .disclosure-provenance {
1685
+ display: grid;
1686
+ grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
1687
+ gap: 5px 8px;
1688
+ margin: 7px 0 9px;
1689
+ padding: 8px;
1690
+ border: 1px solid rgba(0, 240, 255, 0.12);
1691
+ border-radius: 10px;
1692
+ background: rgba(0, 240, 255, 0.035);
1693
+ }
1694
+
1695
+ .disclosure-provenance-row {
1696
+ min-width: 0;
1697
+ }
1698
+
1699
+ .disclosure-provenance-key {
1700
+ display: block;
1701
+ color: var(--text-muted);
1702
+ font-size: 9px;
1703
+ text-transform: uppercase;
1704
+ letter-spacing: 0.4px;
1705
+ margin-bottom: 2px;
1706
+ }
1707
+
1708
+ .disclosure-provenance-value {
1709
+ display: block;
1710
+ color: var(--text-secondary);
1711
+ font-size: 11px;
1712
+ overflow-wrap: anywhere;
1713
+ }
1714
+
1715
+ .disclosure-chip {
1716
+ font-size: 10px;
1717
+ color: var(--text-muted);
1718
+ border: 1px solid rgba(255, 255, 255, 0.08);
1719
+ background: rgba(255, 255, 255, 0.035);
1720
+ border-radius: 999px;
1721
+ padding: 3px 7px;
1722
+ }
1723
+
1724
+ .disclosure-layer + .disclosure-layer {
1725
+ margin-top: 14px;
1726
+ }
1727
+
1728
+ .disclosure-context-list {
1729
+ display: flex;
1730
+ flex-direction: column;
1731
+ gap: 6px;
1732
+ margin-bottom: 10px;
1733
+ }
1734
+
1735
+ .disclosure-context-item {
1736
+ align-items: flex-start;
1737
+ font-size: 12px;
1738
+ color: var(--text-secondary);
1739
+ background: rgba(255, 255, 255, 0.025);
1740
+ border-radius: 8px;
1741
+ padding: 7px;
1742
+ }
1743
+
1744
+ @media (max-width: 1100px) {
1745
+ .disclosure-layout,
1746
+ .disclosure-search-row {
1747
+ flex-direction: column;
1748
+ }
1749
+ }
1750
+
@@ -0,0 +1,5 @@
1
+ /**
2
+ * User-facing application entrypoints live here.
3
+ */
4
+
5
+ export {};
@@ -0,0 +1,244 @@
1
+ /**
2
+ * Chat API
3
+ * Endpoints for memory-aware chat using Claude CLI
4
+ */
5
+
6
+ import { Hono } from 'hono';
7
+ import { streamSSE } from 'hono/streaming';
8
+ import { spawn } from 'child_process';
9
+ import type { ChildProcess } from 'child_process';
10
+ import { getServiceFromQuery } from './utils.js';
11
+
12
+ export const chatRouter = new Hono();
13
+
14
+ interface ChatRequest {
15
+ message: string;
16
+ history?: Array<{ role: 'user' | 'assistant'; content: string }>;
17
+ }
18
+
19
+ const CLAUDE_TIMEOUT_MS = 120_000;
20
+
21
+ chatRouter.post('/', async (c) => {
22
+ let body: ChatRequest;
23
+ try {
24
+ body = await c.req.json<ChatRequest>();
25
+ } catch {
26
+ return c.json({ error: 'Invalid JSON body' }, 400);
27
+ }
28
+
29
+ if (!body.message?.trim()) {
30
+ return c.json({ error: 'Message is required' }, 400);
31
+ }
32
+
33
+ const memoryService = getServiceFromQuery(c);
34
+
35
+ try {
36
+ await memoryService.initialize();
37
+
38
+ // Retrieve relevant memories for context
39
+ let memoryContext = '';
40
+ let statsContext = '';
41
+
42
+ try {
43
+ const result = await memoryService.retrieveMemories(body.message, {
44
+ topK: 8,
45
+ minScore: 0.5
46
+ });
47
+
48
+ if (result.memories.length > 0) {
49
+ const parts: string[] = ['## Relevant Memories\n'];
50
+ for (const m of result.memories) {
51
+ const date = new Date(m.event.timestamp).toISOString().split('T')[0];
52
+ const content = m.event.content.slice(0, 500);
53
+ parts.push(`### [${m.event.eventType}] ${date} (score: ${m.score.toFixed(2)})`);
54
+ parts.push(content);
55
+ if (m.sessionContext) {
56
+ parts.push(`_Context: ${m.sessionContext}_`);
57
+ }
58
+ parts.push('');
59
+ }
60
+ memoryContext = parts.join('\n');
61
+ }
62
+ } catch {
63
+ // Continue without memory context if retrieval fails
64
+ }
65
+
66
+ try {
67
+ const stats = await memoryService.getStats();
68
+ const levels = stats.levelStats.map(l => `${l.level}: ${l.count}`).join(', ');
69
+ statsContext = [
70
+ '## Memory Stats',
71
+ `- Total events: ${stats.totalEvents}`,
72
+ `- Vector nodes: ${stats.vectorCount}`,
73
+ `- By level: ${levels}`
74
+ ].join('\n');
75
+ } catch {
76
+ // Continue without stats if it fails
77
+ }
78
+
79
+ const fullPrompt = buildPrompt(
80
+ statsContext,
81
+ memoryContext,
82
+ body.history || [],
83
+ body.message
84
+ );
85
+
86
+ // Stream response via SSE
87
+ return streamSSE(c, async (stream) => {
88
+ try {
89
+ await streamClaudeResponse(fullPrompt, stream);
90
+ } catch (err) {
91
+ await stream.writeSSE({
92
+ event: 'error',
93
+ data: JSON.stringify({ error: (err as Error).message })
94
+ });
95
+ }
96
+ });
97
+ } catch (error) {
98
+ return c.json({ error: (error as Error).message }, 500);
99
+ } finally {
100
+ await memoryService.shutdown();
101
+ }
102
+ });
103
+
104
+ function buildPrompt(
105
+ statsContext: string,
106
+ memoryContext: string,
107
+ history: Array<{ role: string; content: string }>,
108
+ currentMessage: string
109
+ ): string {
110
+ const parts: string[] = [];
111
+
112
+ parts.push('You are a helpful assistant that answers questions about the user\'s code memory data.');
113
+ parts.push('The memory system tracks coding sessions, tool usage, prompts, and responses.');
114
+ parts.push('Answer concisely based on the memory context below. If you don\'t have enough data, say so.');
115
+ parts.push('Use markdown formatting in your responses.\n');
116
+
117
+ if (statsContext) {
118
+ parts.push(statsContext);
119
+ parts.push('');
120
+ }
121
+
122
+ if (memoryContext) {
123
+ parts.push(memoryContext);
124
+ } else {
125
+ parts.push('No directly relevant memories found for this query.');
126
+ parts.push('Answer based on general knowledge or suggest the user rephrase.\n');
127
+ }
128
+
129
+ parts.push('---\n');
130
+
131
+ // Include recent history (last 10 turns)
132
+ const recentHistory = history.slice(-10);
133
+ if (recentHistory.length > 0) {
134
+ parts.push('## Conversation History\n');
135
+ for (const msg of recentHistory) {
136
+ const prefix = msg.role === 'user' ? 'User' : 'Assistant';
137
+ parts.push(`**${prefix}:** ${msg.content}\n`);
138
+ }
139
+ }
140
+
141
+ parts.push(`**User:** ${currentMessage}`);
142
+
143
+ return parts.join('\n');
144
+ }
145
+
146
+ function streamClaudeResponse(
147
+ prompt: string,
148
+ stream: { writeSSE: (msg: { event?: string; data: string }) => Promise<void> }
149
+ ): Promise<void> {
150
+ return new Promise((resolve, reject) => {
151
+ const proc: ChildProcess = spawn('claude', [
152
+ '-p',
153
+ '--output-format', 'stream-json',
154
+ '--verbose'
155
+ ], {
156
+ stdio: ['pipe', 'pipe', 'pipe'],
157
+ env: { ...process.env }
158
+ });
159
+
160
+ const timeout = setTimeout(() => {
161
+ proc.kill('SIGTERM');
162
+ reject(new Error('Chat response timed out after 2 minutes'));
163
+ }, CLAUDE_TIMEOUT_MS);
164
+
165
+ // Write prompt to stdin
166
+ proc.stdin!.write(prompt);
167
+ proc.stdin!.end();
168
+
169
+ let buffer = '';
170
+ let lastSentText = '';
171
+
172
+ proc.stdout!.on('data', async (chunk: Buffer) => {
173
+ buffer += chunk.toString();
174
+ const lines = buffer.split('\n');
175
+ buffer = lines.pop() || '';
176
+
177
+ for (const line of lines) {
178
+ if (!line.trim()) continue;
179
+ try {
180
+ const parsed = JSON.parse(line);
181
+
182
+ // Extract text from assistant messages
183
+ if (parsed.type === 'assistant' && parsed.message?.content) {
184
+ const textBlocks = parsed.message.content
185
+ .filter((b: { type: string }) => b.type === 'text')
186
+ .map((b: { text: string }) => b.text)
187
+ .join('');
188
+
189
+ if (textBlocks.length > lastSentText.length) {
190
+ const delta = textBlocks.slice(lastSentText.length);
191
+ lastSentText = textBlocks;
192
+ await stream.writeSSE({
193
+ event: 'message',
194
+ data: JSON.stringify({ content: delta })
195
+ });
196
+ }
197
+ }
198
+
199
+ // Handle completion
200
+ if (parsed.type === 'result') {
201
+ await stream.writeSSE({ event: 'done', data: '{}' });
202
+ }
203
+ } catch {
204
+ // Skip non-JSON lines
205
+ }
206
+ }
207
+ });
208
+
209
+ proc.stderr!.on('data', (chunk: Buffer) => {
210
+ if (process.env.CLAUDE_MEMORY_DEBUG) {
211
+ console.error('[chat] claude stderr:', chunk.toString());
212
+ }
213
+ });
214
+
215
+ proc.on('error', (err) => {
216
+ clearTimeout(timeout);
217
+ if ((err as NodeJS.ErrnoException).code === 'ENOENT') {
218
+ reject(new Error('Claude CLI not found. Install with: npm install -g @anthropic-ai/claude-code'));
219
+ } else {
220
+ reject(err);
221
+ }
222
+ });
223
+
224
+ proc.on('close', async (code) => {
225
+ clearTimeout(timeout);
226
+
227
+ // Flush remaining buffer
228
+ if (buffer.trim()) {
229
+ try {
230
+ const parsed = JSON.parse(buffer);
231
+ if (parsed.type === 'result') {
232
+ await stream.writeSSE({ event: 'done', data: '{}' });
233
+ }
234
+ } catch { /* ignore */ }
235
+ }
236
+
237
+ if (code !== 0 && code !== null) {
238
+ reject(new Error(`Claude CLI exited with code ${code}`));
239
+ } else {
240
+ resolve();
241
+ }
242
+ });
243
+ });
244
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Citations API
3
+ * Endpoints for citation management
4
+ */
5
+
6
+ import { Hono } from 'hono';
7
+ import { getServiceFromQuery } from './utils.js';
8
+ import { generateCitationId, parseCitationId } from '../../../core/citation-generator.js';
9
+
10
+ export const citationsRouter = new Hono();
11
+
12
+ // GET /api/citations/:id - Get citation by ID
13
+ citationsRouter.get('/:id', async (c) => {
14
+ const { id } = c.req.param();
15
+
16
+ // Support both formats: "a7Bc3x" or "mem:a7Bc3x"
17
+ const citationId = parseCitationId(id) || id;
18
+ const memoryService = getServiceFromQuery(c);
19
+
20
+ try {
21
+ await memoryService.initialize();
22
+
23
+ // Search through recent events to find the one matching this citation ID
24
+ const recentEvents = await memoryService.getRecentEvents(10000);
25
+
26
+ const event = recentEvents.find(e => {
27
+ const eventCitationId = generateCitationId(e.id);
28
+ return eventCitationId === citationId;
29
+ });
30
+
31
+ if (!event) {
32
+ return c.json({ error: 'Citation not found' }, 404);
33
+ }
34
+
35
+ return c.json({
36
+ citation: {
37
+ id: citationId,
38
+ eventId: event.id
39
+ },
40
+ event: {
41
+ id: event.id,
42
+ eventType: event.eventType,
43
+ timestamp: event.timestamp,
44
+ sessionId: event.sessionId,
45
+ content: event.content,
46
+ metadata: event.metadata
47
+ }
48
+ });
49
+ } catch (error) {
50
+ return c.json({ error: (error as Error).message }, 500);
51
+ } finally {
52
+ await memoryService.shutdown();
53
+ }
54
+ });
55
+
56
+ // GET /api/citations/:id/related - Get related citations
57
+ citationsRouter.get('/:id/related', async (c) => {
58
+ const { id } = c.req.param();
59
+ const citationId = parseCitationId(id) || id;
60
+ const memoryService = getServiceFromQuery(c);
61
+
62
+ try {
63
+ await memoryService.initialize();
64
+
65
+ const recentEvents = await memoryService.getRecentEvents(10000);
66
+
67
+ // Find the main event
68
+ const event = recentEvents.find(e => {
69
+ const eventCitationId = generateCitationId(e.id);
70
+ return eventCitationId === citationId;
71
+ });
72
+
73
+ if (!event) {
74
+ return c.json({ error: 'Citation not found' }, 404);
75
+ }
76
+
77
+ // Get surrounding events from same session
78
+ const sessionEvents = recentEvents
79
+ .filter(e => e.sessionId === event.sessionId)
80
+ .sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
81
+
82
+ const eventIndex = sessionEvents.findIndex(e => e.id === event.id);
83
+ const prev = eventIndex > 0 ? sessionEvents[eventIndex - 1] : null;
84
+ const next = eventIndex < sessionEvents.length - 1 ? sessionEvents[eventIndex + 1] : null;
85
+
86
+ return c.json({
87
+ previous: prev ? {
88
+ citationId: generateCitationId(prev.id),
89
+ eventType: prev.eventType,
90
+ timestamp: prev.timestamp,
91
+ preview: prev.content.slice(0, 100) + (prev.content.length > 100 ? '...' : '')
92
+ } : null,
93
+ next: next ? {
94
+ citationId: generateCitationId(next.id),
95
+ eventType: next.eventType,
96
+ timestamp: next.timestamp,
97
+ preview: next.content.slice(0, 100) + (next.content.length > 100 ? '...' : '')
98
+ } : null
99
+ });
100
+ } catch (error) {
101
+ return c.json({ error: (error as Error).message }, 500);
102
+ } finally {
103
+ await memoryService.shutdown();
104
+ }
105
+ });
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Events API
3
+ * Endpoints for event management
4
+ */
5
+
6
+ import { Hono } from 'hono';
7
+ import { getServiceFromQuery } from './utils.js';
8
+
9
+ export const eventsRouter = new Hono();
10
+
11
+ // GET /api/events - List events with filters
12
+ eventsRouter.get('/', async (c) => {
13
+ const sessionId = c.req.query('sessionId');
14
+ const eventType = c.req.query('type');
15
+ const level = c.req.query('level');
16
+ const sort = c.req.query('sort') || 'recent'; // recent | accessed | oldest
17
+ const q = (c.req.query('q') || '').trim().toLowerCase();
18
+ const limit = parseInt(c.req.query('limit') || '100', 10);
19
+ const offset = parseInt(c.req.query('offset') || '0', 10);
20
+ const memoryService = getServiceFromQuery(c);
21
+
22
+ try {
23
+ await memoryService.initialize();
24
+
25
+ let events: any[];
26
+
27
+ // Filter by level using the dedicated method
28
+ if (level) {
29
+ events = await memoryService.getEventsByLevel(level, { limit: limit + offset + 1000, offset: 0 });
30
+ } else {
31
+ events = await memoryService.getRecentEvents(limit + offset + 1000);
32
+ }
33
+
34
+ // Filter by session
35
+ if (sessionId) {
36
+ events = events.filter(e => e.sessionId === sessionId);
37
+ }
38
+
39
+ // Filter by type
40
+ if (eventType) {
41
+ events = events.filter(e => e.eventType === eventType);
42
+ }
43
+
44
+ // Content query filter
45
+ if (q) {
46
+ events = events.filter(e => (e.content || '').toLowerCase().includes(q));
47
+ }
48
+
49
+ // Sort
50
+ if (sort === 'accessed') {
51
+ events.sort((a: any, b: any) => {
52
+ const aTime = a.last_accessed_at || '';
53
+ const bTime = b.last_accessed_at || '';
54
+ return bTime.localeCompare(aTime);
55
+ });
56
+ } else if (sort === 'most-accessed') {
57
+ events.sort((a: any, b: any) => (b.access_count || 0) - (a.access_count || 0));
58
+ } else if (sort === 'oldest') {
59
+ events.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
60
+ }
61
+ // 'recent' is default (already sorted by timestamp DESC from the query)
62
+
63
+ // Pagination
64
+ const total = events.length;
65
+ events = events.slice(offset, offset + limit);
66
+
67
+ return c.json({
68
+ events: events.map(e => ({
69
+ id: e.id,
70
+ eventType: e.eventType,
71
+ timestamp: e.timestamp,
72
+ sessionId: e.sessionId,
73
+ preview: e.content.slice(0, 200) + (e.content.length > 200 ? '...' : ''),
74
+ contentLength: e.content.length,
75
+ metadata: e.metadata,
76
+ accessCount: (e as any).access_count || 0,
77
+ lastAccessedAt: (e as any).last_accessed_at || null
78
+ })),
79
+ total,
80
+ limit,
81
+ offset,
82
+ hasMore: offset + limit < total
83
+ });
84
+ } catch (error) {
85
+ return c.json({ error: (error as Error).message }, 500);
86
+ } finally {
87
+ await memoryService.shutdown();
88
+ }
89
+ });
90
+
91
+ // GET /api/events/:id - Get event details
92
+ eventsRouter.get('/:id', async (c) => {
93
+ const { id } = c.req.param();
94
+ const memoryService = getServiceFromQuery(c);
95
+
96
+ try {
97
+ await memoryService.initialize();
98
+
99
+ const recentEvents = await memoryService.getRecentEvents(10000);
100
+ const event = recentEvents.find(e => e.id === id);
101
+
102
+ if (!event) {
103
+ return c.json({ error: 'Event not found' }, 404);
104
+ }
105
+
106
+ // Get surrounding events for context
107
+ const sessionEvents = recentEvents
108
+ .filter(e => e.sessionId === event.sessionId)
109
+ .sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
110
+
111
+ const eventIndex = sessionEvents.findIndex(e => e.id === id);
112
+ const start = Math.max(0, eventIndex - 2);
113
+ const end = Math.min(sessionEvents.length, eventIndex + 3);
114
+ const context = sessionEvents.slice(start, end).filter(e => e.id !== id);
115
+
116
+ return c.json({
117
+ event: {
118
+ id: event.id,
119
+ eventType: event.eventType,
120
+ timestamp: event.timestamp,
121
+ sessionId: event.sessionId,
122
+ content: event.content,
123
+ metadata: event.metadata
124
+ },
125
+ context: context.map(e => ({
126
+ id: e.id,
127
+ eventType: e.eventType,
128
+ timestamp: e.timestamp,
129
+ preview: e.content.slice(0, 100) + (e.content.length > 100 ? '...' : '')
130
+ }))
131
+ });
132
+ } catch (error) {
133
+ return c.json({ error: (error as Error).message }, 500);
134
+ } finally {
135
+ await memoryService.shutdown();
136
+ }
137
+ });