@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,86 @@
1
+ /**
2
+ * Entity-only LLM extraction (FEAT-402 AC-7) — used by the `entity-backfill`
3
+ * command to extract entities from ALREADY-DISTILLED memory text, without
4
+ * re-running the full 8-stage distill pipeline (no re-chunking, no atom
5
+ * re-extraction, memory text and hash untouched). Distill-time extraction
6
+ * (stage 5, src/distill/stages/05-extract.ts) instead emits entities inline
7
+ * on each atom in the SAME LLM call — this module exists only for the
8
+ * backfill's one-shot pass over pre-existing rows that predate that stage.
9
+ *
10
+ * Deliberately lenient: unlike stage 5's extractChunk (which throws
11
+ * DeterministicError on parse failure and poisons the job), a bad response
12
+ * here just returns [] and lets the caller log + move on. The corpus is
13
+ * scanned by "not yet linked" (src/entity/backfill.ts), so a memory that got
14
+ * an empty/failed extraction this run remains a valid candidate on the next
15
+ * run — the backfill is naturally resumable without a checkpoint table.
16
+ */
17
+ import { z } from 'zod';
18
+ import { AtomEntitySchema } from '../distill/prompts/extract.js';
19
+ import { BudgetTracker } from '../budget/tracker.js';
20
+ const LenientEntitiesSchema = z.object({ entities: z.array(z.unknown()) });
21
+ export const ENTITY_ONLY_SYSTEM_PROMPT = `You identify named things mentioned in a short piece of durable knowledge extracted from an AI coding agent transcript.
22
+
23
+ Output STRICT JSON matching:
24
+ {
25
+ "entities": [
26
+ { "name": "<named thing mentioned>", "kind": "product" | "tech" | "person" | "org" | "repo" | "concept" }
27
+ ]
28
+ }
29
+
30
+ kind is one of:
31
+ - product: a named product or app (e.g. "AstraMemory", "GitHub Copilot")
32
+ - tech: a language/framework/library/tool/protocol (e.g. "Postgres", "TypeScript", "sqlite-vec")
33
+ - person: a named individual
34
+ - org: a company or organization
35
+ - repo: a named git repository or codebase
36
+ - concept: a named pattern, architecture, or idea (e.g. "bitemporal model", "CRDT")
37
+
38
+ List every specific named thing the text is ABOUT — not every word. If nothing specific is named, return {"entities": []}.`;
39
+ /**
40
+ * Extract entities from one piece of already-distilled memory text.
41
+ * Returns [] (never throws) on budget-exceeded, transport, or parse failure
42
+ * — callers decide whether/how to surface that (the backfill CLI counts it
43
+ * as "skipped", not "failed").
44
+ */
45
+ export async function extractEntitiesForText(text, provider, budget, capUsd) {
46
+ if (!text.trim())
47
+ return [];
48
+ const promptChars = ENTITY_ONLY_SYSTEM_PROMPT.length + text.length;
49
+ const estimateUsd = BudgetTracker.estimateUsd(promptChars, 0.000002, 0.000002);
50
+ if (!budget.canSpend(estimateUsd, capUsd))
51
+ return [];
52
+ let raw;
53
+ let usageUsd;
54
+ try {
55
+ const result = await provider.chat([
56
+ { role: 'system', content: ENTITY_ONLY_SYSTEM_PROMPT },
57
+ { role: 'user', content: `Identify entities in this text:\n\n${text}` },
58
+ ], { temperature: 0.1, json: true, maxTokens: 400 });
59
+ raw = result.text;
60
+ usageUsd = result.usage.usd;
61
+ }
62
+ catch {
63
+ return [];
64
+ }
65
+ budget.record(usageUsd);
66
+ return tryParseEntities(raw);
67
+ }
68
+ function tryParseEntities(raw) {
69
+ try {
70
+ let text = raw.trim();
71
+ text = text.replace(/^```(?:json)?\n?/i, '').replace(/\n?```\s*$/i, '').trim();
72
+ const start = text.indexOf('{');
73
+ const end = text.lastIndexOf('}');
74
+ if (start === -1 || end === -1)
75
+ return [];
76
+ const parsed = JSON.parse(text.slice(start, end + 1));
77
+ const wrapper = LenientEntitiesSchema.safeParse(parsed);
78
+ if (!wrapper.success)
79
+ return [];
80
+ return wrapper.data.entities.filter((e) => AtomEntitySchema.safeParse(e).success);
81
+ }
82
+ catch {
83
+ return [];
84
+ }
85
+ }
86
+ //# sourceMappingURL=extract-entities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-entities.js","sourceRoot":"","sources":["../../src/entity/extract-entities.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Entity name normalization — the single seam AC-9 requires.
3
+ *
4
+ * Every caller that resolves an entity name to an `entities.id` (distill-time
5
+ * extraction in stage 8, the entity-backfill command, and — in slice 2 — the
6
+ * search `entity=` filter) MUST go through this function first. Today it is
7
+ * lowercase + trim + whitespace-collapse only, so "Postgres" / "postgres" /
8
+ * " Postgres " collapse to the same normalized name and therefore the same
9
+ * `entities.id` via the UNIQUE constraint on `entities.name`.
10
+ *
11
+ * An alias table ("pg" -> "postgres", "postgres flexible" -> "postgres") is
12
+ * explicitly deferred (FEAT-402 AC-9, roadmap W4.x) but this function is
13
+ * where it plugs in later — swap the body for a dictionary/DB lookup and
14
+ * every call site (extraction, backfill, future query filter) inherits it
15
+ * without a single call-site edit.
16
+ */
17
+ export declare function normalizeEntityName(raw: string): string;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Entity name normalization — the single seam AC-9 requires.
3
+ *
4
+ * Every caller that resolves an entity name to an `entities.id` (distill-time
5
+ * extraction in stage 8, the entity-backfill command, and — in slice 2 — the
6
+ * search `entity=` filter) MUST go through this function first. Today it is
7
+ * lowercase + trim + whitespace-collapse only, so "Postgres" / "postgres" /
8
+ * " Postgres " collapse to the same normalized name and therefore the same
9
+ * `entities.id` via the UNIQUE constraint on `entities.name`.
10
+ *
11
+ * An alias table ("pg" -> "postgres", "postgres flexible" -> "postgres") is
12
+ * explicitly deferred (FEAT-402 AC-9, roadmap W4.x) but this function is
13
+ * where it plugs in later — swap the body for a dictionary/DB lookup and
14
+ * every call site (extraction, backfill, future query filter) inherits it
15
+ * without a single call-site edit.
16
+ */
17
+ export function normalizeEntityName(raw) {
18
+ return raw.trim().toLowerCase().replace(/\s+/g, ' ');
19
+ }
20
+ //# sourceMappingURL=normalize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../src/entity/normalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAW;IAC7C,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AACvD,CAAC"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * ADR-005 retrieval eval harness.
3
+ *
4
+ * Seeds the shared eval corpus (contracts/fixtures/eval/corpus.json) into a
5
+ * live database, runs the shared query set through the local search engine,
6
+ * and scores recall@k / NDCG@k against the graded relevance judgments.
7
+ *
8
+ * Known v1 engine gaps, handled explicitly rather than silently:
9
+ * - per-query `mode` (keyword|semantic|hybrid) is advisory only; the local
10
+ * engine always runs its hybrid FTS+vector path. The mode is echoed in
11
+ * the per-query report so a future mode-routing engine can be compared.
12
+ *
13
+ * FEAT-401: `as_of` (bitemporal time-travel) is now supported end-to-end —
14
+ * seedEvalCorpus backfills each atom's declared valid_from (in addition to
15
+ * valid_to) so corpus atoms carry their fixture-declared validity windows
16
+ * rather than the insert-time "now", and runRetrievalEval forwards
17
+ * `filters.as_of` straight into search() instead of skipping the query.
18
+ *
19
+ * FEAT-402 slice 2 (AC-8): each corpus atom may declare an `entities: string[]`
20
+ * array (already present on every fixture atom since slice 1). seedEvalCorpus
21
+ * links them via EntityRepo the same way distill-time extraction does, and a
22
+ * query may declare `filters.entity` to exercise the AC-4 pre-fusion
23
+ * intersection end-to-end. Fixture entities have no `kind` — seeded with the
24
+ * generic 'concept' kind, which is irrelevant to filtering (name-only lookup).
25
+ */
26
+ import type { DB } from '../storage/db.js';
27
+ import type { EmbedProvider } from '../contracts/index.js';
28
+ import { type GradedRelevance } from './metrics.js';
29
+ export interface EvalAtom {
30
+ id: string;
31
+ type: string;
32
+ text: string;
33
+ evidence: string | string[] | null;
34
+ confidence: number;
35
+ importance: number;
36
+ provenance: {
37
+ session_id: string;
38
+ repo: string;
39
+ project: string;
40
+ };
41
+ /** Bitemporal valid-time start (ADR-001). Optional for pre-FEAT-401 fixtures. */
42
+ valid_from?: string;
43
+ valid_to: string | null;
44
+ scope: string;
45
+ content_hash: string;
46
+ /** FEAT-402 slice 2 AC-8: entity names linked to this atom (kind-less — seeded as 'concept'). */
47
+ entities?: string[];
48
+ }
49
+ export interface EvalQuery {
50
+ id: string;
51
+ text: string;
52
+ mode: string;
53
+ filters: {
54
+ type?: string[];
55
+ as_of?: string;
56
+ entity?: string;
57
+ };
58
+ graded_relevant: GradedRelevance[];
59
+ }
60
+ export interface EvalCorpus {
61
+ atoms: EvalAtom[];
62
+ }
63
+ export interface EvalQuerySet {
64
+ queries: EvalQuery[];
65
+ }
66
+ export interface QueryResult {
67
+ id: string;
68
+ mode: string;
69
+ skipped: string | null;
70
+ recall: number | null;
71
+ ndcg: number | null;
72
+ rankedAtomIds: string[];
73
+ }
74
+ export interface EvalReport {
75
+ k: number;
76
+ perQuery: QueryResult[];
77
+ evaluated: number;
78
+ skipped: number;
79
+ meanRecall: number;
80
+ meanNdcg: number;
81
+ }
82
+ /**
83
+ * Insert every corpus atom into the DB (memories + FTS via trigger + vector
84
+ * index). Returns memory-id → atom-id so engine hits can be scored against
85
+ * the corpus judgments. Atoms with a non-null valid_to are marked
86
+ * invalidated after insert, matching their bitemporal state.
87
+ */
88
+ export declare function seedEvalCorpus(db: DB, embed: EmbedProvider, corpus: EvalCorpus): Promise<Map<string, string>>;
89
+ export declare function runRetrievalEval(db: DB, embed: EmbedProvider, weights: {
90
+ alpha: number;
91
+ beta: number;
92
+ gamma: number;
93
+ delta: number;
94
+ epsilon: number;
95
+ zeta?: number;
96
+ }, corpus: EvalCorpus, querySet: EvalQuerySet, k?: number): Promise<EvalReport>;
@@ -0,0 +1,119 @@
1
+ /**
2
+ * ADR-005 retrieval eval harness.
3
+ *
4
+ * Seeds the shared eval corpus (contracts/fixtures/eval/corpus.json) into a
5
+ * live database, runs the shared query set through the local search engine,
6
+ * and scores recall@k / NDCG@k against the graded relevance judgments.
7
+ *
8
+ * Known v1 engine gaps, handled explicitly rather than silently:
9
+ * - per-query `mode` (keyword|semantic|hybrid) is advisory only; the local
10
+ * engine always runs its hybrid FTS+vector path. The mode is echoed in
11
+ * the per-query report so a future mode-routing engine can be compared.
12
+ *
13
+ * FEAT-401: `as_of` (bitemporal time-travel) is now supported end-to-end —
14
+ * seedEvalCorpus backfills each atom's declared valid_from (in addition to
15
+ * valid_to) so corpus atoms carry their fixture-declared validity windows
16
+ * rather than the insert-time "now", and runRetrievalEval forwards
17
+ * `filters.as_of` straight into search() instead of skipping the query.
18
+ *
19
+ * FEAT-402 slice 2 (AC-8): each corpus atom may declare an `entities: string[]`
20
+ * array (already present on every fixture atom since slice 1). seedEvalCorpus
21
+ * links them via EntityRepo the same way distill-time extraction does, and a
22
+ * query may declare `filters.entity` to exercise the AC-4 pre-fusion
23
+ * intersection end-to-end. Fixture entities have no `kind` — seeded with the
24
+ * generic 'concept' kind, which is irrelevant to filtering (name-only lookup).
25
+ */
26
+ import { MemoryRepo } from '../storage/memories.js';
27
+ import { EntityRepo } from '../storage/entities.js';
28
+ import { SqliteVecStore } from '../vector/sqlite-vec.js';
29
+ import { search, parseAsOf } from '../search/search.js';
30
+ import { recallAtK, ndcgAtK } from './metrics.js';
31
+ /**
32
+ * Insert every corpus atom into the DB (memories + FTS via trigger + vector
33
+ * index). Returns memory-id → atom-id so engine hits can be scored against
34
+ * the corpus judgments. Atoms with a non-null valid_to are marked
35
+ * invalidated after insert, matching their bitemporal state.
36
+ */
37
+ export async function seedEvalCorpus(db, embed, corpus) {
38
+ const repo = new MemoryRepo(db);
39
+ const entityRepo = new EntityRepo(db);
40
+ const vecStore = new SqliteVecStore(db, embed.dim);
41
+ const memToAtom = new Map();
42
+ for (const atom of corpus.atoms) {
43
+ const memId = repo.insert({
44
+ type: atom.type,
45
+ text: atom.text,
46
+ normalized_text: atom.text.toLowerCase(),
47
+ repo: atom.provenance.repo,
48
+ project: atom.provenance.project,
49
+ branch: null,
50
+ agent: null,
51
+ // corpus session ids don't exist in the sessions table (FK) — seed detached
52
+ session_id: null,
53
+ hash: atom.content_hash,
54
+ source_hash: null,
55
+ importance: atom.importance,
56
+ confidence: atom.confidence,
57
+ evidence: Array.isArray(atom.evidence) ? atom.evidence.join('; ') : atom.evidence,
58
+ scope: atom.scope,
59
+ });
60
+ // FEAT-401: backfill the fixture-declared valid_from/valid_to so corpus
61
+ // atoms carry their real bitemporal windows instead of insert-time "now"
62
+ // — required for as_of queries (q6) to resolve against the right
63
+ // generation. valid_from mirrors created_at on a fresh insert, so only
64
+ // rewrite it when the fixture declares a different instant.
65
+ if (atom.valid_from !== undefined) {
66
+ db.prepare('UPDATE memories SET valid_from = ? WHERE id = ?')
67
+ .run(Date.parse(atom.valid_from), memId);
68
+ }
69
+ if (atom.valid_to !== null) {
70
+ db.prepare('UPDATE memories SET valid_to = ? WHERE id = ?')
71
+ .run(Date.parse(atom.valid_to), memId);
72
+ }
73
+ const [vec] = await embed.embed([atom.text]);
74
+ if (!vec)
75
+ throw new Error(`embed returned no vector for atom ${atom.id}`);
76
+ await vecStore.upsert(memId, vec);
77
+ memToAtom.set(memId, atom.id);
78
+ // FEAT-402 slice 2 AC-8: link fixture-declared entities the same way
79
+ // distill-time extraction does, so the `entity=` filter (AC-4) has real
80
+ // memory_entities rows to intersect against in the eval gate.
81
+ if (atom.entities && atom.entities.length > 0) {
82
+ entityRepo.linkEntitiesForMemory(memId, atom.entities.map(name => ({ name, kind: 'concept' })));
83
+ }
84
+ }
85
+ return memToAtom;
86
+ }
87
+ export async function runRetrievalEval(db, embed,
88
+ // epsilon (ADR-010 usefulness component) and zeta (FEAT-402 AC-6 entity
89
+ // bonus) are part of the fused score — the eval must exercise the same
90
+ // weight set production search uses, not a narrower structural subset
91
+ // that only works by accident.
92
+ weights, corpus, querySet, k = 10) {
93
+ const memToAtom = await seedEvalCorpus(db, embed, corpus);
94
+ const perQuery = [];
95
+ for (const q of querySet.queries) {
96
+ const as_of = q.filters.as_of !== undefined ? parseAsOf(q.filters.as_of) : undefined;
97
+ const hits = await search(q.text, { type: q.filters.type, as_of, entity: q.filters.entity }, k, { db, embed, weights });
98
+ const rankedAtomIds = hits
99
+ .map(h => memToAtom.get(h.id))
100
+ .filter((id) => id !== undefined);
101
+ perQuery.push({
102
+ id: q.id, mode: q.mode, skipped: null,
103
+ recall: recallAtK(rankedAtomIds, q.graded_relevant, k),
104
+ ndcg: ndcgAtK(rankedAtomIds, q.graded_relevant, k),
105
+ rankedAtomIds,
106
+ });
107
+ }
108
+ const evaluated = perQuery.filter(r => r.skipped === null);
109
+ const mean = (xs) => xs.length === 0 ? 0 : xs.reduce((a, b) => a + b, 0) / xs.length;
110
+ return {
111
+ k,
112
+ perQuery,
113
+ evaluated: evaluated.length,
114
+ skipped: perQuery.length - evaluated.length,
115
+ meanRecall: mean(evaluated.map(r => r.recall)),
116
+ meanNdcg: mean(evaluated.map(r => r.ndcg)),
117
+ };
118
+ }
119
+ //# sourceMappingURL=harness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harness.js","sourceRoot":"","sources":["../../src/eval/harness.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Retrieval quality metrics — ADR-005 eval harness.
3
+ *
4
+ * Both metrics operate on a ranked list of atom ids (engine output order)
5
+ * against a graded relevance list (0 = not relevant .. 3 = highly relevant).
6
+ */
7
+ export interface GradedRelevance {
8
+ atom_id: string;
9
+ grade: number;
10
+ }
11
+ /**
12
+ * recall@k — fraction of relevant atoms (grade > 0) that appear in the
13
+ * top-k ranked list. Returns 1 when the query has no relevant atoms
14
+ * (nothing to miss).
15
+ */
16
+ export declare function recallAtK(ranked: string[], graded: GradedRelevance[], k: number): number;
17
+ /**
18
+ * NDCG@k with exponential gain (2^grade - 1) and log2(rank+1) discount.
19
+ * Ideal DCG is computed from the graded list sorted descending, so a
20
+ * grade-0 entry contributes nothing to either side. Returns 1 when the
21
+ * query has no relevant atoms.
22
+ */
23
+ export declare function ndcgAtK(ranked: string[], graded: GradedRelevance[], k: number): number;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Retrieval quality metrics — ADR-005 eval harness.
3
+ *
4
+ * Both metrics operate on a ranked list of atom ids (engine output order)
5
+ * against a graded relevance list (0 = not relevant .. 3 = highly relevant).
6
+ */
7
+ /**
8
+ * recall@k — fraction of relevant atoms (grade > 0) that appear in the
9
+ * top-k ranked list. Returns 1 when the query has no relevant atoms
10
+ * (nothing to miss).
11
+ */
12
+ export function recallAtK(ranked, graded, k) {
13
+ const relevant = new Set(graded.filter(g => g.grade > 0).map(g => g.atom_id));
14
+ if (relevant.size === 0)
15
+ return 1;
16
+ const topK = ranked.slice(0, k);
17
+ let found = 0;
18
+ for (const id of topK) {
19
+ if (relevant.has(id))
20
+ found++;
21
+ }
22
+ return found / relevant.size;
23
+ }
24
+ /**
25
+ * NDCG@k with exponential gain (2^grade - 1) and log2(rank+1) discount.
26
+ * Ideal DCG is computed from the graded list sorted descending, so a
27
+ * grade-0 entry contributes nothing to either side. Returns 1 when the
28
+ * query has no relevant atoms.
29
+ */
30
+ export function ndcgAtK(ranked, graded, k) {
31
+ const gradeMap = new Map(graded.map(g => [g.atom_id, g.grade]));
32
+ const gain = (grade) => Math.pow(2, grade) - 1;
33
+ let dcg = 0;
34
+ ranked.slice(0, k).forEach((id, i) => {
35
+ dcg += gain(gradeMap.get(id) ?? 0) / Math.log2(i + 2);
36
+ });
37
+ const idealGrades = graded.map(g => g.grade).sort((a, b) => b - a).slice(0, k);
38
+ let idcg = 0;
39
+ idealGrades.forEach((grade, i) => {
40
+ idcg += gain(grade) / Math.log2(i + 2);
41
+ });
42
+ return idcg === 0 ? 1 : dcg / idcg;
43
+ }
44
+ //# sourceMappingURL=metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/eval/metrics.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,MAAgB,EAAE,MAAyB,EAAE,CAAS;IAC9E,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAC9E,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAClC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAChC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;QACtB,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,KAAK,EAAE,CAAC;IAChC,CAAC;IACD,OAAO,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC;AAC/B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,MAAgB,EAAE,MAAyB,EAAE,CAAS;IAC5E,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAChE,MAAM,IAAI,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAE/D,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE;QACnC,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/E,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,WAAW,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QAC/B,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC;AACrC,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Correlation ID — request_id propagation via AsyncLocalStorage.
3
+ *
4
+ * Usage:
5
+ * - On each incoming HTTP request: call runWithRequestId(uuid, fn)
6
+ * - Anywhere in the call stack: call getRequestId() to retrieve the current ID
7
+ * - child loggers can bind it via logger.child({ request_id: getRequestId() })
8
+ */
9
+ import { randomUUID } from 'node:crypto';
10
+ export { randomUUID };
11
+ /**
12
+ * Run fn inside a context that has request_id set.
13
+ * Callers that do not call this will see undefined from getRequestId().
14
+ */
15
+ export declare function runWithRequestId<T>(requestId: string, fn: () => T): T;
16
+ /**
17
+ * Retrieve the current request_id from the async context.
18
+ * Returns undefined when called outside a runWithRequestId scope.
19
+ */
20
+ export declare function getRequestId(): string | undefined;
21
+ /**
22
+ * Generate a new RFC 4122 v4 UUID suitable for use as a request_id.
23
+ */
24
+ export declare function newRequestId(): string;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Correlation ID — request_id propagation via AsyncLocalStorage.
3
+ *
4
+ * Usage:
5
+ * - On each incoming HTTP request: call runWithRequestId(uuid, fn)
6
+ * - Anywhere in the call stack: call getRequestId() to retrieve the current ID
7
+ * - child loggers can bind it via logger.child({ request_id: getRequestId() })
8
+ */
9
+ import { AsyncLocalStorage } from 'node:async_hooks';
10
+ import { randomUUID } from 'node:crypto';
11
+ export { randomUUID };
12
+ const storage = new AsyncLocalStorage();
13
+ /**
14
+ * Run fn inside a context that has request_id set.
15
+ * Callers that do not call this will see undefined from getRequestId().
16
+ */
17
+ export function runWithRequestId(requestId, fn) {
18
+ return storage.run(requestId, fn);
19
+ }
20
+ /**
21
+ * Retrieve the current request_id from the async context.
22
+ * Returns undefined when called outside a runWithRequestId scope.
23
+ */
24
+ export function getRequestId() {
25
+ return storage.getStore();
26
+ }
27
+ /**
28
+ * Generate a new RFC 4122 v4 UUID suitable for use as a request_id.
29
+ */
30
+ export function newRequestId() {
31
+ return randomUUID();
32
+ }
33
+ //# sourceMappingURL=correlation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correlation.js","sourceRoot":"","sources":["../../src/log/correlation.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,MAAM,OAAO,GAAG,IAAI,iBAAiB,EAAU,CAAC;AAEhD;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAI,SAAiB,EAAE,EAAW;IAChE,OAAO,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;AACpC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,OAAO,CAAC,QAAQ,EAAE,CAAC;AAC5B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,UAAU,EAAE,CAAC;AACtB,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Structured pino logger for AstraMemory Local.
3
+ *
4
+ * - Default level: info. Override with LOG_LEVEL env.
5
+ * - JSON emit (service mode). pino-pretty auto-activated when LOG_PRETTY=1 and
6
+ * pino-pretty is installed (optional dev dep).
7
+ * - Secret scrubber applied via pino's built-in redact OR serializer fallback.
8
+ *
9
+ * Usage:
10
+ * import { logger, childLogger } from '../log/logger.js';
11
+ *
12
+ * // root logger — use in top-level server code
13
+ * logger.info({ event: 'server.start', port: 7777 }, 'daemon started');
14
+ *
15
+ * // child logger — bind fields for a request / job / stage
16
+ * const log = childLogger({ request_id, session_id });
17
+ * log.info({ status: 200, duration_ms: 12 }, 'request complete');
18
+ */
19
+ import pino from 'pino';
20
+ /**
21
+ * Root logger instance. Long-lived singleton shared across the process.
22
+ */
23
+ export declare const logger: pino.Logger;
24
+ /**
25
+ * Create a child logger with bound fields.
26
+ * All subsequent log calls on the child will include those fields.
27
+ *
28
+ * Common patterns:
29
+ * childLogger({ request_id, method, path }) // HTTP layer
30
+ * childLogger({ request_id, session_id, transcript_id }) // ingest route
31
+ * childLogger({ job_id, job_kind, attempt }) // worker
32
+ * childLogger({ job_id, stage }) // distill stage
33
+ * childLogger({ provider, model }) // LLM/embed provider
34
+ *
35
+ * Sensitive fields in bindings are filtered by isSensitiveKey.
36
+ */
37
+ export declare function childLogger(bindings: Record<string, unknown>): pino.Logger;
38
+ export type { pino };
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Structured pino logger for AstraMemory Local.
3
+ *
4
+ * - Default level: info. Override with LOG_LEVEL env.
5
+ * - JSON emit (service mode). pino-pretty auto-activated when LOG_PRETTY=1 and
6
+ * pino-pretty is installed (optional dev dep).
7
+ * - Secret scrubber applied via pino's built-in redact OR serializer fallback.
8
+ *
9
+ * Usage:
10
+ * import { logger, childLogger } from '../log/logger.js';
11
+ *
12
+ * // root logger — use in top-level server code
13
+ * logger.info({ event: 'server.start', port: 7777 }, 'daemon started');
14
+ *
15
+ * // child logger — bind fields for a request / job / stage
16
+ * const log = childLogger({ request_id, session_id });
17
+ * log.info({ status: 200, duration_ms: 12 }, 'request complete');
18
+ */
19
+ import pino from 'pino';
20
+ import { isSensitiveKey } from './scrub.js';
21
+ const level = process.env['LOG_LEVEL'] ?? 'info';
22
+ /**
23
+ * Pino redactPaths — catches known sensitive field names at top-level and
24
+ * nested under 'req', 'res', 'headers', 'body'. Supplements scrubObj for
25
+ * log-line objects we control.
26
+ */
27
+ const redactPaths = [
28
+ 'authorization',
29
+ 'api_key',
30
+ 'apiKey',
31
+ 'token',
32
+ 'bearer',
33
+ 'password',
34
+ 'secret',
35
+ 'MEMORY_BEARER',
36
+ 'azure_api_key',
37
+ // Nested in HTTP context objects
38
+ 'req.headers.authorization',
39
+ 'headers.authorization',
40
+ 'headers.api-key',
41
+ 'headers["api-key"]',
42
+ ];
43
+ /**
44
+ * Custom serializer for Error objects: captures message + kind, no stack-with-payload.
45
+ * Stack is emitted only at debug level by the caller if needed.
46
+ */
47
+ function serializeError(err) {
48
+ if (err instanceof Error) {
49
+ return {
50
+ error_message: err.message,
51
+ error_kind: err.name ?? 'Error',
52
+ };
53
+ }
54
+ return { error_message: String(err), error_kind: 'Unknown' };
55
+ }
56
+ let transport;
57
+ // Service mode (ASTRA_LOG_DIR set by the shim launcher): rotate JSON logs to
58
+ // <ASTRA_LOG_DIR>/daemon.log, 10MB per file, 5 files retained. Without this,
59
+ // a scheduler-supervised daemon's stdout either vanishes or grows unbounded
60
+ // under redirection. Foreground runs keep stdout.
61
+ const logDir = process.env['ASTRA_LOG_DIR'];
62
+ if (logDir) {
63
+ transport = {
64
+ target: 'pino-roll',
65
+ options: {
66
+ file: `${logDir.replace(/[\\/]+$/, '')}/daemon.log`,
67
+ size: '10m',
68
+ limit: { count: 5 },
69
+ mkdir: true,
70
+ },
71
+ };
72
+ }
73
+ else if (process.env['LOG_PRETTY'] === '1') {
74
+ // pino-pretty transport: activated via LOG_PRETTY=1 (foreground dev mode).
75
+ try {
76
+ transport = {
77
+ target: 'pino-pretty',
78
+ options: {
79
+ colorize: true,
80
+ translateTime: 'SYS:standard',
81
+ ignore: 'pid,hostname',
82
+ },
83
+ };
84
+ }
85
+ catch {
86
+ // pino-pretty not installed — fall back to JSON
87
+ }
88
+ }
89
+ const pinoOpts = {
90
+ level,
91
+ redact: {
92
+ paths: redactPaths,
93
+ censor: '[REDACTED]',
94
+ },
95
+ serializers: {
96
+ err: serializeError,
97
+ error: serializeError,
98
+ },
99
+ };
100
+ /**
101
+ * Root logger instance. Long-lived singleton shared across the process.
102
+ */
103
+ export const logger = transport
104
+ ? pino(pinoOpts, pino.transport(transport))
105
+ : pino(pinoOpts);
106
+ /**
107
+ * Create a child logger with bound fields.
108
+ * All subsequent log calls on the child will include those fields.
109
+ *
110
+ * Common patterns:
111
+ * childLogger({ request_id, method, path }) // HTTP layer
112
+ * childLogger({ request_id, session_id, transcript_id }) // ingest route
113
+ * childLogger({ job_id, job_kind, attempt }) // worker
114
+ * childLogger({ job_id, stage }) // distill stage
115
+ * childLogger({ provider, model }) // LLM/embed provider
116
+ *
117
+ * Sensitive fields in bindings are filtered by isSensitiveKey.
118
+ */
119
+ export function childLogger(bindings) {
120
+ // Strip any accidentally-passed sensitive keys from bound fields
121
+ const safe = {};
122
+ for (const [key, val] of Object.entries(bindings)) {
123
+ if (!isSensitiveKey(key)) {
124
+ safe[key] = val;
125
+ }
126
+ }
127
+ return logger.child(safe);
128
+ }
129
+ //# sourceMappingURL=logger.js.map