@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.
- package/CHANGELOG.md +341 -0
- package/README.md +419 -0
- package/dist/backup/retention.d.ts +15 -0
- package/dist/backup/retention.js +62 -0
- package/dist/backup/retention.js.map +1 -0
- package/dist/backup/snapshot.d.ts +21 -0
- package/dist/backup/snapshot.js +55 -0
- package/dist/backup/snapshot.js.map +1 -0
- package/dist/backup/verify.d.ts +23 -0
- package/dist/backup/verify.js +77 -0
- package/dist/backup/verify.js.map +1 -0
- package/dist/budget/tracker.d.ts +58 -0
- package/dist/budget/tracker.js +102 -0
- package/dist/budget/tracker.js.map +1 -0
- package/dist/capture/codex.d.ts +63 -0
- package/dist/capture/codex.js +0 -0
- package/dist/capture/codex.js.map +1 -0
- package/dist/cli/backup.d.ts +1 -0
- package/dist/cli/backup.js +112 -0
- package/dist/cli/backup.js.map +1 -0
- package/dist/cli/budget.d.ts +7 -0
- package/dist/cli/budget.js +44 -0
- package/dist/cli/budget.js.map +1 -0
- package/dist/cli/capture.d.ts +10 -0
- package/dist/cli/capture.js +113 -0
- package/dist/cli/capture.js.map +1 -0
- package/dist/cli/consolidate.d.ts +16 -0
- package/dist/cli/consolidate.js +146 -0
- package/dist/cli/consolidate.js.map +1 -0
- package/dist/cli/doctor.d.ts +1 -0
- package/dist/cli/doctor.js +54 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/entity-backfill.d.ts +10 -0
- package/dist/cli/entity-backfill.js +46 -0
- package/dist/cli/entity-backfill.js.map +1 -0
- package/dist/cli/hook-install.d.ts +45 -0
- package/dist/cli/hook-install.js +77 -0
- package/dist/cli/hook-install.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +312 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +16 -0
- package/dist/cli/init.js +431 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/mcp-stdio.d.ts +18 -0
- package/dist/cli/mcp-stdio.js +67 -0
- package/dist/cli/mcp-stdio.js.map +1 -0
- package/dist/cli/memory.d.ts +15 -0
- package/dist/cli/memory.js +52 -0
- package/dist/cli/memory.js.map +1 -0
- package/dist/cli/open-runtime-db.d.ts +15 -0
- package/dist/cli/open-runtime-db.js +37 -0
- package/dist/cli/open-runtime-db.js.map +1 -0
- package/dist/cli/pair.d.ts +29 -0
- package/dist/cli/pair.js +64 -0
- package/dist/cli/pair.js.map +1 -0
- package/dist/cli/providers.d.ts +10 -0
- package/dist/cli/providers.js +97 -0
- package/dist/cli/providers.js.map +1 -0
- package/dist/cli/queue-purge.d.ts +5 -0
- package/dist/cli/queue-purge.js +92 -0
- package/dist/cli/queue-purge.js.map +1 -0
- package/dist/cli/queue.d.ts +29 -0
- package/dist/cli/queue.js +73 -0
- package/dist/cli/queue.js.map +1 -0
- package/dist/cli/rebuild.d.ts +15 -0
- package/dist/cli/rebuild.js +70 -0
- package/dist/cli/rebuild.js.map +1 -0
- package/dist/cli/reembed-dim.d.ts +21 -0
- package/dist/cli/reembed-dim.js +199 -0
- package/dist/cli/reembed-dim.js.map +1 -0
- package/dist/cli/reinstall.d.ts +1 -0
- package/dist/cli/reinstall.js +205 -0
- package/dist/cli/reinstall.js.map +1 -0
- package/dist/cli/restore.d.ts +1 -0
- package/dist/cli/restore.js +167 -0
- package/dist/cli/restore.js.map +1 -0
- package/dist/cli/retag.d.ts +14 -0
- package/dist/cli/retag.js +62 -0
- package/dist/cli/retag.js.map +1 -0
- package/dist/cli/search.d.ts +66 -0
- package/dist/cli/search.js +174 -0
- package/dist/cli/search.js.map +1 -0
- package/dist/cli/serve.d.ts +9 -0
- package/dist/cli/serve.js +364 -0
- package/dist/cli/serve.js.map +1 -0
- package/dist/cli/service.d.ts +1 -0
- package/dist/cli/service.js +121 -0
- package/dist/cli/service.js.map +1 -0
- package/dist/cli/sync.d.ts +15 -0
- package/dist/cli/sync.js +61 -0
- package/dist/cli/sync.js.map +1 -0
- package/dist/cli/token.d.ts +24 -0
- package/dist/cli/token.js +77 -0
- package/dist/cli/token.js.map +1 -0
- package/dist/cli/wait-health.d.ts +4 -0
- package/dist/cli/wait-health.js +23 -0
- package/dist/cli/wait-health.js.map +1 -0
- package/dist/config/config.d.ts +127 -0
- package/dist/config/config.js +38 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/datadir.d.ts +30 -0
- package/dist/config/datadir.js +65 -0
- package/dist/config/datadir.js.map +1 -0
- package/dist/config/loader.d.ts +23 -0
- package/dist/config/loader.js +102 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/migrate-dirs.d.ts +36 -0
- package/dist/config/migrate-dirs.js +132 -0
- package/dist/config/migrate-dirs.js.map +1 -0
- package/dist/config/persist-envs.d.ts +23 -0
- package/dist/config/persist-envs.js +119 -0
- package/dist/config/persist-envs.js.map +1 -0
- package/dist/config/resolve-runtime.d.ts +19 -0
- package/dist/config/resolve-runtime.js +53 -0
- package/dist/config/resolve-runtime.js.map +1 -0
- package/dist/config/secrets.d.ts +28 -0
- package/dist/config/secrets.js +38 -0
- package/dist/config/secrets.js.map +1 -0
- package/dist/config/sync-settings.d.ts +16 -0
- package/dist/config/sync-settings.js +34 -0
- package/dist/config/sync-settings.js.map +1 -0
- package/dist/config/writer.d.ts +19 -0
- package/dist/config/writer.js +121 -0
- package/dist/config/writer.js.map +1 -0
- package/dist/consolidate/consolidate.d.ts +80 -0
- package/dist/consolidate/consolidate.js +0 -0
- package/dist/consolidate/consolidate.js.map +1 -0
- package/dist/consolidate/proposals.d.ts +35 -0
- package/dist/consolidate/proposals.js +66 -0
- package/dist/consolidate/proposals.js.map +1 -0
- package/dist/contracts/atom-wire.d.ts +48 -0
- package/dist/contracts/atom-wire.js +55 -0
- package/dist/contracts/atom-wire.js.map +1 -0
- package/dist/contracts/embed.d.ts +41 -0
- package/dist/contracts/embed.js +20 -0
- package/dist/contracts/embed.js.map +1 -0
- package/dist/contracts/index.d.ts +5 -0
- package/dist/contracts/index.js +6 -0
- package/dist/contracts/index.js.map +1 -0
- package/dist/contracts/job.d.ts +113 -0
- package/dist/contracts/job.js +32 -0
- package/dist/contracts/job.js.map +1 -0
- package/dist/contracts/llm.d.ts +30 -0
- package/dist/contracts/llm.js +2 -0
- package/dist/contracts/llm.js.map +1 -0
- package/dist/contracts/memory.d.ts +47 -0
- package/dist/contracts/memory.js +5 -0
- package/dist/contracts/memory.js.map +1 -0
- package/dist/contracts/vector.d.ts +29 -0
- package/dist/contracts/vector.js +2 -0
- package/dist/contracts/vector.js.map +1 -0
- package/dist/distill/flatten-turns.d.ts +1 -0
- package/dist/distill/flatten-turns.js +50 -0
- package/dist/distill/flatten-turns.js.map +1 -0
- package/dist/distill/pipeline.d.ts +45 -0
- package/dist/distill/pipeline.js +113 -0
- package/dist/distill/pipeline.js.map +1 -0
- package/dist/distill/prompts/extract.d.ts +122 -0
- package/dist/distill/prompts/extract.js +67 -0
- package/dist/distill/prompts/extract.js.map +1 -0
- package/dist/distill/stages/01-cleanup.d.ts +9 -0
- package/dist/distill/stages/01-cleanup.js +67 -0
- package/dist/distill/stages/01-cleanup.js.map +1 -0
- package/dist/distill/stages/02-normalize.d.ts +9 -0
- package/dist/distill/stages/02-normalize.js +76 -0
- package/dist/distill/stages/02-normalize.js.map +1 -0
- package/dist/distill/stages/03-chunk.d.ts +22 -0
- package/dist/distill/stages/03-chunk.js +138 -0
- package/dist/distill/stages/03-chunk.js.map +1 -0
- package/dist/distill/stages/04-compact.d.ts +28 -0
- package/dist/distill/stages/04-compact.js +69 -0
- package/dist/distill/stages/04-compact.js.map +1 -0
- package/dist/distill/stages/05-extract.d.ts +35 -0
- package/dist/distill/stages/05-extract.js +101 -0
- package/dist/distill/stages/05-extract.js.map +1 -0
- package/dist/distill/stages/06-reduce.d.ts +16 -0
- package/dist/distill/stages/06-reduce.js +30 -0
- package/dist/distill/stages/06-reduce.js.map +1 -0
- package/dist/distill/stages/07-memory-normalize.d.ts +27 -0
- package/dist/distill/stages/07-memory-normalize.js +65 -0
- package/dist/distill/stages/07-memory-normalize.js.map +1 -0
- package/dist/distill/stages/08-embed-index.d.ts +31 -0
- package/dist/distill/stages/08-embed-index.js +82 -0
- package/dist/distill/stages/08-embed-index.js.map +1 -0
- package/dist/doctor/checks.d.ts +77 -0
- package/dist/doctor/checks.js +626 -0
- package/dist/doctor/checks.js.map +1 -0
- package/dist/doctor/hardening-checks.d.ts +9 -0
- package/dist/doctor/hardening-checks.js +182 -0
- package/dist/doctor/hardening-checks.js.map +1 -0
- package/dist/doctor/probes/embed-probe.d.ts +19 -0
- package/dist/doctor/probes/embed-probe.js +47 -0
- package/dist/doctor/probes/embed-probe.js.map +1 -0
- package/dist/doctor/probes/llm-chat-probe.d.ts +11 -0
- package/dist/doctor/probes/llm-chat-probe.js +41 -0
- package/dist/doctor/probes/llm-chat-probe.js.map +1 -0
- package/dist/doctor/probes/plugin-coexistence.d.ts +14 -0
- package/dist/doctor/probes/plugin-coexistence.js +60 -0
- package/dist/doctor/probes/plugin-coexistence.js.map +1 -0
- package/dist/doctor/runner.d.ts +17 -0
- package/dist/doctor/runner.js +53 -0
- package/dist/doctor/runner.js.map +1 -0
- package/dist/doctor/types.d.ts +12 -0
- package/dist/doctor/types.js +2 -0
- package/dist/doctor/types.js.map +1 -0
- package/dist/entity/backfill.d.ts +30 -0
- package/dist/entity/backfill.js +55 -0
- package/dist/entity/backfill.js.map +1 -0
- package/dist/entity/extract-entities.d.ts +27 -0
- package/dist/entity/extract-entities.js +86 -0
- package/dist/entity/extract-entities.js.map +1 -0
- package/dist/entity/normalize.d.ts +17 -0
- package/dist/entity/normalize.js +20 -0
- package/dist/entity/normalize.js.map +1 -0
- package/dist/eval/harness.d.ts +96 -0
- package/dist/eval/harness.js +119 -0
- package/dist/eval/harness.js.map +1 -0
- package/dist/eval/metrics.d.ts +23 -0
- package/dist/eval/metrics.js +44 -0
- package/dist/eval/metrics.js.map +1 -0
- package/dist/log/correlation.d.ts +24 -0
- package/dist/log/correlation.js +33 -0
- package/dist/log/correlation.js.map +1 -0
- package/dist/log/logger.d.ts +38 -0
- package/dist/log/logger.js +129 -0
- package/dist/log/logger.js.map +1 -0
- package/dist/log/scrub.d.ts +33 -0
- package/dist/log/scrub.js +91 -0
- package/dist/log/scrub.js.map +1 -0
- package/dist/mcp/server.d.ts +36 -0
- package/dist/mcp/server.js +553 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/memory-tool/adapter.d.ts +73 -0
- package/dist/memory-tool/adapter.js +269 -0
- package/dist/memory-tool/adapter.js.map +1 -0
- package/dist/pipeline/errors.d.ts +21 -0
- package/dist/pipeline/errors.js +34 -0
- package/dist/pipeline/errors.js.map +1 -0
- package/dist/pipeline/failure-classifier.d.ts +13 -0
- package/dist/pipeline/failure-classifier.js +72 -0
- package/dist/pipeline/failure-classifier.js.map +1 -0
- package/dist/pipeline/handler-ctx-ext.d.ts +23 -0
- package/dist/pipeline/handler-ctx-ext.js +19 -0
- package/dist/pipeline/handler-ctx-ext.js.map +1 -0
- package/dist/pipeline/handler.d.ts +20 -0
- package/dist/pipeline/handler.js +2 -0
- package/dist/pipeline/handler.js.map +1 -0
- package/dist/pipeline/handlers/cleanup.d.ts +14 -0
- package/dist/pipeline/handlers/cleanup.js +47 -0
- package/dist/pipeline/handlers/cleanup.js.map +1 -0
- package/dist/pipeline/handlers/consolidate.d.ts +8 -0
- package/dist/pipeline/handlers/consolidate.js +23 -0
- package/dist/pipeline/handlers/consolidate.js.map +1 -0
- package/dist/pipeline/handlers/distill-events.d.ts +15 -0
- package/dist/pipeline/handlers/distill-events.js +134 -0
- package/dist/pipeline/handlers/distill-events.js.map +1 -0
- package/dist/pipeline/handlers/distill.d.ts +17 -0
- package/dist/pipeline/handlers/distill.js +110 -0
- package/dist/pipeline/handlers/distill.js.map +1 -0
- package/dist/pipeline/handlers/reembed.d.ts +10 -0
- package/dist/pipeline/handlers/reembed.js +34 -0
- package/dist/pipeline/handlers/reembed.js.map +1 -0
- package/dist/pipeline/job-repo.d.ts +86 -0
- package/dist/pipeline/job-repo.js +168 -0
- package/dist/pipeline/job-repo.js.map +1 -0
- package/dist/pipeline/mock-providers.d.ts +49 -0
- package/dist/pipeline/mock-providers.js +175 -0
- package/dist/pipeline/mock-providers.js.map +1 -0
- package/dist/pipeline/registry.d.ts +15 -0
- package/dist/pipeline/registry.js +20 -0
- package/dist/pipeline/registry.js.map +1 -0
- package/dist/pipeline/worker.d.ts +41 -0
- package/dist/pipeline/worker.js +167 -0
- package/dist/pipeline/worker.js.map +1 -0
- package/dist/providers/embed/azure-openai.d.ts +25 -0
- package/dist/providers/embed/azure-openai.js +138 -0
- package/dist/providers/embed/azure-openai.js.map +1 -0
- package/dist/providers/embed/ollama.d.ts +17 -0
- package/dist/providers/embed/ollama.js +106 -0
- package/dist/providers/embed/ollama.js.map +1 -0
- package/dist/providers/index.d.ts +19 -0
- package/dist/providers/index.js +72 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/llm/azure-openai.d.ts +20 -0
- package/dist/providers/llm/azure-openai.js +135 -0
- package/dist/providers/llm/azure-openai.js.map +1 -0
- package/dist/providers/llm/ollama.d.ts +13 -0
- package/dist/providers/llm/ollama.js +113 -0
- package/dist/providers/llm/ollama.js.map +1 -0
- package/dist/providers/llm/pricing.d.ts +21 -0
- package/dist/providers/llm/pricing.js +22 -0
- package/dist/providers/llm/pricing.js.map +1 -0
- package/dist/recall/pack.d.ts +32 -0
- package/dist/recall/pack.js +90 -0
- package/dist/recall/pack.js.map +1 -0
- package/dist/recall/policy.d.ts +39 -0
- package/dist/recall/policy.js +96 -0
- package/dist/recall/policy.js.map +1 -0
- package/dist/redact/detectors.d.ts +20 -0
- package/dist/redact/detectors.js +85 -0
- package/dist/redact/detectors.js.map +1 -0
- package/dist/redact/entropy.d.ts +24 -0
- package/dist/redact/entropy.js +77 -0
- package/dist/redact/entropy.js.map +1 -0
- package/dist/redact/index.d.ts +47 -0
- package/dist/redact/index.js +165 -0
- package/dist/redact/index.js.map +1 -0
- package/dist/search/fuse.d.ts +108 -0
- package/dist/search/fuse.js +135 -0
- package/dist/search/fuse.js.map +1 -0
- package/dist/search/query.d.ts +28 -0
- package/dist/search/query.js +70 -0
- package/dist/search/query.js.map +1 -0
- package/dist/search/search.d.ts +164 -0
- package/dist/search/search.js +310 -0
- package/dist/search/search.js.map +1 -0
- package/dist/server/app.d.ts +17 -0
- package/dist/server/app.js +133 -0
- package/dist/server/app.js.map +1 -0
- package/dist/server/health-state.d.ts +29 -0
- package/dist/server/health-state.js +28 -0
- package/dist/server/health-state.js.map +1 -0
- package/dist/server/lib/network.d.ts +12 -0
- package/dist/server/lib/network.js +16 -0
- package/dist/server/lib/network.js.map +1 -0
- package/dist/server/lib/score-contract.d.ts +36 -0
- package/dist/server/lib/score-contract.js +54 -0
- package/dist/server/lib/score-contract.js.map +1 -0
- package/dist/server/lib/stable-stringify.d.ts +10 -0
- package/dist/server/lib/stable-stringify.js +27 -0
- package/dist/server/lib/stable-stringify.js.map +1 -0
- package/dist/server/lib/wire-meta.d.ts +7 -0
- package/dist/server/lib/wire-meta.js +29 -0
- package/dist/server/lib/wire-meta.js.map +1 -0
- package/dist/server/queries/dashboard.d.ts +142 -0
- package/dist/server/queries/dashboard.js +166 -0
- package/dist/server/queries/dashboard.js.map +1 -0
- package/dist/server/routes/consolidation.d.ts +14 -0
- package/dist/server/routes/consolidation.js +67 -0
- package/dist/server/routes/consolidation.js.map +1 -0
- package/dist/server/routes/dashboard-api-html.d.ts +15 -0
- package/dist/server/routes/dashboard-api-html.js +144 -0
- package/dist/server/routes/dashboard-api-html.js.map +1 -0
- package/dist/server/routes/dashboard-consolidation-html.d.ts +26 -0
- package/dist/server/routes/dashboard-consolidation-html.js +202 -0
- package/dist/server/routes/dashboard-consolidation-html.js.map +1 -0
- package/dist/server/routes/dashboard-html.d.ts +15 -0
- package/dist/server/routes/dashboard-html.js +365 -0
- package/dist/server/routes/dashboard-html.js.map +1 -0
- package/dist/server/routes/dashboard-jobs-html.d.ts +18 -0
- package/dist/server/routes/dashboard-jobs-html.js +186 -0
- package/dist/server/routes/dashboard-jobs-html.js.map +1 -0
- package/dist/server/routes/dashboard-search-html.d.ts +18 -0
- package/dist/server/routes/dashboard-search-html.js +189 -0
- package/dist/server/routes/dashboard-search-html.js.map +1 -0
- package/dist/server/routes/dashboard.d.ts +19 -0
- package/dist/server/routes/dashboard.js +68 -0
- package/dist/server/routes/dashboard.js.map +1 -0
- package/dist/server/routes/digest.d.ts +9 -0
- package/dist/server/routes/digest.js +37 -0
- package/dist/server/routes/digest.js.map +1 -0
- package/dist/server/routes/entities.d.ts +12 -0
- package/dist/server/routes/entities.js +46 -0
- package/dist/server/routes/entities.js.map +1 -0
- package/dist/server/routes/health.d.ts +14 -0
- package/dist/server/routes/health.js +100 -0
- package/dist/server/routes/health.js.map +1 -0
- package/dist/server/routes/ingest.d.ts +209 -0
- package/dist/server/routes/ingest.js +454 -0
- package/dist/server/routes/ingest.js.map +1 -0
- package/dist/server/routes/lifecycle.d.ts +21 -0
- package/dist/server/routes/lifecycle.js +132 -0
- package/dist/server/routes/lifecycle.js.map +1 -0
- package/dist/server/routes/mcp.d.ts +15 -0
- package/dist/server/routes/mcp.js +36 -0
- package/dist/server/routes/mcp.js.map +1 -0
- package/dist/server/routes/memory-tool.d.ts +14 -0
- package/dist/server/routes/memory-tool.js +28 -0
- package/dist/server/routes/memory-tool.js.map +1 -0
- package/dist/server/routes/memory.d.ts +7 -0
- package/dist/server/routes/memory.js +19 -0
- package/dist/server/routes/memory.js.map +1 -0
- package/dist/server/routes/recall.d.ts +15 -0
- package/dist/server/routes/recall.js +74 -0
- package/dist/server/routes/recall.js.map +1 -0
- package/dist/server/routes/search.d.ts +12 -0
- package/dist/server/routes/search.js +203 -0
- package/dist/server/routes/search.js.map +1 -0
- package/dist/server/routes/version.d.ts +2 -0
- package/dist/server/routes/version.js +11 -0
- package/dist/server/routes/version.js.map +1 -0
- package/dist/server/routes/why.d.ts +9 -0
- package/dist/server/routes/why.js +38 -0
- package/dist/server/routes/why.js.map +1 -0
- package/dist/service/index.d.ts +10 -0
- package/dist/service/index.js +25 -0
- package/dist/service/index.js.map +1 -0
- package/dist/service/install-flow.d.ts +18 -0
- package/dist/service/install-flow.js +47 -0
- package/dist/service/install-flow.js.map +1 -0
- package/dist/service/instance-lock.d.ts +26 -0
- package/dist/service/instance-lock.js +150 -0
- package/dist/service/instance-lock.js.map +1 -0
- package/dist/service/launchd.d.ts +11 -0
- package/dist/service/launchd.js +196 -0
- package/dist/service/launchd.js.map +1 -0
- package/dist/service/schtasks.d.ts +31 -0
- package/dist/service/schtasks.js +274 -0
- package/dist/service/schtasks.js.map +1 -0
- package/dist/service/shim.d.ts +21 -0
- package/dist/service/shim.js +80 -0
- package/dist/service/shim.js.map +1 -0
- package/dist/service/systemd.d.ts +11 -0
- package/dist/service/systemd.js +150 -0
- package/dist/service/systemd.js.map +1 -0
- package/dist/service/task-xml.d.ts +36 -0
- package/dist/service/task-xml.js +91 -0
- package/dist/service/task-xml.js.map +1 -0
- package/dist/service/types.d.ts +47 -0
- package/dist/service/types.js +2 -0
- package/dist/service/types.js.map +1 -0
- package/dist/storage/archival.d.ts +29 -0
- package/dist/storage/archival.js +47 -0
- package/dist/storage/archival.js.map +1 -0
- package/dist/storage/bearer-keystore.d.ts +34 -0
- package/dist/storage/bearer-keystore.js +75 -0
- package/dist/storage/bearer-keystore.js.map +1 -0
- package/dist/storage/db.d.ts +37 -0
- package/dist/storage/db.js +92 -0
- package/dist/storage/db.js.map +1 -0
- package/dist/storage/entities.d.ts +71 -0
- package/dist/storage/entities.js +141 -0
- package/dist/storage/entities.js.map +1 -0
- package/dist/storage/ingest-idempotency.d.ts +26 -0
- package/dist/storage/ingest-idempotency.js +29 -0
- package/dist/storage/ingest-idempotency.js.map +1 -0
- package/dist/storage/keystore.d.ts +64 -0
- package/dist/storage/keystore.js +194 -0
- package/dist/storage/keystore.js.map +1 -0
- package/dist/storage/memories.d.ts +51 -0
- package/dist/storage/memories.js +67 -0
- package/dist/storage/memories.js.map +1 -0
- package/dist/storage/memory-events.d.ts +145 -0
- package/dist/storage/memory-events.js +287 -0
- package/dist/storage/memory-events.js.map +1 -0
- package/dist/storage/migrate-encrypt.d.ts +16 -0
- package/dist/storage/migrate-encrypt.js +121 -0
- package/dist/storage/migrate-encrypt.js.map +1 -0
- package/dist/storage/migrate.d.ts +27 -0
- package/dist/storage/migrate.js +105 -0
- package/dist/storage/migrate.js.map +1 -0
- package/dist/storage/redaction-log.d.ts +18 -0
- package/dist/storage/redaction-log.js +27 -0
- package/dist/storage/redaction-log.js.map +1 -0
- package/dist/storage/usefulness.d.ts +115 -0
- package/dist/storage/usefulness.js +203 -0
- package/dist/storage/usefulness.js.map +1 -0
- package/dist/sync/conflict-resolve.d.ts +26 -0
- package/dist/sync/conflict-resolve.js +139 -0
- package/dist/sync/conflict-resolve.js.map +1 -0
- package/dist/sync/puller.d.ts +115 -0
- package/dist/sync/puller.js +173 -0
- package/dist/sync/puller.js.map +1 -0
- package/dist/sync/shipper.d.ts +112 -0
- package/dist/sync/shipper.js +189 -0
- package/dist/sync/shipper.js.map +1 -0
- package/dist/tag-hygiene/backfill.d.ts +50 -0
- package/dist/tag-hygiene/backfill.js +117 -0
- package/dist/tag-hygiene/backfill.js.map +1 -0
- package/dist/tag-hygiene/derive-repo.d.ts +9 -0
- package/dist/tag-hygiene/derive-repo.js +19 -0
- package/dist/tag-hygiene/derive-repo.js.map +1 -0
- package/dist/tag-hygiene/tier2-infer.d.ts +28 -0
- package/dist/tag-hygiene/tier2-infer.js +72 -0
- package/dist/tag-hygiene/tier2-infer.js.map +1 -0
- package/dist/vector/sqlite-vec.d.ts +16 -0
- package/dist/vector/sqlite-vec.js +49 -0
- package/dist/vector/sqlite-vec.js.map +1 -0
- package/migrations/001-init.sql +117 -0
- package/migrations/002-wire-v1.sql +16 -0
- package/migrations/003-expand-memory-types.sql +81 -0
- package/migrations/004-provenance.sql +4 -0
- package/migrations/005-security.sql +12 -0
- package/migrations/006-atom-v3.sql +28 -0
- package/migrations/007-memory-events.sql +30 -0
- package/migrations/008-consolidation.sql +31 -0
- package/migrations/009-tag-hygiene.sql +13 -0
- package/migrations/010-sync-pull.sql +53 -0
- package/migrations/011-embed-dim-migration.sql +28 -0
- package/migrations/012-entities.sql +36 -0
- package/migrations/013-archival.sql +50 -0
- 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;
|