@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,92 @@
1
+ import { existsSync, statSync } from 'node:fs';
2
+ import Database from 'better-sqlite3-multiple-ciphers';
3
+ import * as sqliteVec from 'sqlite-vec';
4
+ /**
5
+ * Thrown by `openDb` when the file on disk cannot be trusted as an intact
6
+ * datadir (FEAT-420 AC-3), and NO encryption key was in play. Distinct from
7
+ * a raw `SqliteError` so callers and operators get an actionable message
8
+ * instead of a low-level driver string.
9
+ */
10
+ export class CorruptDatadirError extends Error {
11
+ constructor(path, reason) {
12
+ super(`Refusing to open ${path}: ${reason}. This looks like a corrupted or truncated ` +
13
+ `SQLite datadir, not a fresh install — a fresh install never pre-creates this file. ` +
14
+ `Restore from a backup ('astramem-local restore') or, if you are certain there is no ` +
15
+ `data to lose, delete the file (and any -wal/-shm siblings) and restart to create a fresh one.`);
16
+ this.name = 'CorruptDatadirError';
17
+ }
18
+ }
19
+ /**
20
+ * Thrown by `openDb` when a key WAS supplied but the file could not be read
21
+ * with it (FEAT-420 AC-3 review fix). SQLCipher cannot distinguish
22
+ * "wrong/missing key" from "corrupted file" at the driver level — both
23
+ * surface as the exact same `SqliteError: file is not a database`
24
+ * (SQLITE_NOTADB), which is also the documented stale-v0.3.4-global-install
25
+ * symptom (CLAUDE.md "Do NOT use bare astramem-local"). Reusing
26
+ * CorruptDatadirError's corruption-and-delete advice here would actively
27
+ * steer an operator with a recoverable key/config problem toward destroying
28
+ * a healthy encrypted database — so this is a distinct class with distinct,
29
+ * non-destructive advice and NO deletion suggestion.
30
+ */
31
+ export class EncryptionKeyError extends Error {
32
+ constructor(path, reason) {
33
+ super(`Refusing to open ${path}: ${reason}. A key was supplied but could not decrypt this file — ` +
34
+ `this is the classic wrong-or-missing-encryption-key symptom, not necessarily corruption ` +
35
+ `(SQLCipher cannot tell the two apart at this layer). Before assuming data loss, check: ` +
36
+ `(1) the key material in secrets.env matches what encrypted this file; ` +
37
+ `(2) you are running the repo build ('node dist/cli/index.js ...'), not a stale globally-` +
38
+ `installed 'astramem-local' shadowing it with a different cipher driver; ` +
39
+ `(3) the key hasn't rotated without re-encrypting this file. Leave this file untouched until ` +
40
+ `one of those is resolved — it may still hold your data intact.`);
41
+ this.name = 'EncryptionKeyError';
42
+ }
43
+ }
44
+ export function openDb(path, opts = {}) {
45
+ // FEAT-420 AC-3: a pre-existing but EMPTY (0-byte) file is silently
46
+ // accepted by SQLite as a brand-new database — better-sqlite3 just
47
+ // initializes it, and migrate() then happily builds a pristine empty
48
+ // schema on top, masking what is actually a truncated/corrupted datadir
49
+ // as data loss with no error at all. A genuinely fresh install never has
50
+ // a pre-existing file at this path (the file doesn't exist until this
51
+ // call creates it), so "file exists AND is 0 bytes" is an unambiguous
52
+ // signal of truncation, not a legitimate first run.
53
+ if (path !== ':memory:' && existsSync(path) && statSync(path).size === 0) {
54
+ throw new CorruptDatadirError(path, 'file exists but is empty (0 bytes)');
55
+ }
56
+ try {
57
+ const db = new Database(path);
58
+ if (path !== ':memory:' && opts.key) {
59
+ db.pragma(`key='${opts.key.replace(/'/g, "''")}'`);
60
+ }
61
+ // Block-and-retry for up to 5s on a locked database instead of throwing
62
+ // SQLITE_BUSY immediately — covers concurrent writers (backup CLI's
63
+ // second connection, doctor probes) against the live daemon.
64
+ db.pragma('busy_timeout = 5000');
65
+ // better-sqlite3 opens the file handle lazily — "file is not a
66
+ // database" / "database disk image is malformed" (garbage bytes, a
67
+ // truncated real file) only surface on the FIRST pragma/exec that
68
+ // actually reads a page, not at `new Database()` itself. Everything
69
+ // through the vec extension load is wrapped so any of these still
70
+ // become the same actionable typed error as the 0-byte case above.
71
+ db.pragma('journal_mode = WAL');
72
+ db.pragma('foreign_keys = ON');
73
+ db.pragma('synchronous = NORMAL');
74
+ sqliteVec.load(db);
75
+ return db;
76
+ }
77
+ catch (err) {
78
+ const alreadyTyped = err instanceof CorruptDatadirError || err instanceof EncryptionKeyError;
79
+ if (path !== ':memory:' && err instanceof Error && !alreadyTyped) {
80
+ // A key was supplied (opts.key) -> the same raw driver error is the
81
+ // wrong/missing-key symptom, not necessarily corruption — see
82
+ // EncryptionKeyError's doc comment. Only diagnose corruption when no
83
+ // key was ever in play.
84
+ if (opts.key) {
85
+ throw new EncryptionKeyError(path, err.message);
86
+ }
87
+ throw new CorruptDatadirError(path, err.message);
88
+ }
89
+ throw err;
90
+ }
91
+ }
92
+ //# sourceMappingURL=db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/storage/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,QAAQ,MAAM,iCAAiC,CAAC;AACvD,OAAO,KAAK,SAAS,MAAM,YAAY,CAAC;AAexC;;;;;GAKG;AACH,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,IAAY,EAAE,MAAc;QACtC,KAAK,CACH,oBAAoB,IAAI,KAAK,MAAM,6CAA6C;YAChF,qFAAqF;YACrF,sFAAsF;YACtF,+FAA+F,CAChG,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAC3C,YAAY,IAAY,EAAE,MAAc;QACtC,KAAK,CACH,oBAAoB,IAAI,KAAK,MAAM,yDAAyD;YAC5F,0FAA0F;YAC1F,yFAAyF;YACzF,wEAAwE;YACxE,0FAA0F;YAC1F,0EAA0E;YAC1E,8FAA8F;YAC9F,gEAAgE,CACjE,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AAED,MAAM,UAAU,MAAM,CAAC,IAAY,EAAE,OAAmB,EAAE;IACxD,oEAAoE;IACpE,mEAAmE;IACnE,qEAAqE;IACrE,wEAAwE;IACxE,yEAAyE;IACzE,sEAAsE;IACtE,sEAAsE;IACtE,oDAAoD;IACpD,IAAI,IAAI,KAAK,UAAU,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACzE,MAAM,IAAI,mBAAmB,CAAC,IAAI,EAAE,oCAAoC,CAAC,CAAC;IAC5E,CAAC;IACD,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,IAAI,KAAK,UAAU,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;YACpC,EAAE,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QACrD,CAAC;QACD,wEAAwE;QACxE,oEAAoE;QACpE,6DAA6D;QAC7D,EAAE,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;QACjC,+DAA+D;QAC/D,mEAAmE;QACnE,kEAAkE;QAClE,oEAAoE;QACpE,kEAAkE;QAClE,mEAAmE;QACnE,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;QAChC,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;QAC/B,EAAE,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC;QAClC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnB,OAAO,EAAE,CAAC;IACZ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,YAAY,GAAG,GAAG,YAAY,mBAAmB,IAAI,GAAG,YAAY,kBAAkB,CAAC;QAC7F,IAAI,IAAI,KAAK,UAAU,IAAI,GAAG,YAAY,KAAK,IAAI,CAAC,YAAY,EAAE,CAAC;YACjE,oEAAoE;YACpE,8DAA8D;YAC9D,qEAAqE;YACrE,wBAAwB;YACxB,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;gBACb,MAAM,IAAI,kBAAkB,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;YAClD,CAAC;YACD,MAAM,IAAI,mBAAmB,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;QACnD,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * entities + memory_entities repo (FEAT-402 slice 1, migration 012).
3
+ *
4
+ * `entities.name` is UNIQUE and always stores the NORMALIZED form
5
+ * (src/entity/normalize.ts normalizeEntityName — AC-9's single seam), so
6
+ * `upsert('Postgres', 'tech')` and `upsert('postgres', 'tech')` resolve to
7
+ * the same row. `memory_entities` is a plain link table written by both the
8
+ * distill-time embed-index stage (same LLM call as atom extraction) and the
9
+ * `entity-backfill` CLI command for the pre-existing corpus.
10
+ */
11
+ import type { DB } from './db.js';
12
+ export interface EntityRow {
13
+ id: string;
14
+ name: string;
15
+ kind: string;
16
+ }
17
+ export interface EntityInput {
18
+ name: string;
19
+ kind: string;
20
+ }
21
+ export declare class EntityRepo {
22
+ private db;
23
+ constructor(db: DB);
24
+ /**
25
+ * Resolve `name` (normalized) to an entities.id, creating the row if it
26
+ * doesn't exist yet. `kind` is only applied on first-create — a later call
27
+ * with a different kind for the same normalized name does NOT overwrite
28
+ * it (first-writer-wins avoids kind flip-flopping across distill runs).
29
+ */
30
+ upsert(name: string, kind: string): string;
31
+ /** Idempotent link — INSERT OR IGNORE on the (memory_id, entity_id) PK. */
32
+ link(memoryId: string, entityId: string): void;
33
+ /**
34
+ * Upsert + link every entity in one call — the shape both the distill-time
35
+ * embed-index stage and the backfill command consume. No-op for an empty
36
+ * or missing list.
37
+ */
38
+ linkEntitiesForMemory(memoryId: string, entities: EntityInput[] | undefined): void;
39
+ /** Remove every memory_entities row for one memory (AC-3 supersede cascade). */
40
+ unlinkMemory(memoryId: string): void;
41
+ /** All entities linked to a memory — used by tests and the (slice 2) query surface. */
42
+ listForMemory(memoryId: string): EntityRow[];
43
+ /** True when `name` (normalized) already resolves to an entities row. */
44
+ exists(name: string): boolean;
45
+ /** Single entity by id — GET /entities/:id/memories 404s when this returns undefined. */
46
+ getById(id: string): EntityRow | undefined;
47
+ /**
48
+ * Autocomplete (FEAT-402 slice 2 AC-5, `GET /entities?q=`) — substring
49
+ * match on the normalized name, case/whitespace-insensitive via the same
50
+ * AC-9 seam every other lookup goes through. Empty/whitespace `query`
51
+ * returns the first `limit` entities alphabetically rather than nothing,
52
+ * so an empty-q autocomplete call still has sane behavior.
53
+ */
54
+ search(query: string, limit?: number): EntityRow[];
55
+ /**
56
+ * Resolve a free-form entity query (e.g. the search `entity=` filter,
57
+ * FEAT-402 slice 2 AC-4) to entity ids via the AC-9 normalize seam: exact
58
+ * match on the normalized name first, falling back to a LIKE substring
59
+ * match only when no exact row exists. Returns [] when nothing matches —
60
+ * callers MUST treat that as "no entity-linked candidates" rather than
61
+ * falling back to an unfiltered search.
62
+ */
63
+ resolveIds(query: string): string[];
64
+ /**
65
+ * All distinct memory ids linked to any of `entityIds` — the join behind
66
+ * both the search `entity=` pre-fusion intersection (AC-4) and
67
+ * `GET /entities/:id/memories` (AC-5). Empty input returns an empty set
68
+ * rather than every memory (an empty entityIds list is never "no filter").
69
+ */
70
+ memoryIdsForEntities(entityIds: string[]): Set<string>;
71
+ }
@@ -0,0 +1,141 @@
1
+ /**
2
+ * entities + memory_entities repo (FEAT-402 slice 1, migration 012).
3
+ *
4
+ * `entities.name` is UNIQUE and always stores the NORMALIZED form
5
+ * (src/entity/normalize.ts normalizeEntityName — AC-9's single seam), so
6
+ * `upsert('Postgres', 'tech')` and `upsert('postgres', 'tech')` resolve to
7
+ * the same row. `memory_entities` is a plain link table written by both the
8
+ * distill-time embed-index stage (same LLM call as atom extraction) and the
9
+ * `entity-backfill` CLI command for the pre-existing corpus.
10
+ */
11
+ import { randomUUID } from 'node:crypto';
12
+ import { normalizeEntityName } from '../entity/normalize.js';
13
+ export class EntityRepo {
14
+ db;
15
+ constructor(db) {
16
+ this.db = db;
17
+ }
18
+ /**
19
+ * Resolve `name` (normalized) to an entities.id, creating the row if it
20
+ * doesn't exist yet. `kind` is only applied on first-create — a later call
21
+ * with a different kind for the same normalized name does NOT overwrite
22
+ * it (first-writer-wins avoids kind flip-flopping across distill runs).
23
+ */
24
+ upsert(name, kind) {
25
+ const normalized = normalizeEntityName(name);
26
+ const existing = this.db
27
+ .prepare('SELECT id FROM entities WHERE name = ?')
28
+ .get(normalized);
29
+ if (existing)
30
+ return existing.id;
31
+ const id = randomUUID();
32
+ this.db.prepare('INSERT INTO entities (id, name, kind) VALUES (?, ?, ?)').run(id, normalized, kind);
33
+ return id;
34
+ }
35
+ /** Idempotent link — INSERT OR IGNORE on the (memory_id, entity_id) PK. */
36
+ link(memoryId, entityId) {
37
+ this.db
38
+ .prepare('INSERT OR IGNORE INTO memory_entities (memory_id, entity_id) VALUES (?, ?)')
39
+ .run(memoryId, entityId);
40
+ }
41
+ /**
42
+ * Upsert + link every entity in one call — the shape both the distill-time
43
+ * embed-index stage and the backfill command consume. No-op for an empty
44
+ * or missing list.
45
+ */
46
+ linkEntitiesForMemory(memoryId, entities) {
47
+ if (!entities || entities.length === 0)
48
+ return;
49
+ for (const e of entities) {
50
+ const entityId = this.upsert(e.name, e.kind);
51
+ this.link(memoryId, entityId);
52
+ }
53
+ }
54
+ /** Remove every memory_entities row for one memory (AC-3 supersede cascade). */
55
+ unlinkMemory(memoryId) {
56
+ this.db.prepare('DELETE FROM memory_entities WHERE memory_id = ?').run(memoryId);
57
+ }
58
+ /** All entities linked to a memory — used by tests and the (slice 2) query surface. */
59
+ listForMemory(memoryId) {
60
+ return this.db
61
+ .prepare(`
62
+ SELECT e.id, e.name, e.kind
63
+ FROM entities e
64
+ JOIN memory_entities me ON me.entity_id = e.id
65
+ WHERE me.memory_id = ?
66
+ ORDER BY e.name ASC
67
+ `)
68
+ .all(memoryId);
69
+ }
70
+ /** True when `name` (normalized) already resolves to an entities row. */
71
+ exists(name) {
72
+ const normalized = normalizeEntityName(name);
73
+ const row = this.db.prepare('SELECT 1 AS x FROM entities WHERE name = ?').get(normalized);
74
+ return row !== undefined;
75
+ }
76
+ /** Single entity by id — GET /entities/:id/memories 404s when this returns undefined. */
77
+ getById(id) {
78
+ return this.db.prepare('SELECT id, name, kind FROM entities WHERE id = ?').get(id);
79
+ }
80
+ /**
81
+ * Autocomplete (FEAT-402 slice 2 AC-5, `GET /entities?q=`) — substring
82
+ * match on the normalized name, case/whitespace-insensitive via the same
83
+ * AC-9 seam every other lookup goes through. Empty/whitespace `query`
84
+ * returns the first `limit` entities alphabetically rather than nothing,
85
+ * so an empty-q autocomplete call still has sane behavior.
86
+ */
87
+ search(query, limit = 20) {
88
+ const normalized = normalizeEntityName(query);
89
+ if (!normalized) {
90
+ return this.db
91
+ .prepare('SELECT id, name, kind FROM entities ORDER BY name ASC LIMIT ?')
92
+ .all(limit);
93
+ }
94
+ const escaped = escapeLike(normalized);
95
+ return this.db
96
+ .prepare(`SELECT id, name, kind FROM entities WHERE name LIKE ? ESCAPE '\\' ORDER BY name ASC LIMIT ?`)
97
+ .all(`%${escaped}%`, limit);
98
+ }
99
+ /**
100
+ * Resolve a free-form entity query (e.g. the search `entity=` filter,
101
+ * FEAT-402 slice 2 AC-4) to entity ids via the AC-9 normalize seam: exact
102
+ * match on the normalized name first, falling back to a LIKE substring
103
+ * match only when no exact row exists. Returns [] when nothing matches —
104
+ * callers MUST treat that as "no entity-linked candidates" rather than
105
+ * falling back to an unfiltered search.
106
+ */
107
+ resolveIds(query) {
108
+ const normalized = normalizeEntityName(query);
109
+ if (!normalized)
110
+ return [];
111
+ const exact = this.db.prepare('SELECT id FROM entities WHERE name = ?').get(normalized);
112
+ if (exact)
113
+ return [exact.id];
114
+ const escaped = escapeLike(normalized);
115
+ const rows = this.db
116
+ .prepare(`SELECT id FROM entities WHERE name LIKE ? ESCAPE '\\'`)
117
+ .all(`%${escaped}%`);
118
+ return rows.map(r => r.id);
119
+ }
120
+ /**
121
+ * All distinct memory ids linked to any of `entityIds` — the join behind
122
+ * both the search `entity=` pre-fusion intersection (AC-4) and
123
+ * `GET /entities/:id/memories` (AC-5). Empty input returns an empty set
124
+ * rather than every memory (an empty entityIds list is never "no filter").
125
+ */
126
+ memoryIdsForEntities(entityIds) {
127
+ if (entityIds.length === 0)
128
+ return new Set();
129
+ const placeholders = entityIds.map(() => '?').join(',');
130
+ const rows = this.db
131
+ .prepare(`SELECT DISTINCT memory_id FROM memory_entities WHERE entity_id IN (${placeholders})`)
132
+ .all(...entityIds);
133
+ return new Set(rows.map(r => r.memory_id));
134
+ }
135
+ }
136
+ /** Escape SQL LIKE wildcards (`%`, `_`) in a substring pattern the caller
137
+ * did not intend as wildcard syntax — used with `ESCAPE '\\'` above. */
138
+ function escapeLike(value) {
139
+ return value.replace(/[\\%_]/g, ch => `\\${ch}`);
140
+ }
141
+ //# sourceMappingURL=entities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entities.js","sourceRoot":"","sources":["../../src/storage/entities.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * D-DEF2 fix — `summary_memory_id` backfill.
3
+ *
4
+ * `POST /ingest/transcript` (server/routes/ingest.ts) writes the transcript
5
+ * row's own id into `ingest_idempotency.summary_memory_id` at insert time —
6
+ * distillation is async (queued as a `distill` job), so there is no real
7
+ * memory id yet when the HTTP response is built. That placeholder value was
8
+ * never updated afterwards, so idempotent replays kept returning the
9
+ * transcript id forever, even after distillation produced real memories
10
+ * (CHANGELOG 0.2.0 "Known issues" — D-DEF2: "Wave-3 distillation will
11
+ * produce a real summary memory... semantic meaning will change when
12
+ * distillation is wired end-to-end").
13
+ *
14
+ * This backfills the row once the distill job actually produces a memory.
15
+ * No schema change: `summary_memory_id` already accepts an arbitrary TEXT
16
+ * id (it has never had a FK constraint tying it to `transcripts.id`), so
17
+ * repointing it at a `memories.id` is a value change, not a shape change.
18
+ */
19
+ import type { DB } from './db.js';
20
+ /**
21
+ * Repoint any `ingest_idempotency` row still holding `transcriptId` as its
22
+ * placeholder `summary_memory_id` to the real `memoryId` produced by
23
+ * distillation. No-op if no such row exists (e.g. the original POST carried
24
+ * no `Idempotency-Key`, so no row was ever created).
25
+ */
26
+ export declare function backfillSummaryMemoryId(db: DB, transcriptId: string, memoryId: string): void;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * D-DEF2 fix — `summary_memory_id` backfill.
3
+ *
4
+ * `POST /ingest/transcript` (server/routes/ingest.ts) writes the transcript
5
+ * row's own id into `ingest_idempotency.summary_memory_id` at insert time —
6
+ * distillation is async (queued as a `distill` job), so there is no real
7
+ * memory id yet when the HTTP response is built. That placeholder value was
8
+ * never updated afterwards, so idempotent replays kept returning the
9
+ * transcript id forever, even after distillation produced real memories
10
+ * (CHANGELOG 0.2.0 "Known issues" — D-DEF2: "Wave-3 distillation will
11
+ * produce a real summary memory... semantic meaning will change when
12
+ * distillation is wired end-to-end").
13
+ *
14
+ * This backfills the row once the distill job actually produces a memory.
15
+ * No schema change: `summary_memory_id` already accepts an arbitrary TEXT
16
+ * id (it has never had a FK constraint tying it to `transcripts.id`), so
17
+ * repointing it at a `memories.id` is a value change, not a shape change.
18
+ */
19
+ /**
20
+ * Repoint any `ingest_idempotency` row still holding `transcriptId` as its
21
+ * placeholder `summary_memory_id` to the real `memoryId` produced by
22
+ * distillation. No-op if no such row exists (e.g. the original POST carried
23
+ * no `Idempotency-Key`, so no row was ever created).
24
+ */
25
+ export function backfillSummaryMemoryId(db, transcriptId, memoryId) {
26
+ db.prepare('UPDATE ingest_idempotency SET summary_memory_id = ? WHERE summary_memory_id = ?')
27
+ .run(memoryId, transcriptId);
28
+ }
29
+ //# sourceMappingURL=ingest-idempotency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingest-idempotency.js","sourceRoot":"","sources":["../../src/storage/ingest-idempotency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,EAAM,EAAE,YAAoB,EAAE,QAAgB;IACpF,EAAE,CAAC,OAAO,CAAC,iFAAiF,CAAC;SAC1F,GAAG,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;AACjC,CAAC"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * keystore.ts — encryption-at-rest key management (SEC-1/2, Wave 1 task 1b).
3
+ *
4
+ * Provider chain (per spec §4.1 / OQ-1):
5
+ * (a) OS credential store — Windows Credential Manager / macOS Keychain /
6
+ * Linux libsecret, via `@napi-rs/keyring` (prebuilt N-API binding,
7
+ * verified to install cleanly with prebuilds for win32-x64-msvc,
8
+ * darwin-x64/arm64, and linux-x64-gnu — the repo's 3 CI targets).
9
+ * (b) key-file fallback (`<configDir>/db.key`, mode 0600) with a WARN log —
10
+ * used when the credential store throws (e.g. headless Linux with no
11
+ * secret-service/dbus session). Spec OQ-1 explicitly allows this
12
+ * fallback for v0.4.
13
+ *
14
+ * Key lookup identity is fixed: service `'astramem-local'`, account `'db-key'`.
15
+ * The key is a 32-byte cryptographically random value, hex-encoded (64 chars),
16
+ * used as the SQLCipher passphrase via `PRAGMA key='<hex>'` — the exact
17
+ * PRAGMA form validated end-to-end (open/reopen/wrong-key) by the 1a spike
18
+ * (tests/security/cipher-spike.test.ts).
19
+ *
20
+ * getOrCreateKey() is idempotent: a second call against the same configDir
21
+ * (and, for the credential-store path, the same machine/user) returns the
22
+ * same key rather than minting a new one.
23
+ */
24
+ import { Entry } from '@napi-rs/keyring';
25
+ export type KeySource = 'credential-store' | 'key-file';
26
+ export interface KeyResult {
27
+ key: string;
28
+ source: KeySource;
29
+ }
30
+ /** Test-only hook: override (or restore) the credential-store Entry constructor. */
31
+ export declare function __setEntryCtorForTests(ctor: typeof Entry | undefined): void;
32
+ /**
33
+ * Returns the encryption key for this machine/user, creating one on first
34
+ * use. Tries the OS credential store first; falls back to a 0600 key file
35
+ * under `configDir` (with a WARN log) when the credential store throws.
36
+ *
37
+ * NOTE: deviates slightly from the originally-sketched `(configDir) => string`
38
+ * signature — returns `{ key, source }` instead of a bare string so callers
39
+ * (doctor, /health) can report key location (SEC-8/AC-5) without a second,
40
+ * duplicate resolution pass. `.key` is what openDb()/migrate-encrypt need.
41
+ */
42
+ export declare function getOrCreateKey(configDir: string): KeyResult;
43
+ export declare function keyFilePath(configDir: string): string;
44
+ export interface BearerStoreResult {
45
+ stored: boolean;
46
+ source: 'credential-store' | 'secrets-env-fallback';
47
+ }
48
+ /**
49
+ * Store `token` in the OS credential store. On failure (no credential store
50
+ * / no secret-service session), WARNs and returns a fallback marker so the
51
+ * caller persists the bearer into secrets.env instead (SEC-10).
52
+ */
53
+ export declare function storeBearer(token: string): BearerStoreResult;
54
+ /**
55
+ * Read the bearer token from the OS credential store, if present.
56
+ * Returns null on any error (store unavailable, or no entry yet) — same
57
+ * "throw and getPassword()->null are both just 'no key yet'" tolerance as
58
+ * getOrCreateCredentialStoreKey above. Callers fall back to secrets.env.
59
+ */
60
+ export declare function readBearer(): string | null;
61
+ /** Store the cloud sync device token (ADR-003 auth) in the credential store. */
62
+ export declare function storeSyncToken(token: string): BearerStoreResult;
63
+ /** Read the cloud sync device token; null when absent/unavailable. */
64
+ export declare function readSyncToken(): string | null;
@@ -0,0 +1,194 @@
1
+ /**
2
+ * keystore.ts — encryption-at-rest key management (SEC-1/2, Wave 1 task 1b).
3
+ *
4
+ * Provider chain (per spec §4.1 / OQ-1):
5
+ * (a) OS credential store — Windows Credential Manager / macOS Keychain /
6
+ * Linux libsecret, via `@napi-rs/keyring` (prebuilt N-API binding,
7
+ * verified to install cleanly with prebuilds for win32-x64-msvc,
8
+ * darwin-x64/arm64, and linux-x64-gnu — the repo's 3 CI targets).
9
+ * (b) key-file fallback (`<configDir>/db.key`, mode 0600) with a WARN log —
10
+ * used when the credential store throws (e.g. headless Linux with no
11
+ * secret-service/dbus session). Spec OQ-1 explicitly allows this
12
+ * fallback for v0.4.
13
+ *
14
+ * Key lookup identity is fixed: service `'astramem-local'`, account `'db-key'`.
15
+ * The key is a 32-byte cryptographically random value, hex-encoded (64 chars),
16
+ * used as the SQLCipher passphrase via `PRAGMA key='<hex>'` — the exact
17
+ * PRAGMA form validated end-to-end (open/reopen/wrong-key) by the 1a spike
18
+ * (tests/security/cipher-spike.test.ts).
19
+ *
20
+ * getOrCreateKey() is idempotent: a second call against the same configDir
21
+ * (and, for the credential-store path, the same machine/user) returns the
22
+ * same key rather than minting a new one.
23
+ */
24
+ import { Entry } from '@napi-rs/keyring';
25
+ import { randomBytes } from 'node:crypto';
26
+ import { existsSync, readFileSync, writeFileSync, chmodSync, mkdirSync } from 'node:fs';
27
+ import { join } from 'node:path';
28
+ import { execFileSync } from 'node:child_process';
29
+ const SERVICE = 'astramem-local';
30
+ const ACCOUNT = 'db-key';
31
+ const BEARER_ACCOUNT = 'bearer';
32
+ // Test-only indirection so tests can simulate a credential-store outage
33
+ // (e.g. headless-Linux fallback) without needing an actual broken OS
34
+ // keychain, and so keystore tests don't have to mutate the developer's
35
+ // real OS credential store as a side effect of `npm test`.
36
+ let EntryCtor = Entry;
37
+ /** Test-only hook: override (or restore) the credential-store Entry constructor. */
38
+ export function __setEntryCtorForTests(ctor) {
39
+ EntryCtor = ctor ?? Entry;
40
+ }
41
+ /**
42
+ * Returns the encryption key for this machine/user, creating one on first
43
+ * use. Tries the OS credential store first; falls back to a 0600 key file
44
+ * under `configDir` (with a WARN log) when the credential store throws.
45
+ *
46
+ * NOTE: deviates slightly from the originally-sketched `(configDir) => string`
47
+ * signature — returns `{ key, source }` instead of a bare string so callers
48
+ * (doctor, /health) can report key location (SEC-8/AC-5) without a second,
49
+ * duplicate resolution pass. `.key` is what openDb()/migrate-encrypt need.
50
+ */
51
+ export function getOrCreateKey(configDir) {
52
+ try {
53
+ return getOrCreateCredentialStoreKey();
54
+ }
55
+ catch (err) {
56
+ console.warn(`[astramem-local] WARNING: OS credential store unavailable (${errMessage(err)}); ` +
57
+ `falling back to a key file with 0600 permissions. This is a weaker guarantee than ` +
58
+ `an OS credential store — see docs/specs/2026-07-02-encryption-and-secret-redaction.md OQ-1.`);
59
+ return getOrCreateKeyFile(configDir);
60
+ }
61
+ }
62
+ function errMessage(err) {
63
+ return err instanceof Error ? err.message : String(err);
64
+ }
65
+ function generateKeyHex() {
66
+ return randomBytes(32).toString('hex');
67
+ }
68
+ // ─── Provider (a): OS credential store ────────────────────────────────────
69
+ function getOrCreateCredentialStoreKey() {
70
+ const entry = new EntryCtor(SERVICE, ACCOUNT);
71
+ // getPassword() returns null when absent on some platforms but throws a
72
+ // NoEntry error on others (per @napi-rs/keyring docs) — treat both as
73
+ // "no key yet", not as "credential store broken". Only the constructor
74
+ // and setPassword() throwing should trigger the key-file fallback.
75
+ let existing;
76
+ try {
77
+ existing = entry.getPassword();
78
+ }
79
+ catch {
80
+ existing = null;
81
+ }
82
+ if (existing) {
83
+ return { key: existing, source: 'credential-store' };
84
+ }
85
+ const key = generateKeyHex();
86
+ entry.setPassword(key);
87
+ return { key, source: 'credential-store' };
88
+ }
89
+ // ─── Provider (b): key-file fallback ──────────────────────────────────────
90
+ function getOrCreateKeyFile(configDir) {
91
+ mkdirSync(configDir, { recursive: true });
92
+ const keyPath = join(configDir, 'db.key');
93
+ if (existsSync(keyPath)) {
94
+ const key = readFileSync(keyPath, 'utf8').trim();
95
+ restrictKeyFileAcl(keyPath); // heal ACLs on files created by older builds
96
+ return { key, source: 'key-file' };
97
+ }
98
+ const key = generateKeyHex();
99
+ writeFileSync(keyPath, key, { mode: 0o600 });
100
+ try {
101
+ // Belt-and-braces: writeFileSync's mode option is honored on creation on
102
+ // POSIX; chmodSync is a no-op on Windows (no POSIX bits) — Windows gets a
103
+ // real ACL below via icacls instead.
104
+ chmodSync(keyPath, 0o600);
105
+ }
106
+ catch {
107
+ /* best-effort on platforms without POSIX permission bits */
108
+ }
109
+ restrictKeyFileAcl(keyPath);
110
+ return { key, source: 'key-file' };
111
+ }
112
+ /**
113
+ * Windows: apply a real ACL to the key file — strip inheritance, grant only
114
+ * the current user. Without this, chmod is a no-op and the DB encryption key
115
+ * sits world-readable next to the database it protects (SEC OQ-1).
116
+ * Best-effort but LOUD on failure: a key file without an ACL is a real
117
+ * security downgrade the user must know about.
118
+ */
119
+ function restrictKeyFileAcl(keyPath) {
120
+ if (process.platform !== 'win32')
121
+ return;
122
+ const user = process.env['USERNAME'];
123
+ if (!user)
124
+ return;
125
+ try {
126
+ execFileSync('icacls', [keyPath, '/inheritance:r', '/grant:r', `${user}:F`], { stdio: 'pipe', timeout: 10_000 });
127
+ }
128
+ catch (err) {
129
+ console.warn(`[astramem-local] WARNING: could not restrict ACL on key file ${keyPath} ` +
130
+ `(icacls failed: ${errMessage(err)}). The DB encryption key is readable by other ` +
131
+ `local accounts — fix manually: icacls "${keyPath}" /inheritance:r /grant:r ${user}:F`);
132
+ }
133
+ }
134
+ export function keyFilePath(configDir) {
135
+ return join(configDir, 'db.key');
136
+ }
137
+ /**
138
+ * Store `token` in the OS credential store. On failure (no credential store
139
+ * / no secret-service session), WARNs and returns a fallback marker so the
140
+ * caller persists the bearer into secrets.env instead (SEC-10).
141
+ */
142
+ export function storeBearer(token) {
143
+ try {
144
+ const entry = new EntryCtor(SERVICE, BEARER_ACCOUNT);
145
+ entry.setPassword(token);
146
+ return { stored: true, source: 'credential-store' };
147
+ }
148
+ catch (err) {
149
+ console.warn(`[astramem-local] WARNING: OS credential store unavailable (${errMessage(err)}); ` +
150
+ `falling back to writing the bearer token into secrets.env. This is a weaker guarantee ` +
151
+ `than an OS credential store — see docs/specs/2026-07-02-encryption-and-secret-redaction.md SEC-10.`);
152
+ return { stored: false, source: 'secrets-env-fallback' };
153
+ }
154
+ }
155
+ /**
156
+ * Read the bearer token from the OS credential store, if present.
157
+ * Returns null on any error (store unavailable, or no entry yet) — same
158
+ * "throw and getPassword()->null are both just 'no key yet'" tolerance as
159
+ * getOrCreateCredentialStoreKey above. Callers fall back to secrets.env.
160
+ */
161
+ export function readBearer() {
162
+ try {
163
+ const entry = new EntryCtor(SERVICE, BEARER_ACCOUNT);
164
+ return entry.getPassword();
165
+ }
166
+ catch {
167
+ return null;
168
+ }
169
+ }
170
+ const SYNC_TOKEN_ACCOUNT = 'sync-device-token';
171
+ /** Store the cloud sync device token (ADR-003 auth) in the credential store. */
172
+ export function storeSyncToken(token) {
173
+ try {
174
+ const entry = new EntryCtor(SERVICE, SYNC_TOKEN_ACCOUNT);
175
+ entry.setPassword(token);
176
+ return { stored: true, source: 'credential-store' };
177
+ }
178
+ catch (err) {
179
+ console.warn(`[astramem-local] WARNING: OS credential store unavailable (${errMessage(err)}); ` +
180
+ `sync device token was NOT stored. Set ASTRA_SYNC_TOKEN in the environment instead.`);
181
+ return { stored: false, source: 'secrets-env-fallback' };
182
+ }
183
+ }
184
+ /** Read the cloud sync device token; null when absent/unavailable. */
185
+ export function readSyncToken() {
186
+ try {
187
+ const entry = new EntryCtor(SERVICE, SYNC_TOKEN_ACCOUNT);
188
+ return entry.getPassword();
189
+ }
190
+ catch {
191
+ return null;
192
+ }
193
+ }
194
+ //# sourceMappingURL=keystore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keystore.js","sourceRoot":"","sources":["../../src/storage/keystore.ts"],"names":[],"mappings":"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"}