@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
package/README.md ADDED
@@ -0,0 +1,419 @@
1
+ # AstraMemory Local
2
+
3
+ Local-first memory daemon for AI coding agents — wire-compatible with `memory-plugin` (v0.2.0+).
4
+
5
+ > **v0.2.0 closes the schema gap**
6
+ > Daemon v0.2.0 now accepts the SaaS-canonical wire envelope: `{event, turns[], wire_version (required), scrub metadata, client_version, captured_at, project_id, cwd}` alongside backward-compatible `{session_id, source, content}`. The daemon and SaaS backend now share a wire contract. See the [astramemory-plugin FEAT 4a spec](https://github.com/astragenie/astramemory-plugin/blob/main/docs/superpowers/specs/2026-06-29-hooks-provider-migration-4a.md) for the unified wire contract and migration timeline.
7
+
8
+ ## Wire compatibility
9
+
10
+ The daemon's ingest endpoint now speaks the same wire protocol as the SaaS backend. Both old and new clients work:
11
+
12
+ **Legacy plugin (v0.1.x):**
13
+ ```json
14
+ POST /ingest/transcript
15
+ Content-Type: application/json
16
+ Authorization: Bearer <token>
17
+
18
+ {
19
+ "session_id": "claude-20260630-abc123",
20
+ "source": "precompact",
21
+ "content": "[Assistant]: Distilled 3 facts..."
22
+ }
23
+ ```
24
+
25
+ **SaaS canonical (v0.2.0+):**
26
+ ```json
27
+ POST /ingest/transcript
28
+ Content-Type: application/json
29
+ Authorization: Bearer <token>
30
+
31
+ {
32
+ "event": "pre_compact",
33
+ "session_id": "claude-20260630-abc123",
34
+ "turns": [{"role": "user", "content": "..."}, ...],
35
+ "wire_version": "v1.0",
36
+ "captured_at": "2026-06-30T12:34:56Z",
37
+ "client_version": "0.5.0",
38
+ "project_id": "my-project",
39
+ "cwd": "/home/user/src"
40
+ }
41
+ ```
42
+
43
+ Both shapes are accepted — no migration needed. See [src/contracts/wire.ts](src/contracts/wire.ts) for the complete schema definition.
44
+
45
+ ## Why it exists
46
+
47
+ Claude Code sessions compact and terminate, taking context with them. AstraMemory Local captures
48
+ every session transcript, distills typed memories (decisions, facts, lessons, commands, todos),
49
+ and serves them back via hybrid search (BM25 + vector + importance + freshness). It runs entirely
50
+ on your workstation — no cloud account, no data leaves your machine. The plugin's hooks post to
51
+ the local daemon instead of the SaaS endpoint through a single environment variable swap.
52
+
53
+ ---
54
+
55
+ ## Quick start (5 commands)
56
+
57
+ ```bash
58
+ bun add -g @astragenie/astramemory-local
59
+ astra-memory init
60
+ # follow the wizard — picks Ollama or Azure, writes config.yaml + secrets.env
61
+ astra-memory service install
62
+ export MEMORY_API_URL=http://127.0.0.1:7777
63
+ export MEMORY_BEARER=$(astra-memory token print)
64
+ ```
65
+
66
+ Restart Claude Code. All plugin hooks (PreCompact, SessionEnd, SubagentStop) now post to the
67
+ local daemon. No other plugin changes needed.
68
+
69
+ ---
70
+
71
+ ## Architecture
72
+
73
+ ```
74
+ memory-plugin hooks
75
+ |
76
+ | POST /ingest/transcript (v0.2.0+ — SaaS-canonical envelope)
77
+ | Authorization: Bearer <token>
78
+ v
79
+ +------------------+ SQLite (memory.sqlite)
80
+ | HTTP daemon | ---> +-------------------+
81
+ | Fastify | | sessions |
82
+ | 127.0.0.1:7777 | | messages |
83
+ | (v0.2.0+) | | transcripts |
84
+ +------------------+ | ingest_idempotency|
85
+ | jobs (queue) |
86
+ | memories |
87
+ | memories_fts (FTS5)|
88
+ | memories_vec (vec0)|
89
+ | budget_spend |
90
+ +-------------------+
91
+ |
92
+ in-process worker loop
93
+ |
94
+ 8-stage distillation
95
+ (cleanup -> normalize ->
96
+ chunk -> compact ->
97
+ extract -> reduce ->
98
+ memory-normalize ->
99
+ embed + index)
100
+ |
101
+ +--------------+--------------+
102
+ | | |
103
+ memories FTS5 index sqlite-vec
104
+ (rows) (BM25 search) (cosine ANN)
105
+ | | |
106
+ +--------------+--------------+
107
+ |
108
+ hybrid score fusion
109
+ a*BM25 + b*cosine +
110
+ c*importance + d*freshness
111
+ |
112
+ GET /search POST /recall
113
+ |
114
+ /recall in plugin slash commands
115
+ ```
116
+
117
+ Single Node process. Workers run in-process on a polling loop. SQLite is the source of truth.
118
+ Everything derived (vectors, FTS rows, compactions) can be rebuilt by replaying the jobs table.
119
+
120
+ ---
121
+
122
+ ## Memory types
123
+
124
+ | Type | Description | Example |
125
+ |------------|--------------------------------------------------------|----------------------------------------------|
126
+ | `decision` | Architectural or design choice made during a session | "Use sqlite-vec for v1 vector storage" |
127
+ | `fact` | Objective project fact, configuration detail | "Port 7777 is the default daemon port" |
128
+ | `lesson` | Something that went wrong and how it was resolved | "sqlite-vec rowid must match memories rowid" |
129
+ | `command` | CLI command or script worth remembering | "bun run build && bun run test -- migrate" |
130
+ | `todo` | Outstanding work item surfaced in conversation | "Add reembed job when provider changes" |
131
+
132
+ ---
133
+
134
+ ## Provider matrix
135
+
136
+ | Concern | Ollama (local, free) | Azure OpenAI (cloud) |
137
+ |-----------------|------------------------------------------|----------------------------------------------|
138
+ | LLM compaction | qwen2.5-coder:7b (default) | gpt-4.1 or any deployment |
139
+ | LLM extraction | qwen2.5-coder:7b (default) | gpt-4.1 or any deployment |
140
+ | Embedding | nomic-embed-text-v2-moe (1024-dim) | text-embedding-3-small (1024 via dimensions) |
141
+ | Cost | $0 (local inference) | ~$0.02/1K tokens + $0.0001/1K embed tokens |
142
+ | Setup | `ollama serve` + `ollama pull <model>` | Azure portal + endpoint + deployment name |
143
+
144
+ Providers are configurable independently per stage. Embedding provider is system-wide — switching
145
+ requires `astra-memory rebuild --reembed` to re-index all memories in the new model's vector space.
146
+
147
+ See [docs/providers.md](docs/providers.md) for full setup instructions.
148
+
149
+ ---
150
+
151
+ ## Public endpoints
152
+
153
+ All endpoints require Bearer token authentication except `GET /version` and `GET /health`.
154
+ `GET /dashboard` additionally accepts an `HttpOnly` session cookie, bootstrapped via a one-time
155
+ `?token=` visit (see [Dashboard](#dashboard) below).
156
+
157
+ | Endpoint | Auth | Description |
158
+ |---|---|---|
159
+ | `GET /health` | — | Daemon health probe: `{ ok, version, wire_versions_supported, schema_version }` |
160
+ | `GET /version` | — | Version discovery: `{ name, version, wire_versions_supported, schema_version, ts }` |
161
+ | `POST /ingest/transcript` | Bearer | Capture protocol endpoint — accepts `transcript` and `events` kinds; idempotency via `Idempotency-Key` header. See [docs/capture-protocol.md](docs/capture-protocol.md). |
162
+ | `GET /search` | Bearer | Hybrid search with type/repo/project/since filters |
163
+ | `POST /recall` | Bearer | Top-K semantic recall (alias: `search` with k=5) |
164
+ | `POST /recall/pack` | Bearer | Token-budgeted memory pack for a repo/project/branch — powers the SessionStart hook |
165
+ | `POST /remember` | Bearer | Direct memory insert, bypasses distillation |
166
+ | `GET /memory/:id` | Bearer | Single memory lookup |
167
+ | `GET /memory/:id/why` | Bearer | Provenance receipt — extraction evidence + confidence for a memory |
168
+ | `GET /memory/:id/history` | Bearer | Full `memory_events` log for a memory (invalidate/supersede/promote chain) |
169
+ | `POST /memory/:id/invalidate` | Bearer | Soft-delete a memory (lifecycle op) |
170
+ | `POST /memory/:id/supersede` | Bearer | Replace a memory with a newer one, linked via `memory_events` |
171
+ | `POST /memory/:id/promote` | Bearer | Promote a memory's scope: personal → team → org |
172
+ | `POST /memory/:id/used` | Bearer | Record an explicit recall-usefulness signal for a memory |
173
+ | `GET /sessions/:id/digest` | Bearer | Session summary digest |
174
+ | `GET /dashboard` | Bearer, cookie, or one-time `?token=` bootstrap | Read-only HTML metrics dashboard, auto-refreshing every 5s |
175
+ | `POST /mcp` | Bearer | Model Context Protocol endpoint (auto-discovered tools, see below) |
176
+
177
+ ## MCP tools (Claude Code auto-discovery)
178
+
179
+ The daemon exposes a **Model Context Protocol** (Streamable HTTP) endpoint at `POST /mcp`.
180
+ Claude Code discovers and calls the tools below automatically when configured in `.mcp.json`.
181
+
182
+ | Tool | Description | Maps to |
183
+ |---|---|---|
184
+ | `search_memory` | Hybrid FTS + vector search with optional type/repo/project/since filters | `GET /search` |
185
+ | `recall_memory` | Top-K semantic recall (default k=5) | `POST /recall` |
186
+ | `remember` | Direct memory insert, bypasses distillation | `POST /remember` |
187
+ | `get_health` | Daemon health probe: `{ ok, version, wire_versions_supported, schema_version }` | `GET /health` |
188
+ | `why_memory` | Provenance receipt — extraction evidence + confidence for a memory | `GET /memory/:id/why` |
189
+ | `session_digest` | Session summary digest | `GET /sessions/:id/digest` |
190
+ | `invalidate_memory` | Soft-delete a memory (lifecycle op) | `POST /memory/:id/invalidate` |
191
+ | `supersede_memory` | Replace an old memory with a new one, linked via `memory_events` | `POST /memory/:id/supersede` |
192
+ | `promote_memory` | Promote a memory's scope: personal → team → org | `POST /memory/:id/promote` |
193
+ | `memory_history` | Full `memory_events` log for a memory | `GET /memory/:id/history` |
194
+ | `mark_memory_used` | Explicit recall-usefulness signal — "this memory mattered" | `POST /memory/:id/used` |
195
+
196
+ **Plugin `.mcp.json` wiring:**
197
+
198
+ ```json
199
+ {
200
+ "mcpServers": {
201
+ "astramem": {
202
+ "type": "http",
203
+ "url": "${MEMORY_API_URL}/mcp",
204
+ "headers": { "Authorization": "Bearer ${MEMORY_BEARER}" }
205
+ }
206
+ }
207
+ }
208
+ ```
209
+
210
+ Set `MEMORY_API_URL=http://127.0.0.1:7777` and `MEMORY_BEARER` to your token
211
+ (printed by `astra-memory token print`).
212
+
213
+ ---
214
+
215
+ ## Budget cap
216
+
217
+ The daily LLM spend cap (default: **$10 USD**) is enforced before each LLM call.
218
+
219
+ - Ollama always reports `$0` cost — the cap only applies to Azure usage.
220
+ - When the cap is reached, pending distillation jobs move to `paused` state. Ingest continues
221
+ to accept transcripts (no data loss). Distillation resumes the next UTC day automatically.
222
+ - Override: `astra-memory budget --reset` (logged).
223
+ - Check current spend: `astra-memory budget`.
224
+
225
+ ---
226
+
227
+ ## Security
228
+
229
+ ### Encryption at rest
230
+
231
+ `memory.sqlite` is encrypted by default using `better-sqlite3-multiple-ciphers` (SQLCipher-compatible
232
+ cipher driver). The 32-byte key is resolved through a provider chain:
233
+
234
+ 1. **OS credential store** — Windows Credential Manager / macOS Keychain / Linux libsecret, via
235
+ `@napi-rs/keyring`.
236
+ 2. **Key-file fallback** — `<configDir>/db.key` (mode `0600`) with a WARN log, used only when the
237
+ credential store throws (e.g. headless Linux with no secret-service session).
238
+
239
+ A pre-existing plaintext `memory.sqlite` (from a version predating encryption) is **auto-migrated**
240
+ transparently on daemon startup: the file is checkpointed, re-keyed via `PRAGMA rekey`, and
241
+ verified (row-count match) before the encrypted copy replaces the original. The pre-migration
242
+ plaintext file is preserved at `memory.sqlite.pre-encryption.bak` — nothing is deleted. Migration
243
+ is idempotent; an already-encrypted file is a no-op.
244
+
245
+ Disabling encryption (`security.encryption.enabled: false`) is a deliberate trust trade-off — the
246
+ daemon logs a prominent WARN at startup, and `astra-memory doctor` reports
247
+ `encryption: OFF — memory.sqlite is stored in PLAINTEXT`.
248
+
249
+ ### Stage-0 secret redaction
250
+
251
+ Every transcript turn and manual `/remember` write passes through a redaction choke point *before*
252
+ it is persisted — downstream pipeline stages only ever see already-redacted text. Detection runs in
253
+ three passes:
254
+
255
+ 1. **PEM private-key blocks** (multiline, whole block).
256
+ 2. **Vendor/pattern detectors** — AWS access keys, GitHub tokens, Azure storage keys/SAS tokens, GCP
257
+ API keys, Slack tokens, JWTs, generic `key=value` credentials, connection-string userinfo — plus
258
+ any org-specific regexes from `security.redaction.customPatterns`.
259
+ 3. **Shannon-entropy fallback** — flags high-entropy strings (default threshold 4.0 bits/char) that
260
+ pattern detectors missed.
261
+
262
+ Matches are replaced with a placeholder — `[REDACTED:<type>:<hash8>]`, where `hash8` is the first 8
263
+ hex chars of `SHA-256(secret value)` — so the same secret always redacts to the same placeholder
264
+ (dedup-safe) while the raw value is **never stored or logged**. Only counts are persisted, in the
265
+ `redaction_log` table (`type`, `count`, `session_id`, `created_at`) — `astra-memory doctor` surfaces
266
+ a 7-day breakdown, e.g. `redaction: on — 12 secrets redacted (3 aws_access_key, 9 generic_credential) in last 7d`.
267
+ Toggle with `security.redaction.enabled` (default `true`).
268
+
269
+ ### Bearer token storage
270
+
271
+ The daemon's Bearer token is stored the same way as the DB encryption key: OS credential store
272
+ first, `secrets.env` (mode `0600`) only as a fallback when the credential store is unavailable. A
273
+ token found only in `secrets.env` is opportunistically promoted into the credential store the next
274
+ time the daemon resolves it — `secrets.env` itself is never rewritten or deleted as part of that
275
+ promotion.
276
+
277
+ ---
278
+
279
+ ## Capture protocol
280
+
281
+ `astramem-local` accepts session capture from any tool that can speak one small HTTP contract —
282
+ `POST /ingest/transcript` with an `astramem-capture@1` envelope. Two kinds are supported:
283
+
284
+ - **`transcript`** (default) — raw turns, run through the full 8-stage distillation pipeline.
285
+ - **`events`** — pre-typed atom candidates (decision/fact/lesson/command/todo/note/event) that skip
286
+ the raw-text/LLM stages and enter directly at the reduce stage. Built for sources that already
287
+ know their own semantics (e.g. `runner-plugin` slice grades and lessons).
288
+
289
+ Both kinds pass through the same stage-0 redaction choke point described above. Writing a new tool
290
+ integration is a small translator — capture at the tool surface, shape into one envelope per session
291
+ boundary, POST it. See [docs/capture-protocol.md](docs/capture-protocol.md) for the full contract,
292
+ field reference, and a curl example.
293
+
294
+ ---
295
+
296
+ ## Memory lifecycle
297
+
298
+ Every memory has an append-only history in the `memory_events` log. Lifecycle operations never
299
+ delete a row — they append an event and update derived state:
300
+
301
+ | Operation | Effect |
302
+ |---|---|
303
+ | **Invalidate** | Soft-deletes a memory (optionally with a reason) — it stops surfacing in search/recall. |
304
+ | **Supersede** | Replaces an old memory with a new one; the two are linked via the event log. |
305
+ | **Promote** | Widens a memory's scope: `personal` → `team` → `org` (downward/same-scope transitions are rejected). |
306
+
307
+ `GET /memory/:id/history` (and the `memory_history` MCP tool) return the full event chain for a
308
+ memory — the complete invalidate/supersede/promote provenance trail.
309
+
310
+ **`why_memory` receipts** (`GET /memory/:id/why`, MCP `why_memory`) answer "why does the daemon
311
+ believe this?" — they return the extraction evidence and confidence that produced the memory, so a
312
+ recalled fact or decision can be traced back to its source.
313
+
314
+ ---
315
+
316
+ ## Usefulness metric
317
+
318
+ The daemon tracks a **recall-usefulness rate**: of the memories served by a search/recall/pack call,
319
+ how many were later marked as actually used (`POST /memory/:id/used`, MCP `mark_memory_used`, or the
320
+ REST twin). The rate is `distinct atoms used / distinct atoms served` in a given time window,
321
+ computed per memory type and per surface (`mcp` / `rest` / `cli`).
322
+
323
+ This is a **v1 measure-only signal** — it does not yet feed ranking (see ADR-010). Query text is
324
+ never stored; only a truncated SHA-256 digest of the query is kept alongside the served/used events,
325
+ themselves appended to the same `memory_events` log lifecycle operations use.
326
+
327
+ ---
328
+
329
+ ## Dashboard
330
+
331
+ `GET /dashboard` serves a single-file, auto-refreshing (every 5s) HTML metrics page — no
332
+ JavaScript, no CDN, no external assets, dark mode by default. It shows memory counts by type,
333
+ recent captures, job-queue state, distill throughput, provider health, today/MTD budget spend vs
334
+ cap, and the pending-capture queue depth.
335
+
336
+ Auth accepts either the usual `Authorization: Bearer <token>` header, or an `HttpOnly` session
337
+ cookie. To open the dashboard directly in a browser (which can't set an `Authorization` header),
338
+ visit it once with `?token=<bearer>` — the daemon exchanges that for the cookie via a 302 redirect
339
+ to the clean URL, so the bearer never persists in browser history or gets re-sent by the
340
+ `<meta refresh>` poll. A missing or wrong credential returns a plain-text 401, never HTML, and the
341
+ query string is stripped from the log line so a wrong `?token=` guess doesn't persist a candidate
342
+ secret.
343
+
344
+ ---
345
+
346
+ ## Commands reference
347
+
348
+ | Command | What it does |
349
+ |--------------------------------------------|----------------------------------------------------|
350
+ | `astra-memory init [--no-hook]` | Interactive wizard — writes config + secrets, runs migrations, installs service, offers the SessionStart memory-pack hook |
351
+ | `astra-memory serve [--port N]` | Start daemon in foreground (dev/debug) |
352
+ | `astra-memory service install` | Register daemon as a user-scope OS service |
353
+ | `astra-memory service status` | Show service state |
354
+ | `astra-memory service start` | Start the service |
355
+ | `astra-memory service stop` | Stop the service |
356
+ | `astra-memory service uninstall` | Remove the service unit |
357
+ | `astra-memory doctor` | Run all health checks, print table |
358
+ | `astra-memory doctor --json` | Machine-readable health check output |
359
+ | `astra-memory search "<query>"` | Hybrid search, print results table |
360
+ | `astra-memory search "<query>" --type decision` | Filter by memory type |
361
+ | `astra-memory recall "<question>"` | Top-5 semantic recall (alias for search k=5) |
362
+ | `astra-memory remember "<text>" [--type]` | Direct insert, bypasses distillation pipeline |
363
+ | `astra-memory queue` | Show pending/failed jobs |
364
+ | `astra-memory queue --state failed` | Show only failed jobs |
365
+ | `astra-memory rebuild [--reembed]` | Rebuild derived indexes; --reembed re-vectors all |
366
+ | `astra-memory providers list` | List configured providers and their health |
367
+ | `astra-memory providers test [name]` | Ping provider, print latency + dim |
368
+ | `astra-memory budget` | Show today and month spend vs cap |
369
+ | `astra-memory budget --reset` | Clear today's spend counter (override, logged) |
370
+ | `astra-memory token print` | Print the current Bearer token |
371
+ | `astra-memory token rotate` | Generate new token, invalidate the old one |
372
+
373
+ ---
374
+
375
+ ## Further reading
376
+
377
+ - [docs/migration-from-saas.md](docs/migration-from-saas.md) — switch the plugin from remote SaaS to local daemon
378
+ - [docs/configuration.md](docs/configuration.md) — full config.yaml reference
379
+ - [docs/providers.md](docs/providers.md) — Ollama and Azure OpenAI setup
380
+ - [docs/capture-protocol.md](docs/capture-protocol.md) — `astramem-capture@1` wire contract (`transcript` + `events` kinds)
381
+ - [docs/hooks/memory-pack.md](docs/hooks/memory-pack.md) — SessionStart memory-pack hook (auto-installed by `init`)
382
+ - [docs/troubleshooting.md](docs/troubleshooting.md) — common issues and fixes
383
+ - [docs/contracts.md](docs/contracts.md) — frozen type interfaces (for contributors)
384
+ - [CHANGELOG.md](CHANGELOG.md) — release history
385
+
386
+ ---
387
+
388
+ ## Development
389
+
390
+ This project uses [Bun](https://bun.sh/) as the package manager and script runner.
391
+
392
+ ```bash
393
+ bun install # install dependencies
394
+ bun run build # compile TypeScript → dist/
395
+ bun run test # run the vitest suite
396
+ ```
397
+
398
+ **Publishing** (maintainers only):
399
+
400
+ ```bash
401
+ bun publish # publishes to GitHub Packages via .npmrc (same token as npm publish)
402
+ ```
403
+
404
+ > **Why Bun?** Faster installs, a single binary, and `bun publish` works natively with the existing
405
+ > `.npmrc` / GH Packages setup. Tests still run through vitest (`bun run test`) because the vitest
406
+ > suite uses `better-sqlite3` native bindings which are not yet compatible with Bun's own test runner.
407
+
408
+ ---
409
+
410
+ ## Status
411
+
412
+ **v0.1.0** — Waves 1-4 of the implementation plan completed.
413
+
414
+ - Wave 1: SQLite schema, migration runner, FTS5, sqlite-vec, ingest endpoint, Fastify server, CLI skeleton.
415
+ - Wave 2: Job worker loop, hybrid search, service install adapters, Ollama + Azure providers.
416
+ - Wave 3: 8-stage distillation pipeline, budget tracker, Zod-validated extraction.
417
+ - Wave 4: Install wizard, cross-OS CI matrix, E2E plugin integration test, this documentation.
418
+
419
+ Spec: [astramemory-plugin/docs/superpowers/specs/2026-06-27-astramemory-local-v1-design.md](../astramemory-plugin/docs/superpowers/specs/2026-06-27-astramemory-local-v1-design.md)
@@ -0,0 +1,15 @@
1
+ export interface RetentionResult {
2
+ kept: string[];
3
+ deleted: string[];
4
+ }
5
+ /**
6
+ * Prune old backup snapshots in `dir`, keeping the newest `keep` files.
7
+ *
8
+ * Only files matching `memory-*.sqlite` are considered — other files in the
9
+ * directory are left untouched.
10
+ *
11
+ * @param dir Directory to scan (must exist; throws if not readable).
12
+ * @param keep Number of snapshots to retain (must be >= 1).
13
+ * @returns { kept, deleted } arrays of absolute paths.
14
+ */
15
+ export declare function pruneOldBackups(dir: string, keep: number): RetentionResult;
@@ -0,0 +1,62 @@
1
+ /**
2
+ * retention.ts — prune old backup snapshots, keeping the newest N.
3
+ *
4
+ * Scans `dir` for files matching `memory-*.sqlite`, sorts by mtime descending,
5
+ * keeps the first `keep`, deletes the rest.
6
+ */
7
+ import { readdirSync, statSync, unlinkSync } from 'node:fs';
8
+ import { join } from 'node:path';
9
+ /**
10
+ * Prune old backup snapshots in `dir`, keeping the newest `keep` files.
11
+ *
12
+ * Only files matching `memory-*.sqlite` are considered — other files in the
13
+ * directory are left untouched.
14
+ *
15
+ * @param dir Directory to scan (must exist; throws if not readable).
16
+ * @param keep Number of snapshots to retain (must be >= 1).
17
+ * @returns { kept, deleted } arrays of absolute paths.
18
+ */
19
+ export function pruneOldBackups(dir, keep) {
20
+ if (keep < 1)
21
+ throw new RangeError(`keep must be >= 1, got ${keep}`);
22
+ // Gather candidate files
23
+ let entries;
24
+ try {
25
+ entries = readdirSync(dir);
26
+ }
27
+ catch (err) {
28
+ // Directory does not exist yet — nothing to prune
29
+ return { kept: [], deleted: [] };
30
+ }
31
+ const candidates = entries
32
+ .filter(name => /^memory-.*\.sqlite$/.test(name))
33
+ .map(name => {
34
+ const fullPath = join(dir, name);
35
+ let mtime = 0;
36
+ try {
37
+ mtime = statSync(fullPath).mtimeMs;
38
+ }
39
+ catch {
40
+ // File vanished between readdir and stat — skip it
41
+ return null;
42
+ }
43
+ return { path: fullPath, mtime };
44
+ })
45
+ .filter((x) => x !== null);
46
+ // Sort newest first
47
+ candidates.sort((a, b) => b.mtime - a.mtime);
48
+ const kept = candidates.slice(0, keep).map(c => c.path);
49
+ const toDelete = candidates.slice(keep);
50
+ const deleted = [];
51
+ for (const candidate of toDelete) {
52
+ try {
53
+ unlinkSync(candidate.path);
54
+ deleted.push(candidate.path);
55
+ }
56
+ catch {
57
+ // Best-effort: if deletion fails (e.g. race condition) skip it
58
+ }
59
+ }
60
+ return { kept, deleted };
61
+ }
62
+ //# sourceMappingURL=retention.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retention.js","sourceRoot":"","sources":["../../src/backup/retention.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAOjC;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW,EAAE,IAAY;IACvD,IAAI,IAAI,GAAG,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,0BAA0B,IAAI,EAAE,CAAC,CAAC;IAErE,yBAAyB;IACzB,IAAI,OAAiB,CAAC;IACtB,IAAI,CAAC;QACH,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,kDAAkD;QAClD,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACnC,CAAC;IAED,MAAM,UAAU,GAAG,OAAO;SACvB,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;SAChD,GAAG,CAAC,IAAI,CAAC,EAAE;QACV,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACjC,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,CAAC;YACH,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC;QACrC,CAAC;QAAC,MAAM,CAAC;YACP,mDAAmD;YACnD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IACnC,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,CAAC,EAAwC,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;IAEnE,oBAAoB;IACpB,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAE7C,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,SAAS,IAAI,QAAQ,EAAE,CAAC;QACjC,IAAI,CAAC;YACH,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAC3B,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,+DAA+D;QACjE,CAAC;IACH,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { DB } from '../storage/db.js';
2
+ export interface SnapshotResult {
3
+ path: string;
4
+ size_bytes: number;
5
+ duration_ms: number;
6
+ }
7
+ /**
8
+ * Create an online-safe snapshot of `db` to `outPath`.
9
+ *
10
+ * The directory containing outPath is created if it does not exist.
11
+ * Uses db.backup() (online-safe, zero downtime) when available; falls back
12
+ * to `VACUUM INTO` otherwise. When `db` is an encrypted (SQLCipher) database,
13
+ * the backup/VACUUM INTO output is encrypted with the same key — SQLite's
14
+ * online backup API and VACUUM INTO both operate on the live connection's
15
+ * pages, so ciphertext pages are copied as ciphertext (SEC-8).
16
+ *
17
+ * @param db An open better-sqlite3-multiple-ciphers Database instance.
18
+ * @param outPath Absolute destination path for the snapshot file.
19
+ * @returns Metadata about the written snapshot.
20
+ */
21
+ export declare function createSnapshot(db: DB, outPath: string): Promise<SnapshotResult>;
@@ -0,0 +1,55 @@
1
+ /**
2
+ * snapshot.ts — online-safe SQLite backup using better-sqlite3's built-in
3
+ * backup API (which uses the SQLite Online Backup API under the hood).
4
+ *
5
+ * Falls back to VACUUM INTO if the better-sqlite3 version does not expose
6
+ * db.backup().
7
+ */
8
+ import { mkdirSync, statSync, rmSync } from 'node:fs';
9
+ import { dirname } from 'node:path';
10
+ /**
11
+ * Create an online-safe snapshot of `db` to `outPath`.
12
+ *
13
+ * The directory containing outPath is created if it does not exist.
14
+ * Uses db.backup() (online-safe, zero downtime) when available; falls back
15
+ * to `VACUUM INTO` otherwise. When `db` is an encrypted (SQLCipher) database,
16
+ * the backup/VACUUM INTO output is encrypted with the same key — SQLite's
17
+ * online backup API and VACUUM INTO both operate on the live connection's
18
+ * pages, so ciphertext pages are copied as ciphertext (SEC-8).
19
+ *
20
+ * @param db An open better-sqlite3-multiple-ciphers Database instance.
21
+ * @param outPath Absolute destination path for the snapshot file.
22
+ * @returns Metadata about the written snapshot.
23
+ */
24
+ export async function createSnapshot(db, outPath) {
25
+ // Ensure parent directory exists
26
+ mkdirSync(dirname(outPath), { recursive: true });
27
+ const start = Date.now();
28
+ const vacuumInto = () => {
29
+ // VACUUM INTO is online-safe per SQLite docs (consistent snapshot, does
30
+ // not block writes). Under SQLite3MultipleCiphers the output inherits the
31
+ // main database's encryption, so ciphertext stays ciphertext (SEC-8).
32
+ rmSync(outPath, { force: true }); // VACUUM INTO refuses existing targets
33
+ db.exec(`VACUUM INTO '${outPath.replace(/'/g, "''")}'`);
34
+ };
35
+ if (typeof db.backup === 'function') {
36
+ // better-sqlite3 >= 7.6 exposes db.backup(path) which uses the
37
+ // SQLite Online Backup API — safe to run while the DB is in use.
38
+ // On an ENCRYPTED connection the cipher driver rejects the plaintext
39
+ // target with "backup is not supported with incompatible source and
40
+ // target databases" — fall back to VACUUM INTO in that case.
41
+ try {
42
+ await db.backup(outPath);
43
+ }
44
+ catch {
45
+ vacuumInto();
46
+ }
47
+ }
48
+ else {
49
+ vacuumInto();
50
+ }
51
+ const duration_ms = Date.now() - start;
52
+ const { size: size_bytes } = statSync(outPath);
53
+ return { path: outPath, size_bytes, duration_ms };
54
+ }
55
+ //# sourceMappingURL=snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../src/backup/snapshot.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,EAAM,EACN,OAAe;IAEf,iCAAiC;IACjC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEjD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAEzB,MAAM,UAAU,GAAG,GAAG,EAAE;QACtB,wEAAwE;QACxE,0EAA0E;QAC1E,sEAAsE;QACtE,MAAM,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,uCAAuC;QACzE,EAAE,CAAC,IAAI,CAAC,gBAAgB,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1D,CAAC,CAAC;IAEF,IAAI,OAAQ,EAAU,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QAC7C,+DAA+D;QAC/D,iEAAiE;QACjE,qEAAqE;QACrE,oEAAoE;QACpE,6DAA6D;QAC7D,IAAI,CAAC;YACH,MAAO,EAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACpC,CAAC;QAAC,MAAM,CAAC;YACP,UAAU,EAAE,CAAC;QACf,CAAC;IACH,CAAC;SAAM,CAAC;QACN,UAAU,EAAE,CAAC;IACf,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;IACvC,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAE/C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC;AACpD,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { DB } from '../storage/db.js';
2
+ export interface VerifyResult {
3
+ ok: boolean;
4
+ integrity: string;
5
+ counts: {
6
+ memories: {
7
+ live: number;
8
+ snapshot: number;
9
+ };
10
+ transcripts: {
11
+ live: number;
12
+ snapshot: number;
13
+ };
14
+ };
15
+ error?: string;
16
+ }
17
+ /**
18
+ * Verify `snapshotPath` against the live `db` it was snapshotted from.
19
+ * Row-count tolerance: the live DB may have gained rows since the snapshot
20
+ * started (online backup), so snapshot counts must be <= live counts and
21
+ * within `tolerance` of them — never greater, never wildly behind.
22
+ */
23
+ export declare function verifySnapshot(liveDb: DB, snapshotPath: string, key?: string, tolerance?: number): VerifyResult;