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,106 @@
1
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+
5
+ export interface McpServerEntry {
6
+ command: string;
7
+ args?: string[];
8
+ env?: Record<string, string>;
9
+ }
10
+
11
+ export interface ClaudeDesktopConfig {
12
+ mcpServers?: Record<string, McpServerEntry>;
13
+ [key: string]: unknown;
14
+ }
15
+
16
+ export interface InstallMcpServerOptions extends McpServerEntry {
17
+ serverName: string;
18
+ }
19
+
20
+ export function getDefaultClaudeDesktopConfigPath(
21
+ platform: NodeJS.Platform = process.platform,
22
+ env: NodeJS.ProcessEnv = process.env,
23
+ home: string = homedir()
24
+ ): string {
25
+ if (platform === 'darwin') {
26
+ return join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
27
+ }
28
+
29
+ if (platform === 'win32') {
30
+ return join(env.APPDATA ?? join(home, 'AppData', 'Roaming'), 'Claude', 'claude_desktop_config.json');
31
+ }
32
+
33
+ return join(env.XDG_CONFIG_HOME ?? join(home, '.config'), 'claude', 'claude_desktop_config.json');
34
+ }
35
+
36
+ export function readJsonConfig(configPath: string): ClaudeDesktopConfig {
37
+ if (!existsSync(configPath)) {
38
+ return {};
39
+ }
40
+
41
+ const content = readFileSync(configPath, 'utf8').trim();
42
+ if (!content) {
43
+ return {};
44
+ }
45
+
46
+ return JSON.parse(content) as ClaudeDesktopConfig;
47
+ }
48
+
49
+ export function saveJsonConfig(configPath: string, config: ClaudeDesktopConfig): void {
50
+ mkdirSync(dirname(configPath), { recursive: true });
51
+ const tempPath = `${configPath}.tmp`;
52
+ writeFileSync(tempPath, `${JSON.stringify(config, null, 2)}\n`);
53
+ renameSync(tempPath, configPath);
54
+ }
55
+
56
+ export function installMcpServerConfig(
57
+ existingConfig: ClaudeDesktopConfig,
58
+ options: InstallMcpServerOptions
59
+ ): ClaudeDesktopConfig {
60
+ const { serverName, command, args, env } = options;
61
+ const serverEntry: McpServerEntry = { command };
62
+
63
+ if (args && args.length > 0) {
64
+ serverEntry.args = args;
65
+ } else if (args) {
66
+ serverEntry.args = [];
67
+ }
68
+
69
+ if (env && Object.keys(env).length > 0) {
70
+ serverEntry.env = env;
71
+ }
72
+
73
+ return {
74
+ ...existingConfig,
75
+ mcpServers: {
76
+ ...(existingConfig.mcpServers ?? {}),
77
+ [serverName]: serverEntry
78
+ }
79
+ };
80
+ }
81
+
82
+ export interface InstallMcpServerCommandOptions {
83
+ configPath?: string;
84
+ serverName?: string;
85
+ command?: string;
86
+ args?: string[];
87
+ dryRun?: boolean;
88
+ }
89
+
90
+ export function installMcpServer(options: InstallMcpServerCommandOptions = {}): {
91
+ configPath: string;
92
+ config: ClaudeDesktopConfig;
93
+ } {
94
+ const configPath = options.configPath ?? getDefaultClaudeDesktopConfigPath();
95
+ const config = installMcpServerConfig(readJsonConfig(configPath), {
96
+ serverName: options.serverName ?? 'claude-memory-layer',
97
+ command: options.command ?? 'claude-memory-layer-mcp',
98
+ args: options.args ?? []
99
+ });
100
+
101
+ if (!options.dryRun) {
102
+ saveJsonConfig(configPath, config);
103
+ }
104
+
105
+ return { configPath, config };
106
+ }
@@ -0,0 +1,196 @@
1
+ import type {
2
+ RetrievalDisclosureExpansion,
3
+ RetrievalDisclosureSearchResponse,
4
+ RetrievalDisclosureSource
5
+ } from '../../core/engine/retrieval-disclosure-service.js';
6
+ import type { RetrievalResultEnvelope } from '../../core/model/retrieval-result.js';
7
+ import type { UnifiedRetrievalResult } from '../../core/retriever.js';
8
+
9
+ export function formatPlainSearchResults(result: UnifiedRetrievalResult): string {
10
+ const lines: string[] = [
11
+ '',
12
+ '📚 Search Results',
13
+ '',
14
+ `Confidence: ${result.matchResult.confidence}`,
15
+ `Total local memories found: ${result.memories.length}`,
16
+ `Shared memories found: ${result.sharedMemories?.length ?? 0}`,
17
+ ''
18
+ ];
19
+
20
+ for (const memory of result.memories) {
21
+ const date = memory.event.timestamp.toISOString().split('T')[0];
22
+ lines.push('---');
23
+ lines.push(`📌 ${memory.event.eventType} (${date})`);
24
+ lines.push(` Score: ${memory.score.toFixed(3)}`);
25
+ lines.push(` Session: ${memory.event.sessionId.slice(0, 8)}...`);
26
+ lines.push(` Content: ${preview(memory.event.content, 200)}`);
27
+ lines.push('');
28
+ }
29
+
30
+ if (result.sharedMemories && result.sharedMemories.length > 0) {
31
+ lines.push('🌐 Shared Memories', '');
32
+ for (const entry of result.sharedMemories) {
33
+ lines.push('---');
34
+ lines.push(`🌐 ${entry.title}`);
35
+ lines.push(` Source: shared:${entry.entryId}`);
36
+ lines.push(` Project: ${entry.sourceProjectHash}`);
37
+ lines.push(` Score: ${entry.confidence.toFixed(3)}`);
38
+ lines.push(` Topics: ${entry.topics.join(', ') || 'n/a'}`);
39
+ lines.push(` Symptoms: ${entry.symptoms.join('; ') || 'n/a'}`);
40
+ lines.push(` Root cause: ${entry.rootCause}`);
41
+ lines.push(` Solution: ${entry.solution}`);
42
+ lines.push('');
43
+ }
44
+ }
45
+
46
+ return lines.join('\n');
47
+ }
48
+
49
+ export function formatDisclosureSearch(response: RetrievalDisclosureSearchResponse): string {
50
+ const lines: string[] = [
51
+ '',
52
+ '🔎 Progressive Search Results',
53
+ '',
54
+ `Meta: total=${response.meta.total} vector=${yesNo(response.meta.usedVector)} keyword=${yesNo(response.meta.usedKeyword)} fallback=${yesNo(response.meta.fallbackApplied)}`,
55
+ ''
56
+ ];
57
+
58
+ if (response.results.length === 0) {
59
+ lines.push('No results found.', '');
60
+ return lines.join('\n');
61
+ }
62
+
63
+ response.results.forEach((result, index) => {
64
+ lines.push(formatEnvelope(result, index + 1));
65
+ });
66
+
67
+ return lines.join('\n');
68
+ }
69
+
70
+ export function formatDisclosureExpansion(expansion: RetrievalDisclosureExpansion): string {
71
+ const lines: string[] = [
72
+ '',
73
+ '🧩 Expanded Retrieval Result',
74
+ '',
75
+ 'Target',
76
+ formatEnvelope(expansion.target),
77
+ ''
78
+ ];
79
+
80
+ if (expansion.surroundingFacts && expansion.surroundingFacts.length > 0) {
81
+ lines.push('Surrounding');
82
+ expansion.surroundingFacts.forEach((item, index) => {
83
+ lines.push(formatEnvelope(item, index + 1));
84
+ });
85
+ lines.push('');
86
+ }
87
+
88
+ if (expansion.summaries && expansion.summaries.length > 0) {
89
+ lines.push('Summaries');
90
+ expansion.summaries.forEach((item, index) => {
91
+ lines.push(formatEnvelope(item, index + 1));
92
+ });
93
+ lines.push('');
94
+ }
95
+
96
+ if (expansion.relatedSources && expansion.relatedSources.length > 0) {
97
+ lines.push('Sources');
98
+ for (const source of expansion.relatedSources) {
99
+ lines.push(`- ${source.sourceRef} (${source.sourceType}) events=${source.eventIds.join(',')}`);
100
+ lines.push(...formatMetadataLines(source.metadata, ' '));
101
+ }
102
+ lines.push('');
103
+ }
104
+
105
+ if (expansion.expandedContext) {
106
+ lines.push('Expanded Context', expansion.expandedContext, '');
107
+ }
108
+
109
+ return lines.join('\n');
110
+ }
111
+
112
+ export function formatDisclosureSource(source: RetrievalDisclosureSource): string {
113
+ const lines: string[] = [
114
+ '',
115
+ '📎 Retrieval Source',
116
+ '',
117
+ `sourceRef: ${source.sourceRef}`,
118
+ `sourceType: ${source.sourceType}`,
119
+ `eventIds: ${source.eventIds.join(', ')}`,
120
+ ''
121
+ ];
122
+
123
+ if (source.rawEvents.length > 0) {
124
+ lines.push('Raw Events');
125
+ for (const event of source.rawEvents) {
126
+ const timestamp = event.timestamp instanceof Date
127
+ ? event.timestamp.toISOString()
128
+ : String(event.timestamp);
129
+ lines.push(`- ${event.id} ${timestamp}`);
130
+ lines.push(` [${event.eventType}] ${preview(event.content, 500)}`);
131
+ if (event.sessionId) lines.push(` session: ${event.sessionId}`);
132
+ if (event.canonicalKey) lines.push(` canonicalKey: ${event.canonicalKey}`);
133
+ }
134
+ lines.push('');
135
+ } else if (source.sourceType === 'shared_troubleshooting') {
136
+ lines.push('No local raw events for this shared source.', '');
137
+ }
138
+
139
+ if (source.metadata && Object.keys(source.metadata).length > 0) {
140
+ lines.push('Shared Metadata');
141
+ lines.push(...formatMetadataLines(source.metadata, ' '));
142
+ lines.push('');
143
+ }
144
+
145
+ return lines.join('\n');
146
+ }
147
+
148
+ function formatEnvelope(result: RetrievalResultEnvelope, index?: number): string {
149
+ const prefix = index ? `${index}. ` : '- ';
150
+ const title = result.title ? ` ${result.title}` : '';
151
+ const lines = [
152
+ `${prefix}[${result.resultType}]${title}`,
153
+ ` id: ${result.id}`,
154
+ ` score: ${result.score.toFixed(3)}`,
155
+ ` reasons: ${result.reasons.join(', ') || 'n/a'}`,
156
+ ` source: ${result.sourceRef || 'n/a'}`
157
+ ];
158
+
159
+ if (result.sessionId) {
160
+ lines.push(` session: ${result.sessionId.slice(0, 12)}${result.sessionId.length > 12 ? '...' : ''}`);
161
+ }
162
+
163
+ lines.push(...formatMetadataLines(result.metadata, ' ', ['sourceProjectHash', 'sourceEntryId', 'topics']));
164
+ lines.push(` snippet: ${result.snippet}`);
165
+ lines.push('');
166
+
167
+ return lines.join('\n');
168
+ }
169
+
170
+ function yesNo(value: boolean): 'yes' | 'no' {
171
+ return value ? 'yes' : 'no';
172
+ }
173
+
174
+ function preview(content: string, maxLength: number): string {
175
+ const normalized = content.replace(/\s+/g, ' ').trim();
176
+ if (normalized.length <= maxLength) return normalized;
177
+ return `${normalized.slice(0, Math.max(0, maxLength - 3))}...`;
178
+ }
179
+
180
+ function formatMetadataLines(
181
+ metadata: Record<string, unknown> | undefined,
182
+ prefix: string,
183
+ allowedKeys?: string[]
184
+ ): string[] {
185
+ if (!metadata) return [];
186
+ return Object.entries(metadata)
187
+ .filter(([key, value]) => value !== undefined && (!allowedKeys || allowedKeys.includes(key)))
188
+ .map(([key, value]) => `${prefix}${key}: ${formatMetadataValue(value)}`);
189
+ }
190
+
191
+ function formatMetadataValue(value: unknown): string {
192
+ if (Array.isArray(value)) return value.join(', ');
193
+ if (value instanceof Date) return value.toISOString();
194
+ if (value && typeof value === 'object') return JSON.stringify(value);
195
+ return String(value);
196
+ }
@@ -0,0 +1,244 @@
1
+ // --- Initialization ---
2
+
3
+ document.addEventListener('DOMContentLoaded', () => {
4
+ initDashboard();
5
+ });
6
+
7
+ async function initDashboard() {
8
+ await loadProjects();
9
+ await refreshData();
10
+ setupEventListeners();
11
+ await initActivityChart();
12
+ }
13
+
14
+ async function loadProjects() {
15
+ try {
16
+ const res = await fetch(`${API_BASE}/projects`);
17
+ const data = await res.json();
18
+ state.projects = data.projects || [];
19
+
20
+ const select = document.getElementById('project-select');
21
+ if (!select) return;
22
+
23
+ // Clear existing options except first
24
+ while (select.options.length > 1) select.remove(1);
25
+
26
+ // Add project options
27
+ state.projects.forEach(p => {
28
+ const option = document.createElement('option');
29
+ option.value = p.hash;
30
+ option.textContent = `${p.projectName} (${p.dbSizeHuman})`;
31
+ select.appendChild(option);
32
+ });
33
+ } catch (error) {
34
+ console.error('Failed to load projects:', error);
35
+ }
36
+ }
37
+
38
+ function setupEventListeners() {
39
+ // Pipeline steps
40
+ document.querySelectorAll('.p-step').forEach(step => {
41
+ step.addEventListener('click', (e) => {
42
+ const level = e.currentTarget.dataset.level;
43
+ if (level) selectLevel(level);
44
+ });
45
+ });
46
+
47
+ // Sort buttons
48
+ document.querySelectorAll('.sort-btn[data-sort]').forEach(btn => {
49
+ btn.addEventListener('click', (e) => {
50
+ const sort = e.currentTarget.dataset.sort;
51
+ if (sort) selectSort(sort);
52
+ });
53
+ });
54
+
55
+ // Adherence window controls
56
+ document.querySelectorAll('#adherence-window-controls .sort-btn').forEach(btn => {
57
+ btn.addEventListener('click', async (e) => {
58
+ const window = e.currentTarget.dataset.adhWindow;
59
+ if (!window || state.adherenceWindow === window) return;
60
+ state.adherenceWindow = window;
61
+ document.querySelectorAll('#adherence-window-controls .sort-btn').forEach(b => {
62
+ b.classList.toggle('active', b.dataset.adhWindow === window);
63
+ });
64
+ state.adherenceSummary = await fetchAdherenceSummary().catch(() => null);
65
+ updateAdherenceSummaryUI();
66
+ });
67
+ });
68
+
69
+ // KPI window controls
70
+ document.querySelectorAll('.sort-btn[data-kpi-window]').forEach(btn => {
71
+ btn.addEventListener('click', async (e) => {
72
+ const window = e.currentTarget.dataset.kpiWindow;
73
+ if (!window || state.kpiWindow === window) return;
74
+ state.kpiWindow = window;
75
+ document.querySelectorAll('.sort-btn[data-kpi-window]').forEach(b => {
76
+ b.classList.toggle('active', b.dataset.kpiWindow === window);
77
+ });
78
+ await loadKpiData();
79
+ updateKpiCardsUI();
80
+ renderKpiTrendChart();
81
+ });
82
+ });
83
+
84
+ // Search
85
+ const searchInput = document.getElementById('search-input');
86
+ if (searchInput) {
87
+ searchInput.addEventListener('input', debounce((e) => handleSearch(e.target.value), 300));
88
+ }
89
+
90
+ // User prompt search
91
+ const userPromptSearch = document.getElementById('user-prompt-search');
92
+ if (userPromptSearch) {
93
+ userPromptSearch.addEventListener('input', debounce(async (e) => {
94
+ state.userPromptSearchQuery = e.target.value || '';
95
+ state.userPromptPage = 1;
96
+ await loadUserPromptsView();
97
+ }, 250));
98
+ }
99
+ const userPromptRefresh = document.getElementById('user-prompt-refresh');
100
+ if (userPromptRefresh) {
101
+ userPromptRefresh.addEventListener('click', async () => {
102
+ await loadUserPromptsView();
103
+ });
104
+ }
105
+ const userPromptPrev = document.getElementById('user-prompt-prev');
106
+ if (userPromptPrev) {
107
+ userPromptPrev.addEventListener('click', async () => {
108
+ if (state.userPromptPage <= 1) return;
109
+ state.userPromptPage -= 1;
110
+ await renderUserPromptList();
111
+ });
112
+ }
113
+ const userPromptNext = document.getElementById('user-prompt-next');
114
+ if (userPromptNext) {
115
+ userPromptNext.addEventListener('click', async () => {
116
+ const totalPages = Math.max(1, Math.ceil((state.userPromptItems?.length || 0) / state.userPromptPageSize));
117
+ if (state.userPromptPage >= totalPages) return;
118
+ state.userPromptPage += 1;
119
+ await renderUserPromptList();
120
+ });
121
+ }
122
+
123
+ // Project selector
124
+ const projectSelect = document.getElementById('project-select');
125
+ if (projectSelect) {
126
+ projectSelect.addEventListener('change', async (e) => {
127
+ state.currentProject = e.target.value;
128
+ await refreshData();
129
+ if (state.chartInstance) {
130
+ state.chartInstance.destroy();
131
+ state.chartInstance = null;
132
+ }
133
+ if (state.kpiChartInstance) {
134
+ state.kpiChartInstance.destroy();
135
+ state.kpiChartInstance = null;
136
+ }
137
+ await initActivityChart();
138
+ // Reload current view if not overview
139
+ if (state.currentView !== 'overview') {
140
+ switchView(state.currentView);
141
+ }
142
+ updateChatProjectScope();
143
+ });
144
+ }
145
+
146
+ // Refresh
147
+ const refreshBtn = document.getElementById('refresh-btn');
148
+ if (refreshBtn) {
149
+ refreshBtn.addEventListener('click', refreshData);
150
+ }
151
+
152
+ // Stat cards
153
+ document.querySelectorAll('.stat-card[data-stat]').forEach(card => {
154
+ card.addEventListener('click', () => {
155
+ handleStatClick(card.dataset.stat);
156
+ });
157
+ });
158
+
159
+ // Sidebar navigation
160
+ document.querySelectorAll('.nav-item[data-nav]').forEach(item => {
161
+ item.addEventListener('click', () => {
162
+ switchView(item.dataset.nav);
163
+ });
164
+ });
165
+
166
+ // Modal close buttons
167
+ document.querySelectorAll('.modal-close-btn').forEach(btn => {
168
+ btn.addEventListener('click', () => {
169
+ const modalId = btn.dataset.modal;
170
+ closeModal(modalId);
171
+ });
172
+ });
173
+
174
+ // Modal overlay click to close
175
+ document.querySelectorAll('.modal-overlay').forEach(overlay => {
176
+ overlay.addEventListener('click', (e) => {
177
+ if (e.target === overlay) {
178
+ closeModal(overlay.id);
179
+ }
180
+ });
181
+ });
182
+
183
+ // ESC key to close modals
184
+ document.addEventListener('keydown', (e) => {
185
+ if (e.key === 'Escape') {
186
+ if (state.isChatOpen) {
187
+ closeChatPanel();
188
+ } else {
189
+ closeAllModals();
190
+ }
191
+ }
192
+ });
193
+
194
+ // Chat panel
195
+ const chatToggle = document.getElementById('chat-toggle-btn');
196
+ if (chatToggle) {
197
+ chatToggle.addEventListener('click', toggleChatPanel);
198
+ }
199
+ const chatClose = document.getElementById('chat-close-btn');
200
+ if (chatClose) {
201
+ chatClose.addEventListener('click', () => closeChatPanel());
202
+ }
203
+
204
+ const chatInput = document.getElementById('chat-input');
205
+ const chatSendBtn = document.getElementById('chat-send-btn');
206
+ if (chatInput) {
207
+ chatInput.addEventListener('input', () => {
208
+ chatInput.style.height = 'auto';
209
+ chatInput.style.height = Math.min(chatInput.scrollHeight, 120) + 'px';
210
+ chatSendBtn.disabled = !chatInput.value.trim() || state.isChatStreaming;
211
+ });
212
+ chatInput.addEventListener('keydown', (e) => {
213
+ if (e.key === 'Enter' && !e.shiftKey) {
214
+ e.preventDefault();
215
+ if (chatInput.value.trim() && !state.isChatStreaming) {
216
+ sendChatMessage();
217
+ }
218
+ }
219
+ });
220
+ }
221
+ if (chatSendBtn) {
222
+ chatSendBtn.addEventListener('click', () => {
223
+ if (!state.isChatStreaming) sendChatMessage();
224
+ });
225
+ }
226
+
227
+ // Chat tabs
228
+ document.querySelectorAll('.chat-header-tab').forEach(tab => {
229
+ tab.addEventListener('click', () => {
230
+ switchChatTab(tab.dataset.chatTab);
231
+ });
232
+ });
233
+
234
+ // New conversation button
235
+ const chatNewBtn = document.getElementById('chat-new-btn');
236
+ if (chatNewBtn) {
237
+ chatNewBtn.addEventListener('click', startNewConversation);
238
+ }
239
+
240
+ setupDisclosureSearchListeners();
241
+ }
242
+
243
+ // --- Data Fetching ---
244
+