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,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
+ }