@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,165 @@
1
+ /**
2
+ * Stage-0 secret redaction (spec docs/specs/2026-07-02-encryption-and-secret-redaction.md
3
+ * §4.2/§4.3, SEC-3..6/SEC-9).
4
+ *
5
+ * Single entry point: `redactText(input, opts)`. Invoked at the ingest choke
6
+ * point (POST /ingest/transcript, before the `transcripts` INSERT) and on the
7
+ * `/remember` manual-write path (spec OQ-2: yes). Downstream pipeline stages
8
+ * inherit already-redacted text — there is no second redaction pass.
9
+ *
10
+ * Placeholder format: `[REDACTED:<type>:<hash8>]` where hash8 = first 8 hex
11
+ * chars of SHA-256(secret value). Same secret -> same placeholder (dedup-safe
12
+ * across a transcript); the raw value is NEVER stored or logged (SEC-5).
13
+ *
14
+ * Detection order (never redact inside an already-inserted placeholder):
15
+ * 1. PEM private-key blocks (multiline, whole block)
16
+ * 2. Vendor/pattern detectors (AWS, GitHub, Azure, GCP, Slack, generic
17
+ * key=value, JWT, connection-string userinfo) + config custom patterns
18
+ * 3. Shannon-entropy detector over whatever text remains
19
+ */
20
+ import { createHash } from 'node:crypto';
21
+ import { PEM_DETECTOR, PATTERN_DETECTORS, customDetector } from './detectors.js';
22
+ import { findEntropySecrets } from './entropy.js';
23
+ const PLACEHOLDER_RE_G = /\[REDACTED:[^\]]+\]/g;
24
+ function hash8(value) {
25
+ return createHash('sha256').update(value).digest('hex').slice(0, 8);
26
+ }
27
+ function placeholder(type, digest) {
28
+ return `[REDACTED:${type}:${digest}]`;
29
+ }
30
+ /** Spans already occupied by a previously-inserted placeholder in `text`. */
31
+ function protectedRanges(text) {
32
+ const ranges = [];
33
+ let m;
34
+ PLACEHOLDER_RE_G.lastIndex = 0;
35
+ while ((m = PLACEHOLDER_RE_G.exec(text)) !== null) {
36
+ ranges.push([m.index, m.index + m[0].length]);
37
+ }
38
+ return ranges;
39
+ }
40
+ function overlapsAny(start, end, ranges) {
41
+ return ranges.some(([rs, re]) => start < re && end > rs);
42
+ }
43
+ /** Run one PatternDetector over `text`, returning non-overlapping-with-protected spans. */
44
+ function runDetector(text, detector, guard) {
45
+ const flags = detector.flags.includes('g') ? detector.flags : `${detector.flags}g`;
46
+ const re = new RegExp(detector.source, flags.includes('d') ? flags : `${flags}d`);
47
+ const spans = [];
48
+ let m;
49
+ while ((m = re.exec(text)) !== null) {
50
+ let start;
51
+ let end;
52
+ let value;
53
+ const indices = m.indices;
54
+ const groupRange = detector.valueGroup !== undefined ? indices?.[detector.valueGroup] : undefined;
55
+ if (groupRange !== undefined) {
56
+ [start, end] = groupRange;
57
+ value = m[detector.valueGroup];
58
+ }
59
+ else {
60
+ start = m.index;
61
+ end = m.index + m[0].length;
62
+ value = m[0];
63
+ }
64
+ if (end > start && !overlapsAny(start, end, guard)) {
65
+ spans.push({ type: detector.type, start, end, value });
66
+ }
67
+ if (re.lastIndex === m.index)
68
+ re.lastIndex++; // guard zero-length matches
69
+ }
70
+ return spans;
71
+ }
72
+ /** Drop spans that overlap an earlier (higher-priority) span from the same batch. */
73
+ function dedupeOverlaps(spans) {
74
+ const sorted = [...spans].sort((a, b) => a.start - b.start);
75
+ const kept = [];
76
+ let lastEnd = -1;
77
+ for (const s of sorted) {
78
+ if (s.start >= lastEnd) {
79
+ kept.push(s);
80
+ lastEnd = s.end;
81
+ }
82
+ }
83
+ return kept;
84
+ }
85
+ /** Replace `spans` (non-overlapping, sorted or not) in `text` with placeholders. */
86
+ function applySpans(text, spans) {
87
+ if (spans.length === 0)
88
+ return { text, events: [] };
89
+ const sorted = dedupeOverlaps(spans);
90
+ let out = '';
91
+ let cursor = 0;
92
+ const events = [];
93
+ for (const s of sorted) {
94
+ out += text.slice(cursor, s.start);
95
+ const digest = hash8(s.value);
96
+ out += placeholder(s.type, digest);
97
+ events.push({ type: s.type, hash8: digest, offset: s.start });
98
+ cursor = s.end;
99
+ }
100
+ out += text.slice(cursor);
101
+ return { text: out, events };
102
+ }
103
+ /**
104
+ * Redact secrets from `input`. Pure function — no I/O, no DB writes (callers
105
+ * aggregate `events` into `redaction_log` themselves).
106
+ */
107
+ export function redactText(input, opts = {}) {
108
+ const threshold = opts.entropyThreshold ?? 4.0;
109
+ const allEvents = [];
110
+ // ---- Stage 1: PEM blocks (multiline, first) ----
111
+ let text = input;
112
+ {
113
+ const guard = protectedRanges(text);
114
+ const spans = runDetector(text, PEM_DETECTOR, guard);
115
+ const applied = applySpans(text, spans);
116
+ text = applied.text;
117
+ allEvents.push(...applied.events);
118
+ }
119
+ // ---- Stage 2: vendor/pattern detectors + custom config patterns ----
120
+ {
121
+ const guard = protectedRanges(text);
122
+ const detectors = [
123
+ ...PATTERN_DETECTORS,
124
+ ...(opts.customPatterns ?? []).map(customDetector),
125
+ ];
126
+ let spans = [];
127
+ for (const detector of detectors) {
128
+ try {
129
+ spans = spans.concat(runDetector(text, detector, guard));
130
+ }
131
+ catch {
132
+ // Invalid custom regex from config — skip it rather than crash ingest.
133
+ }
134
+ }
135
+ const applied = applySpans(text, spans);
136
+ text = applied.text;
137
+ allEvents.push(...applied.events);
138
+ }
139
+ // ---- Stage 3: entropy detector over what remains ----
140
+ {
141
+ const guard = protectedRanges(text);
142
+ const entropySpans = findEntropySecrets(text, threshold)
143
+ .filter(m => !overlapsAny(m.start, m.end, guard))
144
+ .map(m => ({ type: 'high_entropy', start: m.start, end: m.end, value: m.value }));
145
+ const applied = applySpans(text, entropySpans);
146
+ text = applied.text;
147
+ allEvents.push(...applied.events);
148
+ }
149
+ return { text, events: allEvents };
150
+ }
151
+ /**
152
+ * Choke-point helper for route handlers: applies config (enabled flag,
153
+ * entropy threshold, custom patterns) and is a no-op passthrough when
154
+ * `security.redaction.enabled` is false (SEC-9).
155
+ */
156
+ export function redactIfEnabled(input, config) {
157
+ if (!config.security.redaction.enabled) {
158
+ return { text: input, events: [] };
159
+ }
160
+ return redactText(input, {
161
+ entropyThreshold: config.security.redaction.entropyThreshold,
162
+ customPatterns: config.security.redaction.customPatterns,
163
+ });
164
+ }
165
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/redact/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Score fusion for hybrid BM25 + cosine + importance + freshness ranking.
3
+ *
4
+ * Formula: raw = α·norm(bm25) + β·norm(cosine) + γ·importance + δ·freshness
5
+ * + ε·usefulness + ζ·entityBonus
6
+ * score = raw / (α + β + γ + δ + ε + ζ) ["active weight sum"]
7
+ *
8
+ * Wire-contract invariant: score MUST land in [0,1] (plugin Zod schema,
9
+ * memory-plugin#8) so the daemon response validates. Every component input
10
+ * is already bounded to [0,1] (normBm25/normCosine via normalizeScores,
11
+ * importance/freshness/usefulness by construction, entityBonus ∈ {0,1} —
12
+ * see entityBonusForQuery), so any convex-combination weight config keeps
13
+ * `raw` in [0, weightSum]; dividing by weightSum restores [0,1] even when
14
+ * the configured weights don't sum to 1 (default config sums to 1.1 — see
15
+ * config.ts search defaults — which without this normalization pushed
16
+ * perfect-match scores to ~1.04 and broke the wire contract).
17
+ *
18
+ * Defaults: α=β=0.4, γ=δ=ε=0.1, ζ=0. Pulled from config.search. The
19
+ * usefulness component (ADR-010 v1.x) is Laplace-smoothed to a neutral 0.5
20
+ * for atoms with no recall_used/memory_corrected signal, so ε only
21
+ * reshuffles atoms that have actually accumulated evidence.
22
+ *
23
+ * ζ (zeta, FEAT-402 slice 2 AC-6) is a distinct entity-relevance bonus: 1
24
+ * when a candidate is entity-linked to an entity mentioned in the query
25
+ * text, 0 otherwise — no-signal default is 0 (not usefulness's neutral 0.5),
26
+ * so with the default `zeta=0` weight the term contributes exactly 0 to
27
+ * every candidate and ranking order is byte-identical to pre-AC-6 behavior
28
+ * (see tests/search/fuse.test.ts zeta=0 no-op case and the eval harness
29
+ * zeta=0 snapshot test).
30
+ *
31
+ * Normalizing by the active weight sum is a per-call constant scalar (the
32
+ * weights config doesn't vary across hits in the same search), so it never
33
+ * changes relative ranking order for a fixed weight config — it is a
34
+ * monotone rescaling, applied uniformly to every candidate.
35
+ */
36
+ export interface FuseInput {
37
+ normBm25: number;
38
+ normCosine: number;
39
+ importance: number;
40
+ freshness: number;
41
+ /** ADR-010 usefulness score [0,1]; 0.5 = no signal. */
42
+ usefulness?: number;
43
+ /** FEAT-402 AC-6 entity-relevance bonus, 0 or 1; 0 = no signal (unlike usefulness). */
44
+ entityBonus?: number;
45
+ alpha: number;
46
+ beta: number;
47
+ gamma: number;
48
+ delta: number;
49
+ /** usefulness weight; omitted = 0 (usefulness ignored) */
50
+ epsilon?: number;
51
+ /** entity-bonus weight; omitted or 0 = OFF (AC-6 default, ranking unchanged) */
52
+ zeta?: number;
53
+ }
54
+ /**
55
+ * Normalize an array of raw scores to [0,1] range.
56
+ * If all values are equal (range = 0) returns all ones.
57
+ */
58
+ export declare function normalizeScores(scores: number[]): number[];
59
+ /**
60
+ * Compute fused score for a single hit whose components are already normalized.
61
+ *
62
+ * Returns a value in [0,1]: the weighted sum is divided by the sum of the
63
+ * active weights so the result stays in-range even when the configured
64
+ * weights don't sum to 1 (see module doc comment). Guards the degenerate
65
+ * all-zero-weights case by returning 0 rather than dividing by zero.
66
+ */
67
+ export declare function fuseScores(input: FuseInput): number;
68
+ export interface RawHit {
69
+ id: string;
70
+ bm25?: number;
71
+ cosine?: number;
72
+ importance: number;
73
+ created_at: number;
74
+ }
75
+ export interface FusedHit {
76
+ id: string;
77
+ score: number;
78
+ source: 'fts' | 'vec' | 'both';
79
+ }
80
+ /**
81
+ * Fuse a set of raw BM25 hits + cosine hits into a single ranked list.
82
+ *
83
+ * @param ftsHits Hits from FTS5, each with bm25 (negative in SQLite — we negate before normalization)
84
+ * @param vecHits Hits from vector search, each with cosine score [0,1] (1/(1+distance))
85
+ * @param metas Map of id → {importance, created_at} for all candidate ids
86
+ * @param weights α,β,γ,δ
87
+ * @param nowMs Current epoch ms for freshness computation
88
+ * @param freshnessDecayDays Half-life of freshness decay in days (default 30)
89
+ * @param usefulness Optional id → usefulness score [0,1] (ADR-010); missing ids default to 0.5
90
+ * @param entityBonus Optional id → entity-relevance bonus (FEAT-402 AC-6); missing ids default to 0
91
+ */
92
+ export declare function fuseHits(ftsHits: Array<{
93
+ id: string;
94
+ bm25: number;
95
+ }>, vecHits: Array<{
96
+ id: string;
97
+ cosine: number;
98
+ }>, metas: Map<string, {
99
+ importance: number;
100
+ created_at: number;
101
+ }>, weights: {
102
+ alpha: number;
103
+ beta: number;
104
+ gamma: number;
105
+ delta: number;
106
+ epsilon?: number;
107
+ zeta?: number;
108
+ }, nowMs: number, freshnessDecayDays?: number, usefulness?: Map<string, number>, entityBonus?: Map<string, number>): FusedHit[];
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Score fusion for hybrid BM25 + cosine + importance + freshness ranking.
3
+ *
4
+ * Formula: raw = α·norm(bm25) + β·norm(cosine) + γ·importance + δ·freshness
5
+ * + ε·usefulness + ζ·entityBonus
6
+ * score = raw / (α + β + γ + δ + ε + ζ) ["active weight sum"]
7
+ *
8
+ * Wire-contract invariant: score MUST land in [0,1] (plugin Zod schema,
9
+ * memory-plugin#8) so the daemon response validates. Every component input
10
+ * is already bounded to [0,1] (normBm25/normCosine via normalizeScores,
11
+ * importance/freshness/usefulness by construction, entityBonus ∈ {0,1} —
12
+ * see entityBonusForQuery), so any convex-combination weight config keeps
13
+ * `raw` in [0, weightSum]; dividing by weightSum restores [0,1] even when
14
+ * the configured weights don't sum to 1 (default config sums to 1.1 — see
15
+ * config.ts search defaults — which without this normalization pushed
16
+ * perfect-match scores to ~1.04 and broke the wire contract).
17
+ *
18
+ * Defaults: α=β=0.4, γ=δ=ε=0.1, ζ=0. Pulled from config.search. The
19
+ * usefulness component (ADR-010 v1.x) is Laplace-smoothed to a neutral 0.5
20
+ * for atoms with no recall_used/memory_corrected signal, so ε only
21
+ * reshuffles atoms that have actually accumulated evidence.
22
+ *
23
+ * ζ (zeta, FEAT-402 slice 2 AC-6) is a distinct entity-relevance bonus: 1
24
+ * when a candidate is entity-linked to an entity mentioned in the query
25
+ * text, 0 otherwise — no-signal default is 0 (not usefulness's neutral 0.5),
26
+ * so with the default `zeta=0` weight the term contributes exactly 0 to
27
+ * every candidate and ranking order is byte-identical to pre-AC-6 behavior
28
+ * (see tests/search/fuse.test.ts zeta=0 no-op case and the eval harness
29
+ * zeta=0 snapshot test).
30
+ *
31
+ * Normalizing by the active weight sum is a per-call constant scalar (the
32
+ * weights config doesn't vary across hits in the same search), so it never
33
+ * changes relative ranking order for a fixed weight config — it is a
34
+ * monotone rescaling, applied uniformly to every candidate.
35
+ */
36
+ /**
37
+ * Normalize an array of raw scores to [0,1] range.
38
+ * If all values are equal (range = 0) returns all ones.
39
+ */
40
+ export function normalizeScores(scores) {
41
+ if (scores.length === 0)
42
+ return [];
43
+ const min = Math.min(...scores);
44
+ const max = Math.max(...scores);
45
+ const range = max - min;
46
+ // All-equal (including single-hit): every score is equally the best match
47
+ // within this component. Returning 0 would erase the component's signal
48
+ // entirely (a lone FTS hit would lose its whole BM25 contribution).
49
+ if (range === 0)
50
+ return scores.map(() => 1);
51
+ return scores.map(s => (s - min) / range);
52
+ }
53
+ /**
54
+ * Compute fused score for a single hit whose components are already normalized.
55
+ *
56
+ * Returns a value in [0,1]: the weighted sum is divided by the sum of the
57
+ * active weights so the result stays in-range even when the configured
58
+ * weights don't sum to 1 (see module doc comment). Guards the degenerate
59
+ * all-zero-weights case by returning 0 rather than dividing by zero.
60
+ */
61
+ export function fuseScores(input) {
62
+ const raw = input.alpha * input.normBm25 +
63
+ input.beta * input.normCosine +
64
+ input.gamma * input.importance +
65
+ input.delta * input.freshness +
66
+ (input.epsilon ?? 0) * (input.usefulness ?? 0.5) +
67
+ (input.zeta ?? 0) * (input.entityBonus ?? 0);
68
+ const weightSum = input.alpha + input.beta + input.gamma + input.delta +
69
+ (input.epsilon ?? 0) + (input.zeta ?? 0);
70
+ if (weightSum === 0)
71
+ return 0;
72
+ // Defense-in-depth: components are bounded to [0,1] at their sources, but a
73
+ // future regression there must degrade to a capped score, not a wire-contract
74
+ // violation that makes plugin clients reject the whole response.
75
+ return Math.min(1, raw / weightSum);
76
+ }
77
+ /**
78
+ * Fuse a set of raw BM25 hits + cosine hits into a single ranked list.
79
+ *
80
+ * @param ftsHits Hits from FTS5, each with bm25 (negative in SQLite — we negate before normalization)
81
+ * @param vecHits Hits from vector search, each with cosine score [0,1] (1/(1+distance))
82
+ * @param metas Map of id → {importance, created_at} for all candidate ids
83
+ * @param weights α,β,γ,δ
84
+ * @param nowMs Current epoch ms for freshness computation
85
+ * @param freshnessDecayDays Half-life of freshness decay in days (default 30)
86
+ * @param usefulness Optional id → usefulness score [0,1] (ADR-010); missing ids default to 0.5
87
+ * @param entityBonus Optional id → entity-relevance bonus (FEAT-402 AC-6); missing ids default to 0
88
+ */
89
+ export function fuseHits(ftsHits, vecHits, metas, weights, nowMs, freshnessDecayDays = 30, usefulness, entityBonus) {
90
+ // Build per-id raw maps
91
+ const ftsMap = new Map(ftsHits.map(h => [h.id, h.bm25]));
92
+ const vecMap = new Map(vecHits.map(h => [h.id, h.cosine]));
93
+ // Union of all candidate ids
94
+ const ids = new Set([...ftsMap.keys(), ...vecMap.keys()]);
95
+ // Normalize BM25 — SQLite bm25() returns negative values (lower = better match)
96
+ // Negate so higher positive = better, then normalize
97
+ const rawBm25Values = ftsHits.map(h => -h.bm25); // negate
98
+ const normBm25Arr = normalizeScores(rawBm25Values);
99
+ const normBm25Map = new Map(ftsHits.map((h, i) => [h.id, normBm25Arr[i] ?? 0]));
100
+ // Normalize cosine scores
101
+ const rawCosineValues = vecHits.map(h => h.cosine);
102
+ const normCosineArr = normalizeScores(rawCosineValues);
103
+ const normCosineMap = new Map(vecHits.map((h, i) => [h.id, normCosineArr[i] ?? 0]));
104
+ // Freshness: exponential decay, half-life = freshnessDecayDays
105
+ const decayMs = freshnessDecayDays * 24 * 60 * 60 * 1000;
106
+ const results = [];
107
+ for (const id of ids) {
108
+ const meta = metas.get(id);
109
+ const importance = meta?.importance ?? 0.5;
110
+ const createdAt = meta?.created_at ?? nowMs;
111
+ const ageDays = (nowMs - createdAt) / (24 * 60 * 60 * 1000);
112
+ // Clamp to 1: a future created_at (SaaS-sync clock skew — puller.ts stores
113
+ // remote-minted timestamps verbatim) makes ageDays negative and exp() > 1,
114
+ // which would push the fused score past the [0,1] wire contract.
115
+ const freshness = Math.min(1, Math.exp(-ageDays / (decayMs / (24 * 60 * 60 * 1000))));
116
+ const normBm25 = normBm25Map.get(id) ?? 0;
117
+ const normCosine = normCosineMap.get(id) ?? 0;
118
+ const score = fuseScores({
119
+ normBm25,
120
+ normCosine,
121
+ importance,
122
+ freshness,
123
+ usefulness: usefulness?.get(id),
124
+ entityBonus: entityBonus?.get(id),
125
+ ...weights
126
+ });
127
+ const inFts = ftsMap.has(id);
128
+ const inVec = vecMap.has(id);
129
+ const source = inFts && inVec ? 'both' : inFts ? 'fts' : 'vec';
130
+ results.push({ id, score, source });
131
+ }
132
+ results.sort((a, b) => b.score - a.score);
133
+ return results;
134
+ }
135
+ //# sourceMappingURL=fuse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fuse.js","sourceRoot":"","sources":["../../src/search/fuse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAqBH;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,MAAgB;IAC9C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACnC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;IAChC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;IAChC,MAAM,KAAK,GAAG,GAAG,GAAG,GAAG,CAAC;IACxB,0EAA0E;IAC1E,wEAAwE;IACxE,oEAAoE;IACpE,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5C,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;AAC5C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,KAAgB;IACzC,MAAM,GAAG,GACP,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,QAAQ;QAC5B,KAAK,CAAC,IAAI,GAAI,KAAK,CAAC,UAAU;QAC9B,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,UAAU;QAC9B,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,SAAS;QAC7B,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,IAAI,GAAG,CAAC;QAChD,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC;IAE/C,MAAM,SAAS,GACb,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK;QACpD,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;IAE3C,IAAI,SAAS,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAC9B,4EAA4E;IAC5E,8EAA8E;IAC9E,iEAAiE;IACjE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,SAAS,CAAC,CAAC;AACtC,CAAC;AAgBD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,QAAQ,CACtB,OAA4C,EAC5C,OAA8C,EAC9C,KAA8D,EAC9D,OAAuG,EACvG,KAAa,EACb,kBAAkB,GAAG,EAAE,EACvB,UAAgC,EAChC,WAAiC;IAEjC,wBAAwB;IACxB,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACzD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAE3D,6BAA6B;IAC7B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,EAAE,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAE1D,gFAAgF;IAChF,qDAAqD;IACrD,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAE,SAAS;IAC3D,MAAM,WAAW,GAAG,eAAe,CAAC,aAAa,CAAC,CAAC;IACnD,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,OAAO,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;IAEhF,0BAA0B;IAC1B,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACnD,MAAM,aAAa,GAAG,eAAe,CAAC,eAAe,CAAC,CAAC;IACvD,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,OAAO,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;IAEpF,+DAA+D;IAC/D,MAAM,OAAO,GAAG,kBAAkB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAEzD,MAAM,OAAO,GAAe,EAAE,CAAC;IAE/B,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;QACrB,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC3B,MAAM,UAAU,GAAG,IAAI,EAAE,UAAU,IAAI,GAAG,CAAC;QAC3C,MAAM,SAAS,GAAG,IAAI,EAAE,UAAU,IAAI,KAAK,CAAC;QAC5C,MAAM,OAAO,GAAG,CAAC,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAC5D,2EAA2E;QAC3E,2EAA2E;QAC3E,iEAAiE;QACjE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,GAAG,CAAC,OAAO,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAEtF,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QAC1C,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QAE9C,MAAM,KAAK,GAAG,UAAU,CAAC;YACvB,QAAQ;YACR,UAAU;YACV,UAAU;YACV,SAAS;YACT,UAAU,EAAE,UAAU,EAAE,GAAG,CAAC,EAAE,CAAC;YAC/B,WAAW,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE,CAAC;YACjC,GAAG,OAAO;SACX,CAAC,CAAC;QAEH,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC7B,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC7B,MAAM,MAAM,GAAuB,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;QAEnF,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACtC,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAC1C,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Query string parser for AstraMemory search.
3
+ *
4
+ * Parses structured filter tokens from a query string:
5
+ * type:decision → filters.type = ['decision']
6
+ * repo:my-repo → filters.repo = 'my-repo'
7
+ * project:wave2 → filters.project = 'wave2'
8
+ * since:7d → filters.since = epoch ms 7 days ago
9
+ * since:24h → filters.since = epoch ms 24 hours ago
10
+ * since:Nh → filters.since = epoch ms N hours ago
11
+ *
12
+ * Unknown prefixes are left in the bare query text (not applied as filters).
13
+ * Design choice: unknown filters are silently ignored (not rejected as 400)
14
+ * because the CLI passes arbitrary user text and we prefer forgiving parse.
15
+ */
16
+ export interface ParsedQuery {
17
+ /** Bare search terms with filter tokens removed */
18
+ q: string;
19
+ /** Extracted structured filters */
20
+ filters: {
21
+ type?: string[];
22
+ repo?: string;
23
+ project?: string;
24
+ /** Epoch ms lower bound for created_at */
25
+ since?: number;
26
+ };
27
+ }
28
+ export declare function parseQuery(raw: string): ParsedQuery;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Query string parser for AstraMemory search.
3
+ *
4
+ * Parses structured filter tokens from a query string:
5
+ * type:decision → filters.type = ['decision']
6
+ * repo:my-repo → filters.repo = 'my-repo'
7
+ * project:wave2 → filters.project = 'wave2'
8
+ * since:7d → filters.since = epoch ms 7 days ago
9
+ * since:24h → filters.since = epoch ms 24 hours ago
10
+ * since:Nh → filters.since = epoch ms N hours ago
11
+ *
12
+ * Unknown prefixes are left in the bare query text (not applied as filters).
13
+ * Design choice: unknown filters are silently ignored (not rejected as 400)
14
+ * because the CLI passes arbitrary user text and we prefer forgiving parse.
15
+ */
16
+ const KNOWN_FILTERS = new Set(['type', 'repo', 'project', 'since']);
17
+ /**
18
+ * Parse a duration string like "7d" or "24h" into milliseconds.
19
+ * Returns null if format is unrecognized.
20
+ */
21
+ function parseDuration(value) {
22
+ const dMatch = value.match(/^(\d+)d$/);
23
+ if (dMatch)
24
+ return Number(dMatch[1]) * 24 * 60 * 60 * 1000;
25
+ const hMatch = value.match(/^(\d+)h$/);
26
+ if (hMatch)
27
+ return Number(hMatch[1]) * 60 * 60 * 1000;
28
+ return null;
29
+ }
30
+ export function parseQuery(raw) {
31
+ const filters = {};
32
+ const bareTerms = [];
33
+ const tokens = raw.trim().split(/\s+/);
34
+ for (const token of tokens) {
35
+ if (!token)
36
+ continue;
37
+ const colonIdx = token.indexOf(':');
38
+ if (colonIdx > 0) {
39
+ const key = token.slice(0, colonIdx);
40
+ const val = token.slice(colonIdx + 1);
41
+ if (KNOWN_FILTERS.has(key) && val) {
42
+ switch (key) {
43
+ case 'type':
44
+ filters.type = filters.type ? [...filters.type, val] : [val];
45
+ break;
46
+ case 'repo':
47
+ filters.repo = val;
48
+ break;
49
+ case 'project':
50
+ filters.project = val;
51
+ break;
52
+ case 'since': {
53
+ const durationMs = parseDuration(val);
54
+ if (durationMs !== null) {
55
+ filters.since = Date.now() - durationMs;
56
+ }
57
+ // If format is unrecognized, drop silently (treat as ignored)
58
+ break;
59
+ }
60
+ }
61
+ // Known filter processed — do not include in bare query
62
+ continue;
63
+ }
64
+ }
65
+ // Unknown token (no colon, or unknown prefix) → include in bare query
66
+ bareTerms.push(token);
67
+ }
68
+ return { q: bareTerms.join(' '), filters };
69
+ }
70
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/search/query.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAeH,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;AAEpE;;;GAGG;AACH,SAAS,aAAa,CAAC,KAAa;IAClC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACvC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAC3D,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACvC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IACtD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,MAAM,SAAS,GAAa,EAAE,CAAC;IAE/B,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAEvC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YACjB,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;YACrC,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;YACtC,IAAI,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;gBAClC,QAAQ,GAAG,EAAE,CAAC;oBACZ,KAAK,MAAM;wBACT,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;wBAC7D,MAAM;oBACR,KAAK,MAAM;wBACT,OAAO,CAAC,IAAI,GAAG,GAAG,CAAC;wBACnB,MAAM;oBACR,KAAK,SAAS;wBACZ,OAAO,CAAC,OAAO,GAAG,GAAG,CAAC;wBACtB,MAAM;oBACR,KAAK,OAAO,CAAC,CAAC,CAAC;wBACb,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;wBACtC,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;4BACxB,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC;wBAC1C,CAAC;wBACD,8DAA8D;wBAC9D,MAAM;oBACR,CAAC;gBACH,CAAC;gBACD,wDAAwD;gBACxD,SAAS;YACX,CAAC;QACH,CAAC;QACD,sEAAsE;QACtE,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;IAED,OAAO,EAAE,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,CAAC;AAC7C,CAAC"}