claude-memory-layer 1.0.27 → 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 (329) 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 -419
  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 -157
  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 -33
  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/memory/user_prompt/uncategorized/2026-03-05.md +0 -6
  326. package/specs/optional-duckdb/context.md +0 -77
  327. package/specs/optional-duckdb/plan.md +0 -142
  328. package/specs/optional-duckdb/spec.md +0 -35
  329. package/src/ui/app.js +0 -2101
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Turns API
3
+ * Endpoints for viewing events grouped by conversation turn
4
+ *
5
+ * A "turn" groups a user_prompt with its associated tool_observations
6
+ * and the final agent_response into a single logical unit.
7
+ */
8
+
9
+ import { Hono } from 'hono';
10
+ import { getServiceFromQuery } from './utils.js';
11
+
12
+ export const turnsRouter = new Hono();
13
+
14
+ // GET /api/turns?sessionId=xxx - List turns for a session
15
+ turnsRouter.get('/', async (c) => {
16
+ const sessionId = c.req.query('sessionId');
17
+ const limit = parseInt(c.req.query('limit') || '20', 10);
18
+ const offset = parseInt(c.req.query('offset') || '0', 10);
19
+
20
+ if (!sessionId) {
21
+ return c.json({ error: 'sessionId is required' }, 400);
22
+ }
23
+
24
+ const memoryService = getServiceFromQuery(c);
25
+
26
+ try {
27
+ await memoryService.initialize();
28
+
29
+ const turns = await memoryService.getSessionTurns(sessionId, { limit, offset });
30
+ const totalTurns = await memoryService.countSessionTurns(sessionId);
31
+
32
+ return c.json({
33
+ turns: turns.map(t => ({
34
+ turnId: t.turnId,
35
+ startedAt: t.startedAt.toISOString(),
36
+ promptPreview: t.promptPreview,
37
+ eventCount: t.eventCount,
38
+ toolCount: t.toolCount,
39
+ hasResponse: t.hasResponse,
40
+ events: t.events.map(e => ({
41
+ id: e.id,
42
+ eventType: e.eventType,
43
+ timestamp: e.timestamp instanceof Date ? e.timestamp.toISOString() : e.timestamp,
44
+ preview: e.content.slice(0, 300) + (e.content.length > 300 ? '...' : ''),
45
+ contentLength: e.content.length
46
+ }))
47
+ })),
48
+ total: totalTurns,
49
+ limit,
50
+ offset,
51
+ hasMore: offset + limit < totalTurns
52
+ });
53
+ } catch (error) {
54
+ return c.json({ error: (error as Error).message }, 500);
55
+ } finally {
56
+ await memoryService.shutdown();
57
+ }
58
+ });
59
+
60
+ // GET /api/turns/:turnId - Get full turn details
61
+ turnsRouter.get('/:turnId', async (c) => {
62
+ const { turnId } = c.req.param();
63
+ const memoryService = getServiceFromQuery(c);
64
+
65
+ try {
66
+ await memoryService.initialize();
67
+
68
+ const events = await memoryService.getEventsByTurn(turnId);
69
+
70
+ if (events.length === 0) {
71
+ return c.json({ error: 'Turn not found' }, 404);
72
+ }
73
+
74
+ const promptEvent = events.find(e => e.eventType === 'user_prompt');
75
+ const toolEvents = events.filter(e => e.eventType === 'tool_observation');
76
+ const responseEvents = events.filter(e => e.eventType === 'agent_response');
77
+
78
+ return c.json({
79
+ turnId,
80
+ sessionId: events[0].sessionId,
81
+ startedAt: events[0].timestamp instanceof Date
82
+ ? events[0].timestamp.toISOString()
83
+ : events[0].timestamp,
84
+ prompt: promptEvent ? {
85
+ id: promptEvent.id,
86
+ content: promptEvent.content,
87
+ timestamp: promptEvent.timestamp instanceof Date
88
+ ? promptEvent.timestamp.toISOString()
89
+ : promptEvent.timestamp
90
+ } : null,
91
+ tools: toolEvents.map(e => {
92
+ let toolName = '';
93
+ let success = true;
94
+ try {
95
+ const parsed = JSON.parse(e.content);
96
+ toolName = parsed.toolName || '';
97
+ success = parsed.success !== false;
98
+ } catch { /* ignore */ }
99
+
100
+ return {
101
+ id: e.id,
102
+ toolName,
103
+ success,
104
+ timestamp: e.timestamp instanceof Date ? e.timestamp.toISOString() : e.timestamp,
105
+ preview: e.content.slice(0, 500) + (e.content.length > 500 ? '...' : '')
106
+ };
107
+ }),
108
+ responses: responseEvents.map(e => ({
109
+ id: e.id,
110
+ content: e.content,
111
+ timestamp: e.timestamp instanceof Date ? e.timestamp.toISOString() : e.timestamp
112
+ })),
113
+ totalEvents: events.length
114
+ });
115
+ } catch (error) {
116
+ return c.json({ error: (error as Error).message }, 500);
117
+ } finally {
118
+ await memoryService.shutdown();
119
+ }
120
+ });
121
+
122
+ // POST /api/turns/backfill - Backfill turn_ids from metadata
123
+ turnsRouter.post('/backfill', async (c) => {
124
+ const memoryService = getServiceFromQuery(c);
125
+
126
+ try {
127
+ await memoryService.initialize();
128
+ const updated = await memoryService.backfillTurnIds();
129
+
130
+ return c.json({
131
+ success: true,
132
+ updated,
133
+ message: `Backfilled turn_id for ${updated} events`
134
+ });
135
+ } catch (error) {
136
+ return c.json({
137
+ success: false,
138
+ error: (error as Error).message
139
+ }, 500);
140
+ } finally {
141
+ await memoryService.shutdown();
142
+ }
143
+ });
@@ -0,0 +1,65 @@
1
+ /**
2
+ * API Utilities
3
+ * Shared helpers for API endpoints
4
+ */
5
+
6
+ import type { Context } from 'hono';
7
+ import {
8
+ DISABLED_SHARED_STORE_CONFIG,
9
+ getReadOnlyMemoryService,
10
+ MemoryService
11
+ } from '../../../services/memory-service.js';
12
+ import { resolveProjectStoragePath } from '../../../core/registry/project-path.js';
13
+
14
+ /**
15
+ * Get the appropriate MemoryService based on the ?project= query parameter.
16
+ * - If ?project=<hash> is set (8 hex chars), resolves directly to project storage
17
+ * - If ?project=<path> is set, computes hash from path
18
+ * - Otherwise, returns the global read-only service
19
+ *
20
+ * Always creates read-only services for the dashboard API to avoid
21
+ * VectorWorker lifecycle issues with per-request services.
22
+ */
23
+ export function getServiceFromQuery(c: Context): MemoryService {
24
+ const project = c.req.query('project') || c.req.query('projectId');
25
+ if (project) {
26
+ const storagePath = resolveProjectStoragePath(project);
27
+
28
+ return new MemoryService({
29
+ storagePath,
30
+ readOnly: true,
31
+ analyticsEnabled: false,
32
+ sharedStoreConfig: DISABLED_SHARED_STORE_CONFIG
33
+ });
34
+ }
35
+ return getReadOnlyMemoryService();
36
+ }
37
+
38
+
39
+ /**
40
+ * Read-only lightweight service for API paths that only need sqlite/keyword reads.
41
+ * This avoids per-request vector/embedder/shared-store initialization for stats and
42
+ * explicit fast searches while preserving the same project query resolution rules.
43
+ */
44
+ export function getLightweightServiceFromQuery(c: Context): MemoryService {
45
+ const project = c.req.query('project') || c.req.query('projectId');
46
+ if (project) {
47
+ const storagePath = resolveProjectStoragePath(project);
48
+
49
+ return new MemoryService({
50
+ storagePath,
51
+ readOnly: true,
52
+ lightweightMode: true,
53
+ analyticsEnabled: false,
54
+ sharedStoreConfig: DISABLED_SHARED_STORE_CONFIG
55
+ });
56
+ }
57
+
58
+ return new MemoryService({
59
+ storagePath: '~/.claude-code/memory',
60
+ readOnly: true,
61
+ lightweightMode: true,
62
+ analyticsEnabled: false,
63
+ sharedStoreConfig: DISABLED_SHARED_STORE_CONFIG
64
+ });
65
+ }
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Web Viewer HTTP Server
3
+ * Provides REST API and serves static UI files
4
+ */
5
+
6
+ import { Hono } from 'hono';
7
+ import { cors } from 'hono/cors';
8
+ import { logger } from 'hono/logger';
9
+ import { serve } from '@hono/node-server';
10
+ import { serveStatic } from '@hono/node-server/serve-static';
11
+ import * as path from 'path';
12
+ import * as fs from 'fs';
13
+ import { fileURLToPath as fileUrlToPath } from 'url';
14
+
15
+ import { apiRouter } from './api/index.js';
16
+
17
+ const app = new Hono();
18
+ const moduleDir = path.dirname(fileUrlToPath(import.meta.url));
19
+
20
+ // Middleware
21
+ app.use('/*', cors());
22
+ app.use('/*', logger());
23
+
24
+ // API routes
25
+ app.route('/api', apiRouter);
26
+
27
+ // Health check
28
+ app.get('/health', (c) => c.json({ status: 'ok', timestamp: new Date().toISOString() }));
29
+
30
+ function resolveUiPath(): string {
31
+ const candidates = [
32
+ // Built server: dist/server/index.js -> dist/ui
33
+ path.resolve(moduleDir, '../ui'),
34
+ // Source/dev server: src/apps/server/index.ts -> src/apps/dashboard
35
+ path.resolve(moduleDir, '../dashboard'),
36
+ // Fallback when running from a repository root.
37
+ path.resolve(process.cwd(), 'dist/ui'),
38
+ path.resolve(process.cwd(), 'src/apps/dashboard')
39
+ ];
40
+
41
+ return candidates.find((candidate) => fs.existsSync(path.join(candidate, 'index.html'))) ?? candidates[0];
42
+ }
43
+
44
+ // Static files (UI)
45
+ const uiPath = resolveUiPath();
46
+ if (fs.existsSync(uiPath)) {
47
+ app.use('/*', serveStatic({ root: uiPath }));
48
+ }
49
+
50
+ // Fallback for SPA routing
51
+ app.get('*', (c) => {
52
+ const indexPath = path.join(uiPath, 'index.html');
53
+ if (fs.existsSync(indexPath)) {
54
+ return c.html(fs.readFileSync(indexPath, 'utf-8'));
55
+ }
56
+ return c.text('UI not built. Run "npm run build:ui" first.', 404);
57
+ });
58
+
59
+ export { app };
60
+
61
+ let serverInstance: ReturnType<typeof serve> | null = null;
62
+
63
+ /**
64
+ * Start the HTTP server
65
+ */
66
+ export function startServer(port: number = 37777): NonNullable<ReturnType<typeof serve>> {
67
+ if (serverInstance) {
68
+ return serverInstance;
69
+ }
70
+
71
+ serverInstance = serve({
72
+ fetch: app.fetch,
73
+ port,
74
+ hostname: '127.0.0.1'
75
+ });
76
+
77
+ console.log(`🧠 Code Memory viewer started at http://localhost:${port}`);
78
+
79
+ return serverInstance;
80
+ }
81
+
82
+ /**
83
+ * Stop the HTTP server
84
+ */
85
+ export function stopServer(): void {
86
+ if (serverInstance) {
87
+ serverInstance.close();
88
+ serverInstance = null;
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Check if server is running on given port
94
+ */
95
+ export async function isServerRunning(port: number = 37777): Promise<boolean> {
96
+ try {
97
+ const response = await fetch(`http://127.0.0.1:${port}/health`);
98
+ return response.ok;
99
+ } catch {
100
+ return false;
101
+ }
102
+ }
103
+
104
+ // Start server if run directly
105
+ // Check if this file is being run directly (not imported)
106
+ const isMainModule = process.argv[1]?.includes('server/index') ||
107
+ process.argv[1]?.endsWith('server.js');
108
+ if (isMainModule) {
109
+ const port = parseInt(process.env.PORT || '37777', 10);
110
+ startServer(port);
111
+ }