@astragenie/astramemory-local 0.7.2

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 (493) hide show
  1. package/CHANGELOG.md +341 -0
  2. package/README.md +419 -0
  3. package/dist/backup/retention.d.ts +15 -0
  4. package/dist/backup/retention.js +62 -0
  5. package/dist/backup/retention.js.map +1 -0
  6. package/dist/backup/snapshot.d.ts +21 -0
  7. package/dist/backup/snapshot.js +55 -0
  8. package/dist/backup/snapshot.js.map +1 -0
  9. package/dist/backup/verify.d.ts +23 -0
  10. package/dist/backup/verify.js +77 -0
  11. package/dist/backup/verify.js.map +1 -0
  12. package/dist/budget/tracker.d.ts +58 -0
  13. package/dist/budget/tracker.js +102 -0
  14. package/dist/budget/tracker.js.map +1 -0
  15. package/dist/capture/codex.d.ts +63 -0
  16. package/dist/capture/codex.js +0 -0
  17. package/dist/capture/codex.js.map +1 -0
  18. package/dist/cli/backup.d.ts +1 -0
  19. package/dist/cli/backup.js +112 -0
  20. package/dist/cli/backup.js.map +1 -0
  21. package/dist/cli/budget.d.ts +7 -0
  22. package/dist/cli/budget.js +44 -0
  23. package/dist/cli/budget.js.map +1 -0
  24. package/dist/cli/capture.d.ts +10 -0
  25. package/dist/cli/capture.js +113 -0
  26. package/dist/cli/capture.js.map +1 -0
  27. package/dist/cli/consolidate.d.ts +16 -0
  28. package/dist/cli/consolidate.js +146 -0
  29. package/dist/cli/consolidate.js.map +1 -0
  30. package/dist/cli/doctor.d.ts +1 -0
  31. package/dist/cli/doctor.js +54 -0
  32. package/dist/cli/doctor.js.map +1 -0
  33. package/dist/cli/entity-backfill.d.ts +10 -0
  34. package/dist/cli/entity-backfill.js +46 -0
  35. package/dist/cli/entity-backfill.js.map +1 -0
  36. package/dist/cli/hook-install.d.ts +45 -0
  37. package/dist/cli/hook-install.js +77 -0
  38. package/dist/cli/hook-install.js.map +1 -0
  39. package/dist/cli/index.d.ts +2 -0
  40. package/dist/cli/index.js +312 -0
  41. package/dist/cli/index.js.map +1 -0
  42. package/dist/cli/init.d.ts +16 -0
  43. package/dist/cli/init.js +431 -0
  44. package/dist/cli/init.js.map +1 -0
  45. package/dist/cli/mcp-stdio.d.ts +18 -0
  46. package/dist/cli/mcp-stdio.js +67 -0
  47. package/dist/cli/mcp-stdio.js.map +1 -0
  48. package/dist/cli/memory.d.ts +15 -0
  49. package/dist/cli/memory.js +52 -0
  50. package/dist/cli/memory.js.map +1 -0
  51. package/dist/cli/open-runtime-db.d.ts +15 -0
  52. package/dist/cli/open-runtime-db.js +37 -0
  53. package/dist/cli/open-runtime-db.js.map +1 -0
  54. package/dist/cli/pair.d.ts +29 -0
  55. package/dist/cli/pair.js +64 -0
  56. package/dist/cli/pair.js.map +1 -0
  57. package/dist/cli/providers.d.ts +10 -0
  58. package/dist/cli/providers.js +97 -0
  59. package/dist/cli/providers.js.map +1 -0
  60. package/dist/cli/queue-purge.d.ts +5 -0
  61. package/dist/cli/queue-purge.js +92 -0
  62. package/dist/cli/queue-purge.js.map +1 -0
  63. package/dist/cli/queue.d.ts +29 -0
  64. package/dist/cli/queue.js +73 -0
  65. package/dist/cli/queue.js.map +1 -0
  66. package/dist/cli/rebuild.d.ts +15 -0
  67. package/dist/cli/rebuild.js +70 -0
  68. package/dist/cli/rebuild.js.map +1 -0
  69. package/dist/cli/reembed-dim.d.ts +21 -0
  70. package/dist/cli/reembed-dim.js +199 -0
  71. package/dist/cli/reembed-dim.js.map +1 -0
  72. package/dist/cli/reinstall.d.ts +1 -0
  73. package/dist/cli/reinstall.js +205 -0
  74. package/dist/cli/reinstall.js.map +1 -0
  75. package/dist/cli/restore.d.ts +1 -0
  76. package/dist/cli/restore.js +167 -0
  77. package/dist/cli/restore.js.map +1 -0
  78. package/dist/cli/retag.d.ts +14 -0
  79. package/dist/cli/retag.js +62 -0
  80. package/dist/cli/retag.js.map +1 -0
  81. package/dist/cli/search.d.ts +66 -0
  82. package/dist/cli/search.js +174 -0
  83. package/dist/cli/search.js.map +1 -0
  84. package/dist/cli/serve.d.ts +9 -0
  85. package/dist/cli/serve.js +364 -0
  86. package/dist/cli/serve.js.map +1 -0
  87. package/dist/cli/service.d.ts +1 -0
  88. package/dist/cli/service.js +121 -0
  89. package/dist/cli/service.js.map +1 -0
  90. package/dist/cli/sync.d.ts +15 -0
  91. package/dist/cli/sync.js +61 -0
  92. package/dist/cli/sync.js.map +1 -0
  93. package/dist/cli/token.d.ts +24 -0
  94. package/dist/cli/token.js +77 -0
  95. package/dist/cli/token.js.map +1 -0
  96. package/dist/cli/wait-health.d.ts +4 -0
  97. package/dist/cli/wait-health.js +23 -0
  98. package/dist/cli/wait-health.js.map +1 -0
  99. package/dist/config/config.d.ts +127 -0
  100. package/dist/config/config.js +38 -0
  101. package/dist/config/config.js.map +1 -0
  102. package/dist/config/datadir.d.ts +30 -0
  103. package/dist/config/datadir.js +65 -0
  104. package/dist/config/datadir.js.map +1 -0
  105. package/dist/config/loader.d.ts +23 -0
  106. package/dist/config/loader.js +102 -0
  107. package/dist/config/loader.js.map +1 -0
  108. package/dist/config/migrate-dirs.d.ts +36 -0
  109. package/dist/config/migrate-dirs.js +132 -0
  110. package/dist/config/migrate-dirs.js.map +1 -0
  111. package/dist/config/persist-envs.d.ts +23 -0
  112. package/dist/config/persist-envs.js +119 -0
  113. package/dist/config/persist-envs.js.map +1 -0
  114. package/dist/config/resolve-runtime.d.ts +19 -0
  115. package/dist/config/resolve-runtime.js +53 -0
  116. package/dist/config/resolve-runtime.js.map +1 -0
  117. package/dist/config/secrets.d.ts +28 -0
  118. package/dist/config/secrets.js +38 -0
  119. package/dist/config/secrets.js.map +1 -0
  120. package/dist/config/sync-settings.d.ts +16 -0
  121. package/dist/config/sync-settings.js +34 -0
  122. package/dist/config/sync-settings.js.map +1 -0
  123. package/dist/config/writer.d.ts +19 -0
  124. package/dist/config/writer.js +121 -0
  125. package/dist/config/writer.js.map +1 -0
  126. package/dist/consolidate/consolidate.d.ts +80 -0
  127. package/dist/consolidate/consolidate.js +0 -0
  128. package/dist/consolidate/consolidate.js.map +1 -0
  129. package/dist/consolidate/proposals.d.ts +35 -0
  130. package/dist/consolidate/proposals.js +66 -0
  131. package/dist/consolidate/proposals.js.map +1 -0
  132. package/dist/contracts/atom-wire.d.ts +48 -0
  133. package/dist/contracts/atom-wire.js +55 -0
  134. package/dist/contracts/atom-wire.js.map +1 -0
  135. package/dist/contracts/embed.d.ts +41 -0
  136. package/dist/contracts/embed.js +20 -0
  137. package/dist/contracts/embed.js.map +1 -0
  138. package/dist/contracts/index.d.ts +5 -0
  139. package/dist/contracts/index.js +6 -0
  140. package/dist/contracts/index.js.map +1 -0
  141. package/dist/contracts/job.d.ts +113 -0
  142. package/dist/contracts/job.js +32 -0
  143. package/dist/contracts/job.js.map +1 -0
  144. package/dist/contracts/llm.d.ts +30 -0
  145. package/dist/contracts/llm.js +2 -0
  146. package/dist/contracts/llm.js.map +1 -0
  147. package/dist/contracts/memory.d.ts +47 -0
  148. package/dist/contracts/memory.js +5 -0
  149. package/dist/contracts/memory.js.map +1 -0
  150. package/dist/contracts/vector.d.ts +29 -0
  151. package/dist/contracts/vector.js +2 -0
  152. package/dist/contracts/vector.js.map +1 -0
  153. package/dist/distill/flatten-turns.d.ts +1 -0
  154. package/dist/distill/flatten-turns.js +50 -0
  155. package/dist/distill/flatten-turns.js.map +1 -0
  156. package/dist/distill/pipeline.d.ts +45 -0
  157. package/dist/distill/pipeline.js +113 -0
  158. package/dist/distill/pipeline.js.map +1 -0
  159. package/dist/distill/prompts/extract.d.ts +122 -0
  160. package/dist/distill/prompts/extract.js +67 -0
  161. package/dist/distill/prompts/extract.js.map +1 -0
  162. package/dist/distill/stages/01-cleanup.d.ts +9 -0
  163. package/dist/distill/stages/01-cleanup.js +67 -0
  164. package/dist/distill/stages/01-cleanup.js.map +1 -0
  165. package/dist/distill/stages/02-normalize.d.ts +9 -0
  166. package/dist/distill/stages/02-normalize.js +76 -0
  167. package/dist/distill/stages/02-normalize.js.map +1 -0
  168. package/dist/distill/stages/03-chunk.d.ts +22 -0
  169. package/dist/distill/stages/03-chunk.js +138 -0
  170. package/dist/distill/stages/03-chunk.js.map +1 -0
  171. package/dist/distill/stages/04-compact.d.ts +28 -0
  172. package/dist/distill/stages/04-compact.js +69 -0
  173. package/dist/distill/stages/04-compact.js.map +1 -0
  174. package/dist/distill/stages/05-extract.d.ts +35 -0
  175. package/dist/distill/stages/05-extract.js +101 -0
  176. package/dist/distill/stages/05-extract.js.map +1 -0
  177. package/dist/distill/stages/06-reduce.d.ts +16 -0
  178. package/dist/distill/stages/06-reduce.js +30 -0
  179. package/dist/distill/stages/06-reduce.js.map +1 -0
  180. package/dist/distill/stages/07-memory-normalize.d.ts +27 -0
  181. package/dist/distill/stages/07-memory-normalize.js +65 -0
  182. package/dist/distill/stages/07-memory-normalize.js.map +1 -0
  183. package/dist/distill/stages/08-embed-index.d.ts +31 -0
  184. package/dist/distill/stages/08-embed-index.js +82 -0
  185. package/dist/distill/stages/08-embed-index.js.map +1 -0
  186. package/dist/doctor/checks.d.ts +77 -0
  187. package/dist/doctor/checks.js +626 -0
  188. package/dist/doctor/checks.js.map +1 -0
  189. package/dist/doctor/hardening-checks.d.ts +9 -0
  190. package/dist/doctor/hardening-checks.js +182 -0
  191. package/dist/doctor/hardening-checks.js.map +1 -0
  192. package/dist/doctor/probes/embed-probe.d.ts +19 -0
  193. package/dist/doctor/probes/embed-probe.js +47 -0
  194. package/dist/doctor/probes/embed-probe.js.map +1 -0
  195. package/dist/doctor/probes/llm-chat-probe.d.ts +11 -0
  196. package/dist/doctor/probes/llm-chat-probe.js +41 -0
  197. package/dist/doctor/probes/llm-chat-probe.js.map +1 -0
  198. package/dist/doctor/probes/plugin-coexistence.d.ts +14 -0
  199. package/dist/doctor/probes/plugin-coexistence.js +60 -0
  200. package/dist/doctor/probes/plugin-coexistence.js.map +1 -0
  201. package/dist/doctor/runner.d.ts +17 -0
  202. package/dist/doctor/runner.js +53 -0
  203. package/dist/doctor/runner.js.map +1 -0
  204. package/dist/doctor/types.d.ts +12 -0
  205. package/dist/doctor/types.js +2 -0
  206. package/dist/doctor/types.js.map +1 -0
  207. package/dist/entity/backfill.d.ts +30 -0
  208. package/dist/entity/backfill.js +55 -0
  209. package/dist/entity/backfill.js.map +1 -0
  210. package/dist/entity/extract-entities.d.ts +27 -0
  211. package/dist/entity/extract-entities.js +86 -0
  212. package/dist/entity/extract-entities.js.map +1 -0
  213. package/dist/entity/normalize.d.ts +17 -0
  214. package/dist/entity/normalize.js +20 -0
  215. package/dist/entity/normalize.js.map +1 -0
  216. package/dist/eval/harness.d.ts +96 -0
  217. package/dist/eval/harness.js +119 -0
  218. package/dist/eval/harness.js.map +1 -0
  219. package/dist/eval/metrics.d.ts +23 -0
  220. package/dist/eval/metrics.js +44 -0
  221. package/dist/eval/metrics.js.map +1 -0
  222. package/dist/log/correlation.d.ts +24 -0
  223. package/dist/log/correlation.js +33 -0
  224. package/dist/log/correlation.js.map +1 -0
  225. package/dist/log/logger.d.ts +38 -0
  226. package/dist/log/logger.js +129 -0
  227. package/dist/log/logger.js.map +1 -0
  228. package/dist/log/scrub.d.ts +33 -0
  229. package/dist/log/scrub.js +91 -0
  230. package/dist/log/scrub.js.map +1 -0
  231. package/dist/mcp/server.d.ts +36 -0
  232. package/dist/mcp/server.js +553 -0
  233. package/dist/mcp/server.js.map +1 -0
  234. package/dist/memory-tool/adapter.d.ts +73 -0
  235. package/dist/memory-tool/adapter.js +269 -0
  236. package/dist/memory-tool/adapter.js.map +1 -0
  237. package/dist/pipeline/errors.d.ts +21 -0
  238. package/dist/pipeline/errors.js +34 -0
  239. package/dist/pipeline/errors.js.map +1 -0
  240. package/dist/pipeline/failure-classifier.d.ts +13 -0
  241. package/dist/pipeline/failure-classifier.js +72 -0
  242. package/dist/pipeline/failure-classifier.js.map +1 -0
  243. package/dist/pipeline/handler-ctx-ext.d.ts +23 -0
  244. package/dist/pipeline/handler-ctx-ext.js +19 -0
  245. package/dist/pipeline/handler-ctx-ext.js.map +1 -0
  246. package/dist/pipeline/handler.d.ts +20 -0
  247. package/dist/pipeline/handler.js +2 -0
  248. package/dist/pipeline/handler.js.map +1 -0
  249. package/dist/pipeline/handlers/cleanup.d.ts +14 -0
  250. package/dist/pipeline/handlers/cleanup.js +47 -0
  251. package/dist/pipeline/handlers/cleanup.js.map +1 -0
  252. package/dist/pipeline/handlers/consolidate.d.ts +8 -0
  253. package/dist/pipeline/handlers/consolidate.js +23 -0
  254. package/dist/pipeline/handlers/consolidate.js.map +1 -0
  255. package/dist/pipeline/handlers/distill-events.d.ts +15 -0
  256. package/dist/pipeline/handlers/distill-events.js +134 -0
  257. package/dist/pipeline/handlers/distill-events.js.map +1 -0
  258. package/dist/pipeline/handlers/distill.d.ts +17 -0
  259. package/dist/pipeline/handlers/distill.js +110 -0
  260. package/dist/pipeline/handlers/distill.js.map +1 -0
  261. package/dist/pipeline/handlers/reembed.d.ts +10 -0
  262. package/dist/pipeline/handlers/reembed.js +34 -0
  263. package/dist/pipeline/handlers/reembed.js.map +1 -0
  264. package/dist/pipeline/job-repo.d.ts +86 -0
  265. package/dist/pipeline/job-repo.js +168 -0
  266. package/dist/pipeline/job-repo.js.map +1 -0
  267. package/dist/pipeline/mock-providers.d.ts +49 -0
  268. package/dist/pipeline/mock-providers.js +175 -0
  269. package/dist/pipeline/mock-providers.js.map +1 -0
  270. package/dist/pipeline/registry.d.ts +15 -0
  271. package/dist/pipeline/registry.js +20 -0
  272. package/dist/pipeline/registry.js.map +1 -0
  273. package/dist/pipeline/worker.d.ts +41 -0
  274. package/dist/pipeline/worker.js +167 -0
  275. package/dist/pipeline/worker.js.map +1 -0
  276. package/dist/providers/embed/azure-openai.d.ts +25 -0
  277. package/dist/providers/embed/azure-openai.js +138 -0
  278. package/dist/providers/embed/azure-openai.js.map +1 -0
  279. package/dist/providers/embed/ollama.d.ts +17 -0
  280. package/dist/providers/embed/ollama.js +106 -0
  281. package/dist/providers/embed/ollama.js.map +1 -0
  282. package/dist/providers/index.d.ts +19 -0
  283. package/dist/providers/index.js +72 -0
  284. package/dist/providers/index.js.map +1 -0
  285. package/dist/providers/llm/azure-openai.d.ts +20 -0
  286. package/dist/providers/llm/azure-openai.js +135 -0
  287. package/dist/providers/llm/azure-openai.js.map +1 -0
  288. package/dist/providers/llm/ollama.d.ts +13 -0
  289. package/dist/providers/llm/ollama.js +113 -0
  290. package/dist/providers/llm/ollama.js.map +1 -0
  291. package/dist/providers/llm/pricing.d.ts +21 -0
  292. package/dist/providers/llm/pricing.js +22 -0
  293. package/dist/providers/llm/pricing.js.map +1 -0
  294. package/dist/recall/pack.d.ts +32 -0
  295. package/dist/recall/pack.js +90 -0
  296. package/dist/recall/pack.js.map +1 -0
  297. package/dist/recall/policy.d.ts +39 -0
  298. package/dist/recall/policy.js +96 -0
  299. package/dist/recall/policy.js.map +1 -0
  300. package/dist/redact/detectors.d.ts +20 -0
  301. package/dist/redact/detectors.js +85 -0
  302. package/dist/redact/detectors.js.map +1 -0
  303. package/dist/redact/entropy.d.ts +24 -0
  304. package/dist/redact/entropy.js +77 -0
  305. package/dist/redact/entropy.js.map +1 -0
  306. package/dist/redact/index.d.ts +47 -0
  307. package/dist/redact/index.js +165 -0
  308. package/dist/redact/index.js.map +1 -0
  309. package/dist/search/fuse.d.ts +108 -0
  310. package/dist/search/fuse.js +135 -0
  311. package/dist/search/fuse.js.map +1 -0
  312. package/dist/search/query.d.ts +28 -0
  313. package/dist/search/query.js +70 -0
  314. package/dist/search/query.js.map +1 -0
  315. package/dist/search/search.d.ts +164 -0
  316. package/dist/search/search.js +310 -0
  317. package/dist/search/search.js.map +1 -0
  318. package/dist/server/app.d.ts +17 -0
  319. package/dist/server/app.js +133 -0
  320. package/dist/server/app.js.map +1 -0
  321. package/dist/server/health-state.d.ts +29 -0
  322. package/dist/server/health-state.js +28 -0
  323. package/dist/server/health-state.js.map +1 -0
  324. package/dist/server/lib/network.d.ts +12 -0
  325. package/dist/server/lib/network.js +16 -0
  326. package/dist/server/lib/network.js.map +1 -0
  327. package/dist/server/lib/score-contract.d.ts +36 -0
  328. package/dist/server/lib/score-contract.js +54 -0
  329. package/dist/server/lib/score-contract.js.map +1 -0
  330. package/dist/server/lib/stable-stringify.d.ts +10 -0
  331. package/dist/server/lib/stable-stringify.js +27 -0
  332. package/dist/server/lib/stable-stringify.js.map +1 -0
  333. package/dist/server/lib/wire-meta.d.ts +7 -0
  334. package/dist/server/lib/wire-meta.js +29 -0
  335. package/dist/server/lib/wire-meta.js.map +1 -0
  336. package/dist/server/queries/dashboard.d.ts +142 -0
  337. package/dist/server/queries/dashboard.js +166 -0
  338. package/dist/server/queries/dashboard.js.map +1 -0
  339. package/dist/server/routes/consolidation.d.ts +14 -0
  340. package/dist/server/routes/consolidation.js +67 -0
  341. package/dist/server/routes/consolidation.js.map +1 -0
  342. package/dist/server/routes/dashboard-api-html.d.ts +15 -0
  343. package/dist/server/routes/dashboard-api-html.js +144 -0
  344. package/dist/server/routes/dashboard-api-html.js.map +1 -0
  345. package/dist/server/routes/dashboard-consolidation-html.d.ts +26 -0
  346. package/dist/server/routes/dashboard-consolidation-html.js +202 -0
  347. package/dist/server/routes/dashboard-consolidation-html.js.map +1 -0
  348. package/dist/server/routes/dashboard-html.d.ts +15 -0
  349. package/dist/server/routes/dashboard-html.js +365 -0
  350. package/dist/server/routes/dashboard-html.js.map +1 -0
  351. package/dist/server/routes/dashboard-jobs-html.d.ts +18 -0
  352. package/dist/server/routes/dashboard-jobs-html.js +186 -0
  353. package/dist/server/routes/dashboard-jobs-html.js.map +1 -0
  354. package/dist/server/routes/dashboard-search-html.d.ts +18 -0
  355. package/dist/server/routes/dashboard-search-html.js +189 -0
  356. package/dist/server/routes/dashboard-search-html.js.map +1 -0
  357. package/dist/server/routes/dashboard.d.ts +19 -0
  358. package/dist/server/routes/dashboard.js +68 -0
  359. package/dist/server/routes/dashboard.js.map +1 -0
  360. package/dist/server/routes/digest.d.ts +9 -0
  361. package/dist/server/routes/digest.js +37 -0
  362. package/dist/server/routes/digest.js.map +1 -0
  363. package/dist/server/routes/entities.d.ts +12 -0
  364. package/dist/server/routes/entities.js +46 -0
  365. package/dist/server/routes/entities.js.map +1 -0
  366. package/dist/server/routes/health.d.ts +14 -0
  367. package/dist/server/routes/health.js +100 -0
  368. package/dist/server/routes/health.js.map +1 -0
  369. package/dist/server/routes/ingest.d.ts +209 -0
  370. package/dist/server/routes/ingest.js +454 -0
  371. package/dist/server/routes/ingest.js.map +1 -0
  372. package/dist/server/routes/lifecycle.d.ts +21 -0
  373. package/dist/server/routes/lifecycle.js +132 -0
  374. package/dist/server/routes/lifecycle.js.map +1 -0
  375. package/dist/server/routes/mcp.d.ts +15 -0
  376. package/dist/server/routes/mcp.js +36 -0
  377. package/dist/server/routes/mcp.js.map +1 -0
  378. package/dist/server/routes/memory-tool.d.ts +14 -0
  379. package/dist/server/routes/memory-tool.js +28 -0
  380. package/dist/server/routes/memory-tool.js.map +1 -0
  381. package/dist/server/routes/memory.d.ts +7 -0
  382. package/dist/server/routes/memory.js +19 -0
  383. package/dist/server/routes/memory.js.map +1 -0
  384. package/dist/server/routes/recall.d.ts +15 -0
  385. package/dist/server/routes/recall.js +74 -0
  386. package/dist/server/routes/recall.js.map +1 -0
  387. package/dist/server/routes/search.d.ts +12 -0
  388. package/dist/server/routes/search.js +203 -0
  389. package/dist/server/routes/search.js.map +1 -0
  390. package/dist/server/routes/version.d.ts +2 -0
  391. package/dist/server/routes/version.js +11 -0
  392. package/dist/server/routes/version.js.map +1 -0
  393. package/dist/server/routes/why.d.ts +9 -0
  394. package/dist/server/routes/why.js +38 -0
  395. package/dist/server/routes/why.js.map +1 -0
  396. package/dist/service/index.d.ts +10 -0
  397. package/dist/service/index.js +25 -0
  398. package/dist/service/index.js.map +1 -0
  399. package/dist/service/install-flow.d.ts +18 -0
  400. package/dist/service/install-flow.js +47 -0
  401. package/dist/service/install-flow.js.map +1 -0
  402. package/dist/service/instance-lock.d.ts +26 -0
  403. package/dist/service/instance-lock.js +150 -0
  404. package/dist/service/instance-lock.js.map +1 -0
  405. package/dist/service/launchd.d.ts +11 -0
  406. package/dist/service/launchd.js +196 -0
  407. package/dist/service/launchd.js.map +1 -0
  408. package/dist/service/schtasks.d.ts +31 -0
  409. package/dist/service/schtasks.js +274 -0
  410. package/dist/service/schtasks.js.map +1 -0
  411. package/dist/service/shim.d.ts +21 -0
  412. package/dist/service/shim.js +80 -0
  413. package/dist/service/shim.js.map +1 -0
  414. package/dist/service/systemd.d.ts +11 -0
  415. package/dist/service/systemd.js +150 -0
  416. package/dist/service/systemd.js.map +1 -0
  417. package/dist/service/task-xml.d.ts +36 -0
  418. package/dist/service/task-xml.js +91 -0
  419. package/dist/service/task-xml.js.map +1 -0
  420. package/dist/service/types.d.ts +47 -0
  421. package/dist/service/types.js +2 -0
  422. package/dist/service/types.js.map +1 -0
  423. package/dist/storage/archival.d.ts +29 -0
  424. package/dist/storage/archival.js +47 -0
  425. package/dist/storage/archival.js.map +1 -0
  426. package/dist/storage/bearer-keystore.d.ts +34 -0
  427. package/dist/storage/bearer-keystore.js +75 -0
  428. package/dist/storage/bearer-keystore.js.map +1 -0
  429. package/dist/storage/db.d.ts +37 -0
  430. package/dist/storage/db.js +92 -0
  431. package/dist/storage/db.js.map +1 -0
  432. package/dist/storage/entities.d.ts +71 -0
  433. package/dist/storage/entities.js +141 -0
  434. package/dist/storage/entities.js.map +1 -0
  435. package/dist/storage/ingest-idempotency.d.ts +26 -0
  436. package/dist/storage/ingest-idempotency.js +29 -0
  437. package/dist/storage/ingest-idempotency.js.map +1 -0
  438. package/dist/storage/keystore.d.ts +64 -0
  439. package/dist/storage/keystore.js +194 -0
  440. package/dist/storage/keystore.js.map +1 -0
  441. package/dist/storage/memories.d.ts +51 -0
  442. package/dist/storage/memories.js +67 -0
  443. package/dist/storage/memories.js.map +1 -0
  444. package/dist/storage/memory-events.d.ts +145 -0
  445. package/dist/storage/memory-events.js +287 -0
  446. package/dist/storage/memory-events.js.map +1 -0
  447. package/dist/storage/migrate-encrypt.d.ts +16 -0
  448. package/dist/storage/migrate-encrypt.js +121 -0
  449. package/dist/storage/migrate-encrypt.js.map +1 -0
  450. package/dist/storage/migrate.d.ts +27 -0
  451. package/dist/storage/migrate.js +105 -0
  452. package/dist/storage/migrate.js.map +1 -0
  453. package/dist/storage/redaction-log.d.ts +18 -0
  454. package/dist/storage/redaction-log.js +27 -0
  455. package/dist/storage/redaction-log.js.map +1 -0
  456. package/dist/storage/usefulness.d.ts +115 -0
  457. package/dist/storage/usefulness.js +203 -0
  458. package/dist/storage/usefulness.js.map +1 -0
  459. package/dist/sync/conflict-resolve.d.ts +26 -0
  460. package/dist/sync/conflict-resolve.js +139 -0
  461. package/dist/sync/conflict-resolve.js.map +1 -0
  462. package/dist/sync/puller.d.ts +115 -0
  463. package/dist/sync/puller.js +173 -0
  464. package/dist/sync/puller.js.map +1 -0
  465. package/dist/sync/shipper.d.ts +112 -0
  466. package/dist/sync/shipper.js +189 -0
  467. package/dist/sync/shipper.js.map +1 -0
  468. package/dist/tag-hygiene/backfill.d.ts +50 -0
  469. package/dist/tag-hygiene/backfill.js +117 -0
  470. package/dist/tag-hygiene/backfill.js.map +1 -0
  471. package/dist/tag-hygiene/derive-repo.d.ts +9 -0
  472. package/dist/tag-hygiene/derive-repo.js +19 -0
  473. package/dist/tag-hygiene/derive-repo.js.map +1 -0
  474. package/dist/tag-hygiene/tier2-infer.d.ts +28 -0
  475. package/dist/tag-hygiene/tier2-infer.js +72 -0
  476. package/dist/tag-hygiene/tier2-infer.js.map +1 -0
  477. package/dist/vector/sqlite-vec.d.ts +16 -0
  478. package/dist/vector/sqlite-vec.js +49 -0
  479. package/dist/vector/sqlite-vec.js.map +1 -0
  480. package/migrations/001-init.sql +117 -0
  481. package/migrations/002-wire-v1.sql +16 -0
  482. package/migrations/003-expand-memory-types.sql +81 -0
  483. package/migrations/004-provenance.sql +4 -0
  484. package/migrations/005-security.sql +12 -0
  485. package/migrations/006-atom-v3.sql +28 -0
  486. package/migrations/007-memory-events.sql +30 -0
  487. package/migrations/008-consolidation.sql +31 -0
  488. package/migrations/009-tag-hygiene.sql +13 -0
  489. package/migrations/010-sync-pull.sql +53 -0
  490. package/migrations/011-embed-dim-migration.sql +28 -0
  491. package/migrations/012-entities.sql +36 -0
  492. package/migrations/013-archival.sql +50 -0
  493. package/package.json +50 -0
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Search orchestrator — hybrid FTS5 + vector + score fusion.
3
+ *
4
+ * Flow:
5
+ * 1. FTS5 BM25 query on memories_fts
6
+ * 2. embed(query) via EmbedProvider → vec.search() (mock or real)
7
+ * 3. fuseHits — merge FTS + cosine scores
8
+ * 4. apply SQL filters (type, repo, project, since) on the fused id set
9
+ * 5. join full Memory records, return top-k hits
10
+ *
11
+ * VecFilter is intentionally empty on vector search calls because sqlite-vec
12
+ * does not support pre-filtering. All filters are applied post-fusion.
13
+ */
14
+ import type { DB } from '../storage/db.js';
15
+ import type { EmbedProvider } from '../contracts/index.js';
16
+ import type { MemoryType } from '../contracts/index.js';
17
+ export interface SearchFilters {
18
+ type?: string[];
19
+ repo?: string;
20
+ /**
21
+ * Project filter (FEAT-423). Exact match on `memories.project`. A single
22
+ * string → `project = ?`; a string[] → `project IN (...)` (OR-semantics,
23
+ * mirrors `type[]`). Empty array = no constraint. Absent → all projects.
24
+ */
25
+ project?: string | string[];
26
+ /**
27
+ * Agent filter (FEAT-423 nice-to-have). Exact match on `memories.agent`
28
+ * (the provenance `agent`/`agent_type` populated at ingest). Applied
29
+ * post-fusion exactly like `repo`/`project`; single string or string[]
30
+ * (IN). Absent → all agents. This is a HARD filter; role-scoped soft-boost
31
+ * recall (FEAT-219) is a separate, later ranking concern and does not go here.
32
+ */
33
+ agent?: string | string[];
34
+ since?: number;
35
+ /**
36
+ * Bitemporal time-travel (FEAT-401, ADR-001/ADR-005): return memories as
37
+ * they stood at this instant (epoch ms) rather than the current snapshot.
38
+ * Absent = current behavior (only currently-valid rows).
39
+ */
40
+ as_of?: number;
41
+ /**
42
+ * Entity filter (FEAT-402 slice 2 AC-4). Resolved through
43
+ * EntityRepo.resolveIds (AC-9 normalize seam: exact match, then LIKE
44
+ * substring fallback) to one or more entities.id, then intersected with
45
+ * the FTS+vec candidate set BEFORE fusion — the result is all-and-only
46
+ * entity-linked members of that candidate set, not a post-fusion filter.
47
+ * An unresolvable entity name yields zero results (not an unfiltered
48
+ * search).
49
+ */
50
+ entity?: string;
51
+ }
52
+ export interface SearchHit {
53
+ id: string;
54
+ type: MemoryType;
55
+ text: string;
56
+ score: number;
57
+ source: 'fts' | 'vec' | 'both';
58
+ }
59
+ export interface SearchOpts {
60
+ db: DB;
61
+ embed: EmbedProvider;
62
+ weights: {
63
+ alpha: number;
64
+ beta: number;
65
+ gamma: number;
66
+ delta: number;
67
+ epsilon?: number;
68
+ zeta?: number;
69
+ };
70
+ /** Multiplier used by vector search (cap to limit vector scan) */
71
+ vecK?: number;
72
+ /**
73
+ * SLICE-410-3: when true, search() returns SearchDebugHit[] — the
74
+ * per-candidate fusion intermediates (raw+normalized bm25/cosine,
75
+ * importance, freshness, usefulness, entityBonus, effective weights, and
76
+ * the final fused score) instead of collapsing to SearchHit[]. Every
77
+ * other step (candidate gathering, entity filter, post-fusion SQL
78
+ * filters, validity/as_of, limit, ranking order) is unchanged — debug is
79
+ * purely an alternate projection of the same fused list, so debug:false
80
+ * or omitted is byte-identical to pre-change behavior (AC-2).
81
+ */
82
+ debug?: boolean;
83
+ }
84
+ /**
85
+ * Per-candidate fusion breakdown (SLICE-410-3 AC-1) — the upstream contract
86
+ * for SLICE-410-6's search-debug dashboard page. Mirrors the components
87
+ * `fuseHits`/`fuseScores` (fuse.ts) compute internally and normally discard.
88
+ *
89
+ * Sentinel (AC-4): when a leg has no hit for this candidate (e.g. embed
90
+ * provider down → no vector leg at all), that leg's `raw` is `null` and
91
+ * `normalized` is `0` — identical to the no-signal default `fuseHits`
92
+ * already uses internally, so `score` stays reproducible from these fields
93
+ * even in a degraded (FTS-only or vec-only) run.
94
+ *
95
+ * `usefulness`/`entityBonus`/`weights` are always the *effective* values
96
+ * actually fed into `fuseScores` (defaults resolved, e.g. usefulness 0.5 /
97
+ * entityBonus 0 / zeta 0) so `score` can be reconstructed exactly as:
98
+ * weights.alpha * bm25.normalized + weights.beta * cosine.normalized
99
+ * + weights.gamma * importance + weights.delta * freshness
100
+ * + weights.epsilon * usefulness + weights.zeta * entityBonus
101
+ */
102
+ export interface SearchDebugHit {
103
+ id: string;
104
+ source: 'fts' | 'vec' | 'both';
105
+ bm25: {
106
+ raw: number | null;
107
+ normalized: number;
108
+ };
109
+ cosine: {
110
+ raw: number | null;
111
+ normalized: number;
112
+ };
113
+ importance: number;
114
+ freshness: number;
115
+ usefulness: number;
116
+ entityBonus: number;
117
+ weights: {
118
+ alpha: number;
119
+ beta: number;
120
+ gamma: number;
121
+ delta: number;
122
+ epsilon: number;
123
+ zeta: number;
124
+ };
125
+ score: number;
126
+ }
127
+ /**
128
+ * Bitemporal validity SQL clause (FEAT-401) — the ONE shared filter used by
129
+ * every caller of search() (GET /search, POST /recall, the eval harness).
130
+ * There is deliberately no second implementation anywhere else: the CLI
131
+ * `--as-of` flag and the API `as_of` filter both terminate here because the
132
+ * CLI is a thin HTTP client of the same routes that call search().
133
+ *
134
+ * - No as_of (undefined): current snapshot — only rows with valid_to IS
135
+ * NULL surface, byte-identical to pre-FEAT-401 behavior (AC-2).
136
+ * - as_of = T: the row valid AT INSTANT T — valid_from <= T AND (valid_to
137
+ * IS NULL OR valid_to > T). Half-open interval [valid_from, valid_to):
138
+ * at the exact instant a supersede/invalidate event lands, the new
139
+ * generation is already the one considered valid (AC-5).
140
+ */
141
+ export declare function validityFilterClause(asOf?: number): {
142
+ clause: string;
143
+ params: number[];
144
+ };
145
+ /**
146
+ * Parse an `as_of` wire value (ISO-8601 date-time string) into epoch ms.
147
+ * Shared by every route that accepts the filter (GET /search query param,
148
+ * POST /recall body) so a malformed value is rejected identically everywhere
149
+ * — one parsing path, not a per-route reimplementation. Returns undefined
150
+ * for an absent/empty value; throws for a present-but-unparseable value so
151
+ * callers can turn it into a 400.
152
+ */
153
+ export declare function parseAsOf(value: string | undefined): number | undefined;
154
+ /**
155
+ * Deterministic fake vector for testing — seeded by text hash, dim
156
+ * defaults to DEFAULT_EMBED_DIM (1024). Exported so tests can call it
157
+ * directly without importing the EmbedProvider. Pass `dim` to generate a
158
+ * fixture vector matching a non-default schema (FEAT-409 AC-2).
159
+ */
160
+ export declare function makeFakeVec(text: string, dim?: number): Float32Array;
161
+ export declare function search(query: string, filters: SearchFilters, limit: number, opts: SearchOpts & {
162
+ debug: true;
163
+ }): Promise<SearchDebugHit[]>;
164
+ export declare function search(query: string, filters: SearchFilters, limit: number, opts: SearchOpts): Promise<SearchHit[]>;
@@ -0,0 +1,310 @@
1
+ /**
2
+ * Search orchestrator — hybrid FTS5 + vector + score fusion.
3
+ *
4
+ * Flow:
5
+ * 1. FTS5 BM25 query on memories_fts
6
+ * 2. embed(query) via EmbedProvider → vec.search() (mock or real)
7
+ * 3. fuseHits — merge FTS + cosine scores
8
+ * 4. apply SQL filters (type, repo, project, since) on the fused id set
9
+ * 5. join full Memory records, return top-k hits
10
+ *
11
+ * VecFilter is intentionally empty on vector search calls because sqlite-vec
12
+ * does not support pre-filtering. All filters are applied post-fusion.
13
+ */
14
+ import { DEFAULT_EMBED_DIM } from '../contracts/embed.js';
15
+ import { fuseHits, normalizeScores } from './fuse.js';
16
+ import { SqliteVecStore } from '../vector/sqlite-vec.js';
17
+ import { usefulnessScores } from '../storage/usefulness.js';
18
+ import { EntityRepo } from '../storage/entities.js';
19
+ /**
20
+ * Sanitize a free-form query string for safe use with the FTS5 `MATCH` operator.
21
+ *
22
+ * FTS5 treats several characters as operators (`-` negation, `*` wildcard,
23
+ * `"` phrase, `^` column, `AND`/`OR`/`NOT` connectives). Without sanitization,
24
+ * a query like `sqlite-vec` triggers `fts5: syntax error near "-"` because `-`
25
+ * is parsed as a negation prefix.
26
+ *
27
+ * Strategy: split on whitespace, wrap each token in double quotes (treating
28
+ * each as a literal phrase), and escape embedded `"` by doubling it per the
29
+ * FTS5 phrase-literal rule. Multi-token queries become implicit AND.
30
+ *
31
+ * Trade-off: explicit FTS5 operators (e.g., `cat OR dog`, `"exact phrase"`,
32
+ * `prefix*`) are NOT honored in v1 — every input is treated as a bag of
33
+ * literal phrases. This is the right default for an agent-driven search
34
+ * surface; an `advanced` flag can be added later if needed.
35
+ */
36
+ function escapeFtsQuery(q) {
37
+ return q.trim().split(/\s+/).map(t => `"${t.replace(/"/g, '""')}"`).join(' ');
38
+ }
39
+ /**
40
+ * Bitemporal validity SQL clause (FEAT-401) — the ONE shared filter used by
41
+ * every caller of search() (GET /search, POST /recall, the eval harness).
42
+ * There is deliberately no second implementation anywhere else: the CLI
43
+ * `--as-of` flag and the API `as_of` filter both terminate here because the
44
+ * CLI is a thin HTTP client of the same routes that call search().
45
+ *
46
+ * - No as_of (undefined): current snapshot — only rows with valid_to IS
47
+ * NULL surface, byte-identical to pre-FEAT-401 behavior (AC-2).
48
+ * - as_of = T: the row valid AT INSTANT T — valid_from <= T AND (valid_to
49
+ * IS NULL OR valid_to > T). Half-open interval [valid_from, valid_to):
50
+ * at the exact instant a supersede/invalidate event lands, the new
51
+ * generation is already the one considered valid (AC-5).
52
+ */
53
+ export function validityFilterClause(asOf) {
54
+ if (asOf === undefined) {
55
+ return { clause: 'valid_to IS NULL', params: [] };
56
+ }
57
+ return { clause: 'valid_from <= ? AND (valid_to IS NULL OR valid_to > ?)', params: [asOf, asOf] };
58
+ }
59
+ /**
60
+ * Parse an `as_of` wire value (ISO-8601 date-time string) into epoch ms.
61
+ * Shared by every route that accepts the filter (GET /search query param,
62
+ * POST /recall body) so a malformed value is rejected identically everywhere
63
+ * — one parsing path, not a per-route reimplementation. Returns undefined
64
+ * for an absent/empty value; throws for a present-but-unparseable value so
65
+ * callers can turn it into a 400.
66
+ */
67
+ export function parseAsOf(value) {
68
+ if (value === undefined || value === '')
69
+ return undefined;
70
+ const ms = Date.parse(value);
71
+ if (Number.isNaN(ms)) {
72
+ throw new Error(`invalid as_of value: ${value} (expected ISO-8601 date-time)`);
73
+ }
74
+ return ms;
75
+ }
76
+ /**
77
+ * Deterministic fake vector for testing — seeded by text hash, dim
78
+ * defaults to DEFAULT_EMBED_DIM (1024). Exported so tests can call it
79
+ * directly without importing the EmbedProvider. Pass `dim` to generate a
80
+ * fixture vector matching a non-default schema (FEAT-409 AC-2).
81
+ */
82
+ export function makeFakeVec(text, dim = DEFAULT_EMBED_DIM) {
83
+ const v = new Float32Array(dim);
84
+ let hash = 0;
85
+ for (let i = 0; i < text.length; i++) {
86
+ hash = (hash * 31 + text.charCodeAt(i)) & 0xffffffff;
87
+ }
88
+ for (let i = 0; i < dim; i++) {
89
+ v[i] = Math.sin(hash * 0.001 + i * 0.01);
90
+ }
91
+ return v;
92
+ }
93
+ /**
94
+ * Compute the ζ entity-relevance bonus map (FEAT-402 slice 2 AC-6): for
95
+ * every known entity whose normalized name appears as a substring of the
96
+ * (lowercased) query text, any candidate id linked to that entity gets a
97
+ * bonus of 1. Only called when `search.zeta > 0` — with the default
98
+ * zeta=0 this function never runs, which is what makes the AC-6 snapshot
99
+ * guarantee (identical ranking at zeta=0) hold structurally, not just
100
+ * numerically.
101
+ */
102
+ function entityBonusForQuery(db, query, candidateIds) {
103
+ const q = query.trim().toLowerCase();
104
+ if (!q || candidateIds.size === 0)
105
+ return new Map();
106
+ const entityRows = db.prepare('SELECT id, name FROM entities').all();
107
+ const matchedEntityIds = entityRows.filter(r => r.name && q.includes(r.name)).map(r => r.id);
108
+ if (matchedEntityIds.length === 0)
109
+ return new Map();
110
+ const idPh = Array.from(candidateIds).map(() => '?').join(',');
111
+ const entPh = matchedEntityIds.map(() => '?').join(',');
112
+ const rows = db.prepare(`SELECT DISTINCT memory_id FROM memory_entities WHERE memory_id IN (${idPh}) AND entity_id IN (${entPh})`).all(...candidateIds, ...matchedEntityIds);
113
+ const bonus = new Map();
114
+ for (const row of rows)
115
+ bonus.set(row.memory_id, 1);
116
+ return bonus;
117
+ }
118
+ export async function search(query, filters, limit, opts) {
119
+ const { db, embed, weights } = opts;
120
+ const vecK = opts.vecK ?? Math.max(limit * 4, 50);
121
+ // 1. FTS5 BM25 — run only if query is non-empty
122
+ const ftsHits = [];
123
+ if (query.trim()) {
124
+ const ftsQuery = escapeFtsQuery(query);
125
+ try {
126
+ const rows = db.prepare(`
127
+ SELECT m.id, bm25(memories_fts) AS bm25
128
+ FROM memories_fts
129
+ JOIN memories m ON m.rowid = memories_fts.rowid
130
+ WHERE memories_fts MATCH ?
131
+ ORDER BY bm25
132
+ LIMIT ?
133
+ `).all(ftsQuery, vecK);
134
+ ftsHits.push(...rows);
135
+ }
136
+ catch {
137
+ // FTS5 rejected the query (rare with escapeFtsQuery sanitization).
138
+ // Fall through to vector-only path.
139
+ }
140
+ }
141
+ // 2. Vector search — always attempt; if embed fails, fall back to FTS-only
142
+ const vecHits = [];
143
+ try {
144
+ const vecs = await embed.embed([query]);
145
+ const queryVec = vecs[0];
146
+ if (!queryVec)
147
+ throw new Error('embed provider returned empty result');
148
+ const vecStore = new SqliteVecStore(db, embed.dim);
149
+ // Pass empty filter to vec adapter — post-fusion filters applied below
150
+ const raw = await vecStore.search(queryVec, vecK);
151
+ vecHits.push(...raw.map(h => ({ id: h.id, cosine: h.score })));
152
+ }
153
+ catch {
154
+ // Vector search unavailable (no rows, no provider) — FTS-only mode
155
+ }
156
+ // 2b. Entity filter (FEAT-402 slice 2 AC-4) — resolve `entity` to entity
157
+ // ids (AC-9 normalize seam) and intersect the FTS+vec candidate set BEFORE
158
+ // fusion, so the result is all-and-only entity-linked members of that
159
+ // candidate set. An entity name that resolves to zero entities filters the
160
+ // candidate set to empty (not "unfiltered") — search() returns [] below.
161
+ let filteredFtsHits = ftsHits;
162
+ let filteredVecHits = vecHits;
163
+ if (filters.entity !== undefined) {
164
+ const entityRepo = new EntityRepo(db);
165
+ const entityIds = entityRepo.resolveIds(filters.entity);
166
+ const linkedIds = entityRepo.memoryIdsForEntities(entityIds);
167
+ filteredFtsHits = ftsHits.filter(h => linkedIds.has(h.id));
168
+ filteredVecHits = vecHits.filter(h => linkedIds.has(h.id));
169
+ }
170
+ // 3. Load meta for all candidate ids (importance + created_at for freshness)
171
+ const allIds = new Set([...filteredFtsHits.map(h => h.id), ...filteredVecHits.map(h => h.id)]);
172
+ if (allIds.size === 0)
173
+ return [];
174
+ const placeholders = Array.from(allIds).map(() => '?').join(',');
175
+ const metaRows = db.prepare(`SELECT id, importance, created_at FROM memories WHERE id IN (${placeholders})`).all(...allIds);
176
+ const metaMap = new Map(metaRows.map(r => [r.id, { importance: r.importance, created_at: r.created_at }]));
177
+ // 4. Fuse — usefulness (ADR-010 v1.x) joins as the ε component. ζ
178
+ // (FEAT-402 AC-6) joins as an entity-relevance bonus: DEFAULT 0 (config
179
+ // search.zeta) means the term is skipped entirely — no query, no DB scan,
180
+ // no change to ranking order versus pre-AC-6 behavior.
181
+ const usefulness = usefulnessScores(db, Array.from(allIds));
182
+ const zeta = weights.zeta ?? 0;
183
+ const entityBonus = zeta > 0 ? entityBonusForQuery(db, query, allIds) : undefined;
184
+ const nowMs = Date.now();
185
+ const fused = fuseHits(filteredFtsHits, filteredVecHits, metaMap, weights, nowMs, undefined, usefulness, entityBonus);
186
+ // 5. Apply post-fusion SQL filters then join full memory records
187
+ // Build filter clauses dynamically
188
+ const filterClauses = [];
189
+ const filterParams = [];
190
+ if (filters.type && filters.type.length > 0) {
191
+ const ph = filters.type.map(() => '?').join(',');
192
+ filterClauses.push(`type IN (${ph})`);
193
+ filterParams.push(...filters.type);
194
+ }
195
+ if (filters.repo !== undefined) {
196
+ filterClauses.push('repo = ?');
197
+ filterParams.push(filters.repo);
198
+ }
199
+ // FEAT-423: project/agent accept a single value (`col = ?`) or a list
200
+ // (`col IN (...)`, OR-semantics like `type[]`). An empty list is treated as
201
+ // no constraint, never as "match nothing".
202
+ const addEqOrIn = (col, val) => {
203
+ if (Array.isArray(val)) {
204
+ if (val.length === 0)
205
+ return;
206
+ filterClauses.push(`${col} IN (${val.map(() => '?').join(',')})`);
207
+ filterParams.push(...val);
208
+ }
209
+ else {
210
+ filterClauses.push(`${col} = ?`);
211
+ filterParams.push(val);
212
+ }
213
+ };
214
+ if (filters.project !== undefined)
215
+ addEqOrIn('project', filters.project);
216
+ if (filters.agent !== undefined)
217
+ addEqOrIn('agent', filters.agent);
218
+ if (filters.since !== undefined) {
219
+ filterClauses.push('created_at >= ?');
220
+ filterParams.push(filters.since);
221
+ }
222
+ // Fetch full memory records in one query using IN clause
223
+ const fusedIds = fused.map(h => h.id);
224
+ const idPlaceholders = fusedIds.map(() => '?').join(',');
225
+ // Atom v3 (ADR-001): invalidated memories (valid_to set) must never surface
226
+ // in a current-snapshot recall — why_memory can still fetch them by id
227
+ // directly. FEAT-401: when as_of is set, the snapshot rule is replaced by
228
+ // the bitemporal validity window so a past-valid (now superseded) memory
229
+ // can surface again for a point-in-time query.
230
+ const { clause: validityClause, params: validityParams } = validityFilterClause(filters.as_of);
231
+ const whereFilter = filterClauses.length > 0 ? ` AND ${filterClauses.join(' AND ')}` : '';
232
+ const sql = `SELECT id, type, text FROM memories WHERE id IN (${idPlaceholders}) AND ${validityClause}${whereFilter}`;
233
+ const memRows = db.prepare(sql).all(...fusedIds, ...validityParams, ...filterParams);
234
+ const memMap = new Map(memRows.map(r => [r.id, r]));
235
+ // 6a. Debug projection (SLICE-410-3 AC-1) — recompute the same
236
+ // normalization fuseHits() applies internally (normalizeScores is
237
+ // exported from fuse.ts for exactly this reuse) so components are
238
+ // guaranteed consistent with `fused[].score`, without touching fuse.ts.
239
+ if (opts.debug) {
240
+ const bm25RawMap = new Map(filteredFtsHits.map(h => [h.id, h.bm25]));
241
+ const normBm25Arr = normalizeScores(filteredFtsHits.map(h => -h.bm25));
242
+ const normBm25Map = new Map(filteredFtsHits.map((h, i) => [h.id, normBm25Arr[i] ?? 0]));
243
+ const cosineRawMap = new Map(filteredVecHits.map(h => [h.id, h.cosine]));
244
+ const normCosineArr = normalizeScores(filteredVecHits.map(h => h.cosine));
245
+ const normCosineMap = new Map(filteredVecHits.map((h, i) => [h.id, normCosineArr[i] ?? 0]));
246
+ // Freshness half-life: fuse.ts fuseHits() default freshnessDecayDays=30,
247
+ // which search() always uses (passes `undefined` through to that
248
+ // default). Kept identical here so freshness — and thus `score` — stays
249
+ // reproducible from the documented weights (AC-3).
250
+ const freshnessDecayDays = 30;
251
+ // fuseScores() divides the raw weighted sum by the sum of active weights
252
+ // to keep scores in [0,1] (wire contract). Report weightSum-normalized
253
+ // weights here so `score` stays exactly reproducible as
254
+ // Σ weights.* × component from this object alone.
255
+ const rawWeightSum = weights.alpha + weights.beta + weights.gamma + weights.delta +
256
+ (weights.epsilon ?? 0) + zeta;
257
+ const weightSum = rawWeightSum === 0 ? 1 : rawWeightSum;
258
+ const effectiveWeights = {
259
+ alpha: weights.alpha / weightSum,
260
+ beta: weights.beta / weightSum,
261
+ gamma: weights.gamma / weightSum,
262
+ delta: weights.delta / weightSum,
263
+ epsilon: (weights.epsilon ?? 0) / weightSum,
264
+ zeta: zeta / weightSum,
265
+ };
266
+ const debugResults = [];
267
+ for (const hit of fused) {
268
+ if (!memMap.has(hit.id))
269
+ continue; // filtered out, same as SearchHit path
270
+ const meta = metaMap.get(hit.id);
271
+ const importance = meta?.importance ?? 0.5;
272
+ const createdAt = meta?.created_at ?? nowMs;
273
+ const ageDays = (nowMs - createdAt) / (24 * 60 * 60 * 1000);
274
+ const freshness = Math.exp(-ageDays / freshnessDecayDays);
275
+ debugResults.push({
276
+ id: hit.id,
277
+ source: hit.source,
278
+ bm25: { raw: bm25RawMap.get(hit.id) ?? null, normalized: normBm25Map.get(hit.id) ?? 0 },
279
+ cosine: { raw: cosineRawMap.get(hit.id) ?? null, normalized: normCosineMap.get(hit.id) ?? 0 },
280
+ importance,
281
+ freshness,
282
+ usefulness: usefulness.get(hit.id) ?? 0.5,
283
+ entityBonus: entityBonus?.get(hit.id) ?? 0,
284
+ weights: effectiveWeights,
285
+ score: hit.score,
286
+ });
287
+ if (debugResults.length >= limit)
288
+ break;
289
+ }
290
+ return debugResults;
291
+ }
292
+ // 6. Build result — preserve fused ranking order, skip filtered-out ids
293
+ const results = [];
294
+ for (const hit of fused) {
295
+ const mem = memMap.get(hit.id);
296
+ if (!mem)
297
+ continue; // filtered out
298
+ results.push({
299
+ id: hit.id,
300
+ type: mem.type,
301
+ text: mem.text,
302
+ score: hit.score,
303
+ source: hit.source
304
+ });
305
+ if (results.length >= limit)
306
+ break;
307
+ }
308
+ return results;
309
+ }
310
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/search/search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAiB,MAAM,WAAW,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAgGpD;;;;;;;;;;;;;;;;GAgBG;AACH,SAAS,cAAc,CAAC,CAAS;IAC/B,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAChF,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAa;IAChD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACpD,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,wDAAwD,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;AACpG,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CAAC,KAAyB;IACjD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAC1D,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC7B,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,wBAAwB,KAAK,gCAAgC,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,MAAc,iBAAiB;IACvE,MAAM,CAAC,GAAG,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC;IACvD,CAAC;IACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,mBAAmB,CAAC,EAAM,EAAE,KAAa,EAAE,YAAyB;IAC3E,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,IAAI,CAAC,CAAC,IAAI,YAAY,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,IAAI,GAAG,EAAE,CAAC;IAEpD,MAAM,UAAU,GAAG,EAAE,CAAC,OAAO,CAAC,+BAA+B,CAAC,CAAC,GAAG,EAAyC,CAAC;IAC5G,MAAM,gBAAgB,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC7F,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,GAAG,EAAE,CAAC;IAEpD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,gBAAgB,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxD,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CACrB,sEAAsE,IAAI,uBAAuB,KAAK,GAAG,CAC1G,CAAC,GAAG,CAAC,GAAG,YAAY,EAAE,GAAG,gBAAgB,CAAiC,CAAC;IAE5E,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxC,KAAK,MAAM,GAAG,IAAI,IAAI;QAAE,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;IACpD,OAAO,KAAK,CAAC;AACf,CAAC;AAcD,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,KAAa,EACb,OAAsB,EACtB,KAAa,EACb,IAAgB;IAEhB,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;IAElD,gDAAgD;IAChD,MAAM,OAAO,GAAwC,EAAE,CAAC;IACxD,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QACjB,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC;;;;;;;OAOvB,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAwC,CAAC;YAC9D,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACP,mEAAmE;YACnE,oCAAoC;QACtC,CAAC;IACH,CAAC;IAED,2EAA2E;IAC3E,MAAM,OAAO,GAA0C,EAAE,CAAC;IAC1D,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACzB,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QACvE,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QACnD,uEAAuE;QACvE,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;IACjE,CAAC;IAAC,MAAM,CAAC;QACP,mEAAmE;IACrE,CAAC;IAED,yEAAyE;IACzE,2EAA2E;IAC3E,sEAAsE;IACtE,2EAA2E;IAC3E,yEAAyE;IACzE,IAAI,eAAe,GAAG,OAAO,CAAC;IAC9B,IAAI,eAAe,GAAG,OAAO,CAAC;IAC9B,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QACjC,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;QACtC,MAAM,SAAS,GAAG,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACxD,MAAM,SAAS,GAAG,UAAU,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAAC;QAC7D,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3D,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,6EAA6E;IAC7E,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/F,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEjC,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjE,MAAM,QAAQ,GAAG,EAAE,CAAC,OAAO,CACzB,gEAAgE,YAAY,GAAG,CAChF,CAAC,GAAG,CAAC,GAAG,MAAM,CAAkE,CAAC;IAElF,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;IAE3G,kEAAkE;IAClE,wEAAwE;IACxE,0EAA0E;IAC1E,uDAAuD;IACvD,MAAM,UAAU,GAAG,gBAAgB,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAC5D,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC;IAC/B,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAClF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,MAAM,KAAK,GAAG,QAAQ,CAAC,eAAe,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;IAEtH,iEAAiE;IACjE,sCAAsC;IACtC,MAAM,aAAa,GAAa,EAAE,CAAC;IACnC,MAAM,YAAY,GAAwB,EAAE,CAAC;IAE7C,IAAI,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5C,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjD,aAAa,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;QACtC,YAAY,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC/B,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC/B,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IACD,sEAAsE;IACtE,4EAA4E;IAC5E,2CAA2C;IAC3C,MAAM,SAAS,GAAG,CAAC,GAAwB,EAAE,GAAsB,EAAE,EAAE;QACrE,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO;YAC7B,aAAa,CAAC,IAAI,CAAC,GAAG,GAAG,QAAQ,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAClE,YAAY,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;QAC5B,CAAC;aAAM,CAAC;YACN,aAAa,CAAC,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC;YACjC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;IACH,CAAC,CAAC;IACF,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS;QAAE,SAAS,CAAC,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACzE,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;QAAE,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACnE,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAChC,aAAa,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACtC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;IAED,yDAAyD;IACzD,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACtC,MAAM,cAAc,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzD,4EAA4E;IAC5E,uEAAuE;IACvE,0EAA0E;IAC1E,yEAAyE;IACzE,+CAA+C;IAC/C,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,oBAAoB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC/F,MAAM,WAAW,GAAG,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1F,MAAM,GAAG,GAAG,oDAAoD,cAAc,SAAS,cAAc,GAAG,WAAW,EAAE,CAAC;IACtH,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,QAAQ,EAAE,GAAG,cAAc,EAAE,GAAG,YAAY,CAA0D,CAAC;IAE9I,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAEpD,+DAA+D;IAC/D,kEAAkE;IAClE,kEAAkE;IAClE,wEAAwE;IACxE,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrE,MAAM,WAAW,GAAG,eAAe,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACvE,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAExF,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACzE,MAAM,aAAa,GAAG,eAAe,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QAC1E,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAE5F,yEAAyE;QACzE,iEAAiE;QACjE,wEAAwE;QACxE,mDAAmD;QACnD,MAAM,kBAAkB,GAAG,EAAE,CAAC;QAC9B,yEAAyE;QACzE,uEAAuE;QACvE,wDAAwD;QACxD,kDAAkD;QAClD,MAAM,YAAY,GAChB,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK;YAC5D,CAAC,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;QAChC,MAAM,SAAS,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;QACxD,MAAM,gBAAgB,GAAG;YACvB,KAAK,EAAE,OAAO,CAAC,KAAK,GAAG,SAAS;YAChC,IAAI,EAAE,OAAO,CAAC,IAAI,GAAG,SAAS;YAC9B,KAAK,EAAE,OAAO,CAAC,KAAK,GAAG,SAAS;YAChC,KAAK,EAAE,OAAO,CAAC,KAAK,GAAG,SAAS;YAChC,OAAO,EAAE,CAAC,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,SAAS;YAC3C,IAAI,EAAE,IAAI,GAAG,SAAS;SACvB,CAAC;QAEF,MAAM,YAAY,GAAqB,EAAE,CAAC;QAC1C,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;YACxB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE,SAAS,CAAE,uCAAuC;YAC3E,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACjC,MAAM,UAAU,GAAG,IAAI,EAAE,UAAU,IAAI,GAAG,CAAC;YAC3C,MAAM,SAAS,GAAG,IAAI,EAAE,UAAU,IAAI,KAAK,CAAC;YAC5C,MAAM,OAAO,GAAG,CAAC,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;YAC5D,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,GAAG,kBAAkB,CAAC,CAAC;YAE1D,YAAY,CAAC,IAAI,CAAC;gBAChB,EAAE,EAAE,GAAG,CAAC,EAAE;gBACV,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,IAAI,EAAE,EAAE,GAAG,EAAE,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,UAAU,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;gBACvF,MAAM,EAAE,EAAE,GAAG,EAAE,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,UAAU,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;gBAC7F,UAAU;gBACV,SAAS;gBACT,UAAU,EAAE,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,GAAG;gBACzC,WAAW,EAAE,WAAW,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC;gBAC1C,OAAO,EAAE,gBAAgB;gBACzB,KAAK,EAAE,GAAG,CAAC,KAAK;aACjB,CAAC,CAAC;YACH,IAAI,YAAY,CAAC,MAAM,IAAI,KAAK;gBAAE,MAAM;QAC1C,CAAC;QACD,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,wEAAwE;IACxE,MAAM,OAAO,GAAgB,EAAE,CAAC;IAChC,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC/B,IAAI,CAAC,GAAG;YAAE,SAAS,CAAE,eAAe;QACpC,OAAO,CAAC,IAAI,CAAC;YACX,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,MAAM,EAAE,GAAG,CAAC,MAAM;SACnB,CAAC,CAAC;QACH,IAAI,OAAO,CAAC,MAAM,IAAI,KAAK;YAAE,MAAM;IACrC,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ import type { DB } from '../storage/db.js';
3
+ import type { EmbedProvider } from '../contracts/index.js';
4
+ import { type Config } from '../config/config.js';
5
+ import type { HealthState } from './health-state.js';
6
+ export interface AppOpts {
7
+ db: DB;
8
+ token: string;
9
+ /** Embed provider injected for search + remember routes. Defaults to fake/noop. */
10
+ embed?: EmbedProvider;
11
+ /** Server config — used by dashboard route for budget cap display. Defaults to defaultConfig(). */
12
+ config?: Config;
13
+ /** Live daemon health snapshot (degraded-start, D3). Optional — /health
14
+ * omits the status/embed fields when absent (e.g. bare test apps). */
15
+ healthState?: HealthState;
16
+ }
17
+ export declare function buildApp(opts: AppOpts): Promise<FastifyInstance>;
@@ -0,0 +1,133 @@
1
+ import Fastify from 'fastify';
2
+ import { healthRoute } from './routes/health.js';
3
+ import { versionRoute } from './routes/version.js';
4
+ import { ingestRoute } from './routes/ingest.js';
5
+ import { searchRoute } from './routes/search.js';
6
+ import { memoryRoute } from './routes/memory.js';
7
+ import { lifecycleRoutes } from './routes/lifecycle.js';
8
+ import { whyRoute } from './routes/why.js';
9
+ import { digestRoute } from './routes/digest.js';
10
+ import { recallRoute } from './routes/recall.js';
11
+ import { mcpRoute } from './routes/mcp.js';
12
+ import { dashboardRoute } from './routes/dashboard.js';
13
+ import { dashboardConsolidationRoute } from './routes/dashboard-consolidation-html.js';
14
+ import { dashboardJobsRoute } from './routes/dashboard-jobs-html.js';
15
+ import { dashboardSearchRoute } from './routes/dashboard-search-html.js';
16
+ import { dashboardApiRoute } from './routes/dashboard-api-html.js';
17
+ import { memoryToolRoute } from './routes/memory-tool.js';
18
+ import { consolidationRoutes } from './routes/consolidation.js';
19
+ import { entitiesRoute } from './routes/entities.js';
20
+ import { makeFakeVec } from '../search/search.js';
21
+ import { childLogger } from '../log/logger.js';
22
+ import { newRequestId, runWithRequestId } from '../log/correlation.js';
23
+ import { defaultConfig } from '../config/config.js';
24
+ import { isLoopbackHost } from './lib/network.js';
25
+ /** Default no-op embed provider used when no real provider is injected.
26
+ * FEAT-409: dim derived from config.embedding.dim (defaults to
27
+ * DEFAULT_EMBED_DIM via defaultConfig()) rather than a literal, so the
28
+ * noop provider's fake vectors always match whatever schema dim is live. */
29
+ function makeNoopEmbed(dim) {
30
+ return {
31
+ name: 'ollama',
32
+ model: 'noop',
33
+ dim,
34
+ embed: async (texts) => texts.map(t => makeFakeVec(t, dim)),
35
+ health: async () => ({ ok: false, model: 'noop', dim, error: 'no provider configured' })
36
+ };
37
+ }
38
+ export async function buildApp(opts) {
39
+ // Fastify's internal logger is disabled. We emit request lifecycle logs
40
+ // manually via the onResponse hook below, using our pino instance + the
41
+ // request_id we generate in onRequest. This sidesteps a type incompatibility
42
+ // between FastifyBaseLogger and FastifyInstance<never logger>.
43
+ const app = Fastify({
44
+ logger: false,
45
+ // Long Codex/Claude sessions routinely exceed Fastify's 1MiB default —
46
+ // an oversized transcript should not 413 (wire: POST /ingest/transcript).
47
+ bodyLimit: 10 * 1024 * 1024,
48
+ // A stuck handler must not hold a connection forever (recall with a cold
49
+ // embed can be slow, but 60s is the ceiling — matches the LLM timeout).
50
+ requestTimeout: 60_000,
51
+ });
52
+ const config = opts.config ?? defaultConfig();
53
+ const embed = opts.embed ?? makeNoopEmbed(config.embedding.dim);
54
+ // Assign a request_id to every incoming request and expose it on the reply header.
55
+ app.addHook('onRequest', async (req, reply) => {
56
+ const requestId = newRequestId();
57
+ // Store on req so downstream hooks / routes can read it
58
+ req['requestId'] = requestId;
59
+ // Bind to async local storage for propagation into jobs queued from this request
60
+ runWithRequestId(requestId, () => {
61
+ // noop — storage set; pino child created in route handlers
62
+ });
63
+ void reply.header('x-request-id', requestId);
64
+ });
65
+ // Log HTTP request start + completion with required fields.
66
+ app.addHook('onResponse', (req, reply, done) => {
67
+ const requestId = req['requestId'];
68
+ const log = childLogger({ request_id: requestId ?? 'unknown' });
69
+ log.info({
70
+ method: req.method,
71
+ path: req.url,
72
+ status: reply.statusCode,
73
+ }, 'request complete');
74
+ done();
75
+ });
76
+ // Auth check — scrub the Authorization header value from any error logs.
77
+ // /dashboard and its sub-pages (/dashboard/consolidation, /dashboard/jobs,
78
+ // /dashboard/search — FEAT-410) validate their own token via ?token= query
79
+ // param or cookie — always exempt on prefix, not just the exact path.
80
+ // /health and /version are public ONLY while the daemon is bound to loopback
81
+ // (default). FEAT-406: opting into a non-local bind (config.network.host set
82
+ // to anything but 127.0.0.1/localhost/::1) requires Bearer auth on BOTH
83
+ // routes together — isLoopbackHost is the one predicate that decides this,
84
+ // so the bind and the auth boundary can never drift apart.
85
+ const isLocalBind = isLoopbackHost(config.network.host);
86
+ app.addHook('preHandler', async (req, reply) => {
87
+ const path = req.url.split('?')[0];
88
+ if (path === '/dashboard' || path?.startsWith('/dashboard/'))
89
+ return;
90
+ if (isLocalBind && (path === '/health' || path === '/version'))
91
+ return;
92
+ const auth = req.headers.authorization;
93
+ if (auth !== `Bearer ${opts.token}`) {
94
+ const requestId = req['requestId'];
95
+ childLogger({ request_id: requestId ?? 'unknown' }).warn({ method: req.method, path: req.url }, 'unauthorized request');
96
+ return reply.code(401).send({ error: 'unauthorized' });
97
+ }
98
+ });
99
+ // Unhandled route errors: log the full error server-side, return a
100
+ // sanitized body (no stack, no internals) with the original status when a
101
+ // route set one (e.g. Fastify's own 413/400), else 500. Existing 4xx
102
+ // paths return their own bodies and never reach this handler.
103
+ app.setErrorHandler((rawErr, req, reply) => {
104
+ const err = rawErr;
105
+ const requestId = req['requestId'];
106
+ const status = typeof err.statusCode === 'number' && err.statusCode >= 400 ? err.statusCode : 500;
107
+ childLogger({ request_id: requestId ?? 'unknown' }).error({ method: req.method, path: req.url, status, error_message: err.message, error_kind: err.name }, 'request failed');
108
+ void reply.code(status).send({
109
+ ok: false,
110
+ error: { code: status === 500 ? 'internal' : String(err.code ?? status), message: status === 500 ? 'internal error' : err.message },
111
+ });
112
+ });
113
+ await app.register(healthRoute(config, opts.db, opts.healthState));
114
+ await app.register(versionRoute);
115
+ await app.register(ingestRoute(opts.db, config));
116
+ await app.register(searchRoute(opts.db, embed, config));
117
+ await app.register(memoryRoute(opts.db));
118
+ await app.register(lifecycleRoutes(opts.db));
119
+ await app.register(whyRoute(opts.db));
120
+ await app.register(digestRoute(opts.db));
121
+ await app.register(recallRoute(opts.db, config));
122
+ await app.register(mcpRoute(opts.db, embed, config));
123
+ await app.register(dashboardRoute(opts.db, config, opts.token, opts.healthState));
124
+ await app.register(dashboardConsolidationRoute(opts.db, opts.token));
125
+ await app.register(dashboardJobsRoute(opts.db, opts.token));
126
+ await app.register(dashboardSearchRoute(opts.db, embed, opts.token));
127
+ await app.register(dashboardApiRoute(opts.token));
128
+ await app.register(memoryToolRoute(opts.db, config));
129
+ await app.register(consolidationRoutes(opts.db));
130
+ await app.register(entitiesRoute(opts.db));
131
+ return app;
132
+ }
133
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/server/app.ts"],"names":[],"mappings":"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"}