@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
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Distill-events handler — ADR-008 `events` capture kind.
|
|
3
|
+
*
|
|
4
|
+
* Pre-typed atom candidates (runner-plugin grades/lessons/review verdicts)
|
|
5
|
+
* are already atom-shaped when they hit the wire, so this handler skips
|
|
6
|
+
* pipeline stages 1-5 (cleanup/normalize/chunk/compact/extract — the raw-text
|
|
7
|
+
* and LLM stages) and enters directly at stage 6 (reduce), chaining straight
|
|
8
|
+
* through stage 7 (memory-normalize) and stage 8 (embed+index), mirroring
|
|
9
|
+
* the same three-stage tail src/distill/pipeline.ts runs for the transcript
|
|
10
|
+
* path. No LLMProvider is used here (no compaction/extraction call), so the
|
|
11
|
+
* BudgetExceeded semantics distillHandler has for stages 4/5 do not apply —
|
|
12
|
+
* only the embed provider is exercised (stage 8).
|
|
13
|
+
*/
|
|
14
|
+
import { createHash } from 'node:crypto';
|
|
15
|
+
import { z } from 'zod';
|
|
16
|
+
import { isExtendedCtx } from '../handler-ctx-ext.js';
|
|
17
|
+
import { reduce } from '../../distill/stages/06-reduce.js';
|
|
18
|
+
import { memoryNormalize } from '../../distill/stages/07-memory-normalize.js';
|
|
19
|
+
import { embedAndIndex } from '../../distill/stages/08-embed-index.js';
|
|
20
|
+
import { backfillSummaryMemoryId } from '../../storage/ingest-idempotency.js';
|
|
21
|
+
import { childLogger } from '../../log/logger.js';
|
|
22
|
+
/**
|
|
23
|
+
* Flexible payload schema — ingest route writes {transcript_id, session_id}
|
|
24
|
+
* without the `kind` discriminator. Accept both forms (mirrors distill.ts).
|
|
25
|
+
*/
|
|
26
|
+
const DistillEventsPayloadFlexSchema = z.object({
|
|
27
|
+
transcript_id: z.string().min(1),
|
|
28
|
+
session_id: z.string().min(1),
|
|
29
|
+
kind: z.string().optional(),
|
|
30
|
+
});
|
|
31
|
+
/**
|
|
32
|
+
* Shape of one event as stored in `transcripts.content` (redacted, JSON
|
|
33
|
+
* array) — mirrors CanonicalEventItemSchema in server/routes/ingest.ts and
|
|
34
|
+
* the 7-type registry in distill/prompts/extract.ts (AtomSchema).
|
|
35
|
+
*/
|
|
36
|
+
const StoredEventSchema = z.object({
|
|
37
|
+
type: z.enum(['decision', 'fact', 'lesson', 'command', 'todo', 'note', 'event']),
|
|
38
|
+
text: z.string().min(1),
|
|
39
|
+
importance: z.number().min(0).max(1).optional(),
|
|
40
|
+
confidence: z.number().min(0).max(1).optional(),
|
|
41
|
+
evidence: z.string().optional(),
|
|
42
|
+
occurred_at: z.number().optional(),
|
|
43
|
+
});
|
|
44
|
+
const StoredEventsSchema = z.array(StoredEventSchema).min(1);
|
|
45
|
+
/** Applied when the source event omits importance/confidence (ADR-008). */
|
|
46
|
+
const DEFAULT_IMPORTANCE = 0.7;
|
|
47
|
+
const DEFAULT_CONFIDENCE = 0.9;
|
|
48
|
+
export const distillEventsHandler = {
|
|
49
|
+
kind: 'distill-events',
|
|
50
|
+
async handle(payload, ctx) {
|
|
51
|
+
const parsed = DistillEventsPayloadFlexSchema.safeParse(payload);
|
|
52
|
+
if (!parsed.success) {
|
|
53
|
+
throw new Error(`Invalid distill-events payload: ${parsed.error.message}`);
|
|
54
|
+
}
|
|
55
|
+
const { transcript_id, session_id } = parsed.data;
|
|
56
|
+
// Fetch the transcript row the ingest route wrote (content = JSON of
|
|
57
|
+
// redacted events, source = `<tool>-events` or 'events').
|
|
58
|
+
const transcript = ctx.db
|
|
59
|
+
.prepare('SELECT id, session_id, content, source FROM transcripts WHERE id = ?')
|
|
60
|
+
.get(transcript_id);
|
|
61
|
+
if (!transcript) {
|
|
62
|
+
throw new Error(`Transcript not found: ${transcript_id}`);
|
|
63
|
+
}
|
|
64
|
+
// Fetch session metadata for memory context
|
|
65
|
+
const session = ctx.db
|
|
66
|
+
.prepare('SELECT id, repo, project, branch, agent FROM sessions WHERE id = ?')
|
|
67
|
+
.get(session_id);
|
|
68
|
+
let rawEvents;
|
|
69
|
+
try {
|
|
70
|
+
rawEvents = JSON.parse(transcript.content);
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
// Deterministic — retrying will never fix a JSON parse failure.
|
|
74
|
+
throw new Error(`distill-events transcript content is not valid JSON: ${String(e)}`);
|
|
75
|
+
}
|
|
76
|
+
const eventsResult = StoredEventsSchema.safeParse(rawEvents);
|
|
77
|
+
if (!eventsResult.success) {
|
|
78
|
+
throw new Error(`distill-events transcript content does not match the events shape: ${eventsResult.error.message}`);
|
|
79
|
+
}
|
|
80
|
+
const events = eventsResult.data;
|
|
81
|
+
// Map pre-typed events straight to Atoms — the stage-1-5 skip (ADR-008):
|
|
82
|
+
// no cleanup/normalize/chunk/compact/extract, just the atom shape stages
|
|
83
|
+
// 6-8 already expect.
|
|
84
|
+
const atoms = events.map(ev => ({
|
|
85
|
+
type: ev.type,
|
|
86
|
+
text: ev.text,
|
|
87
|
+
importance: ev.importance ?? DEFAULT_IMPORTANCE,
|
|
88
|
+
confidence: ev.confidence ?? DEFAULT_CONFIDENCE,
|
|
89
|
+
evidence: ev.evidence,
|
|
90
|
+
}));
|
|
91
|
+
if (!isExtendedCtx(ctx)) {
|
|
92
|
+
// Fallback: no providers available (e.g. in unit tests without providers)
|
|
93
|
+
console.warn(`[distill-events] no providers in ctx — transcript ${transcript_id} logged but not distilled. ` +
|
|
94
|
+
'Ensure ExtendedHandlerCtx is passed when providers are configured.');
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const pipeLog = childLogger({ session_id });
|
|
98
|
+
// Stage 6: Reduce (merge by content hash)
|
|
99
|
+
pipeLog.info({ stage: 'reduce', atoms_in: atoms.length }, 'stage start');
|
|
100
|
+
const reducedAtoms = reduce(atoms);
|
|
101
|
+
pipeLog.info({ stage: 'reduce', atoms_out: reducedAtoms.length }, 'stage complete');
|
|
102
|
+
// Stage 7: Memory-normalize
|
|
103
|
+
pipeLog.info({ stage: 'memory-normalize' }, 'stage start');
|
|
104
|
+
const normalizedMemories = memoryNormalize(reducedAtoms);
|
|
105
|
+
pipeLog.info({ stage: 'memory-normalize', memories: normalizedMemories.length }, 'stage complete');
|
|
106
|
+
// Stage 8: Embed + index — session/repo/branch/agent come from the
|
|
107
|
+
// session row; embedAndIndex appends a 'create' memory_event per new
|
|
108
|
+
// memory (2b), same as the transcript path.
|
|
109
|
+
const sourceHash = createHash('sha256').update(transcript.content, 'utf8').digest('hex');
|
|
110
|
+
pipeLog.info({ stage: 'embed-index', memories: normalizedMemories.length }, 'stage start');
|
|
111
|
+
const indexResults = await embedAndIndex(normalizedMemories, {
|
|
112
|
+
db: ctx.db,
|
|
113
|
+
embed: ctx.providers.embed,
|
|
114
|
+
sessionId: session_id,
|
|
115
|
+
repo: session?.repo ?? null,
|
|
116
|
+
project: session?.project ?? null,
|
|
117
|
+
branch: session?.branch ?? null,
|
|
118
|
+
agent: session?.agent ?? null,
|
|
119
|
+
sourceHash,
|
|
120
|
+
});
|
|
121
|
+
const created = indexResults.filter(r => r.created).length;
|
|
122
|
+
const deduped = indexResults.filter(r => !r.created).length;
|
|
123
|
+
pipeLog.info({ stage: 'embed-index', memories_created: created, memories_deduped: deduped }, 'stage complete');
|
|
124
|
+
console.log(`[distill-events] transcript=${transcript_id} events=${events.length} atoms=${atoms.length} ` +
|
|
125
|
+
`created=${created} deduped=${deduped}`);
|
|
126
|
+
// D-DEF2 parity: backfill ingest_idempotency.summary_memory_id from the
|
|
127
|
+
// transcript-id placeholder to the real created memory id, same as the
|
|
128
|
+
// transcript path.
|
|
129
|
+
if (indexResults.length > 0) {
|
|
130
|
+
backfillSummaryMemoryId(ctx.db, transcript_id, indexResults[0].memoryId);
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
//# sourceMappingURL=distill-events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"distill-events.js","sourceRoot":"","sources":["../../../src/pipeline/handlers/distill-events.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Distill handler — Wave 3 implementation.
|
|
3
|
+
*
|
|
4
|
+
* Validates the payload, fetches transcript from DB,
|
|
5
|
+
* runs the 8-stage pipeline, and handles BudgetExceeded by
|
|
6
|
+
* moving the job to paused (not failed).
|
|
7
|
+
*/
|
|
8
|
+
import type { JobHandler } from '../handler.js';
|
|
9
|
+
export declare const distillHandler: JobHandler;
|
|
10
|
+
/**
|
|
11
|
+
* Sentinel error thrown by the distill handler when the budget cap is hit.
|
|
12
|
+
* The worker loop must catch this and call JobRepo.pause() instead of fail().
|
|
13
|
+
*/
|
|
14
|
+
export declare class DistillBudgetPausedError extends Error {
|
|
15
|
+
constructor(budgetMessage: string);
|
|
16
|
+
static is(err: unknown): err is DistillBudgetPausedError;
|
|
17
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Distill handler — Wave 3 implementation.
|
|
3
|
+
*
|
|
4
|
+
* Validates the payload, fetches transcript from DB,
|
|
5
|
+
* runs the 8-stage pipeline, and handles BudgetExceeded by
|
|
6
|
+
* moving the job to paused (not failed).
|
|
7
|
+
*/
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
import { isExtendedCtx } from '../handler-ctx-ext.js';
|
|
10
|
+
import { runPipeline, BudgetExceeded } from '../../distill/pipeline.js';
|
|
11
|
+
import { flattenTranscriptContent } from '../../distill/flatten-turns.js';
|
|
12
|
+
import { backfillSummaryMemoryId } from '../../storage/ingest-idempotency.js';
|
|
13
|
+
/**
|
|
14
|
+
* Flexible payload schema — ingest route writes {transcript_id, session_id}
|
|
15
|
+
* without the `kind` discriminator. Accept both forms.
|
|
16
|
+
*/
|
|
17
|
+
const DistillPayloadFlexSchema = z.object({
|
|
18
|
+
transcript_id: z.string().min(1),
|
|
19
|
+
session_id: z.string().min(1),
|
|
20
|
+
// kind is optional here — ingest route may or may not include it
|
|
21
|
+
kind: z.string().optional(),
|
|
22
|
+
});
|
|
23
|
+
export const distillHandler = {
|
|
24
|
+
kind: 'distill',
|
|
25
|
+
async handle(payload, ctx) {
|
|
26
|
+
const parsed = DistillPayloadFlexSchema.safeParse(payload);
|
|
27
|
+
if (!parsed.success) {
|
|
28
|
+
throw new Error(`Invalid distill payload: ${parsed.error.message}`);
|
|
29
|
+
}
|
|
30
|
+
const { transcript_id, session_id } = parsed.data;
|
|
31
|
+
// Fetch transcript content
|
|
32
|
+
const transcript = ctx.db
|
|
33
|
+
.prepare('SELECT id, session_id, content, source FROM transcripts WHERE id = ?')
|
|
34
|
+
.get(transcript_id);
|
|
35
|
+
if (!transcript) {
|
|
36
|
+
throw new Error(`Transcript not found: ${transcript_id}`);
|
|
37
|
+
}
|
|
38
|
+
// Fetch session metadata for memory context
|
|
39
|
+
const session = ctx.db
|
|
40
|
+
.prepare('SELECT id, repo, project, branch, agent FROM sessions WHERE id = ?')
|
|
41
|
+
.get(session_id);
|
|
42
|
+
// D-DEF1: canonical transcripts store JSON.stringify(turns) in `content`
|
|
43
|
+
// (structured [{role, text, ts}]). Flatten to "role: text" lines — the
|
|
44
|
+
// format stages 1-3 (cleanup/normalize/chunk) actually parse — before it
|
|
45
|
+
// enters the pipeline. Legacy plain-text content passes through as-is.
|
|
46
|
+
const transcriptText = flattenTranscriptContent(transcript.content);
|
|
47
|
+
// Derive source hash for idempotency
|
|
48
|
+
const { createHash } = await import('node:crypto');
|
|
49
|
+
const sourceHash = createHash('sha256')
|
|
50
|
+
.update(transcript.content, 'utf8')
|
|
51
|
+
.digest('hex');
|
|
52
|
+
// Check if we have extended context with providers
|
|
53
|
+
if (!isExtendedCtx(ctx)) {
|
|
54
|
+
// Fallback: no providers available (e.g. in unit tests without providers)
|
|
55
|
+
// Log and complete — no memories will be created
|
|
56
|
+
console.warn(`[distill] no providers in ctx — transcript ${transcript_id} logged but not distilled. ` +
|
|
57
|
+
'Ensure ExtendedHandlerCtx is passed when providers are configured.');
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const pipelineCtx = {
|
|
61
|
+
db: ctx.db,
|
|
62
|
+
llmCompaction: ctx.providers.llm.compaction,
|
|
63
|
+
llmExtraction: ctx.providers.llm.extraction,
|
|
64
|
+
embed: ctx.providers.embed,
|
|
65
|
+
capUsd: ctx.config.budget.daily_usd,
|
|
66
|
+
sessionId: session_id,
|
|
67
|
+
repo: session?.repo ?? null,
|
|
68
|
+
project: session?.project ?? null,
|
|
69
|
+
branch: session?.branch ?? null,
|
|
70
|
+
agent: session?.agent ?? null,
|
|
71
|
+
sourceHash,
|
|
72
|
+
};
|
|
73
|
+
try {
|
|
74
|
+
const result = await runPipeline(transcriptText, pipelineCtx);
|
|
75
|
+
console.log(`[distill] transcript=${transcript_id} chunks=${result.chunksProcessed} atoms=${result.atomsExtracted} ` +
|
|
76
|
+
`created=${result.memoriesCreated} deduped=${result.memoriesDeduped}`);
|
|
77
|
+
// D-DEF2: backfill ingest_idempotency.summary_memory_id (currently the
|
|
78
|
+
// transcript-id placeholder written at ingest time) with the real
|
|
79
|
+
// memory id this run produced, so idempotent replays return it.
|
|
80
|
+
if (result.memoryIds.length > 0) {
|
|
81
|
+
backfillSummaryMemoryId(ctx.db, transcript_id, result.memoryIds[0]);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
if (err instanceof BudgetExceeded) {
|
|
86
|
+
// Budget exceeded — move job to paused. The worker will not retry.
|
|
87
|
+
// We need access to the job id — the worker passes it via the job object.
|
|
88
|
+
// Since JobHandler.handle does not receive the job id directly,
|
|
89
|
+
// we throw a special marker error that the worker catches.
|
|
90
|
+
// Alternative: use a sentinel to signal paused state.
|
|
91
|
+
throw new DistillBudgetPausedError(err.message);
|
|
92
|
+
}
|
|
93
|
+
throw err;
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Sentinel error thrown by the distill handler when the budget cap is hit.
|
|
99
|
+
* The worker loop must catch this and call JobRepo.pause() instead of fail().
|
|
100
|
+
*/
|
|
101
|
+
export class DistillBudgetPausedError extends Error {
|
|
102
|
+
constructor(budgetMessage) {
|
|
103
|
+
super(`BUDGET_PAUSED:${budgetMessage}`);
|
|
104
|
+
this.name = 'DistillBudgetPausedError';
|
|
105
|
+
}
|
|
106
|
+
static is(err) {
|
|
107
|
+
return err instanceof DistillBudgetPausedError;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=distill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"distill.js","sourceRoot":"","sources":["../../../src/pipeline/handlers/distill.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { JobHandler } from '../handler.js';
|
|
2
|
+
/**
|
|
3
|
+
* Reembed handler — recompute + upsert the embedding for one memory
|
|
4
|
+
* (`rebuild` CLI enqueues one job per memory; model swaps re-index this way).
|
|
5
|
+
*
|
|
6
|
+
* A missing memory is a success, not a failure: the memory may have been
|
|
7
|
+
* erased (ADR-006) or superseded-and-cleaned between enqueue and execution,
|
|
8
|
+
* and retrying would never make it reappear.
|
|
9
|
+
*/
|
|
10
|
+
export declare const reembedHandler: JobHandler;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ReembedPayloadSchema } from '../../contracts/index.js';
|
|
2
|
+
import { isExtendedCtx } from '../handler-ctx-ext.js';
|
|
3
|
+
/**
|
|
4
|
+
* Reembed handler — recompute + upsert the embedding for one memory
|
|
5
|
+
* (`rebuild` CLI enqueues one job per memory; model swaps re-index this way).
|
|
6
|
+
*
|
|
7
|
+
* A missing memory is a success, not a failure: the memory may have been
|
|
8
|
+
* erased (ADR-006) or superseded-and-cleaned between enqueue and execution,
|
|
9
|
+
* and retrying would never make it reappear.
|
|
10
|
+
*/
|
|
11
|
+
export const reembedHandler = {
|
|
12
|
+
kind: 'reembed',
|
|
13
|
+
async handle(payload, ctx) {
|
|
14
|
+
const parsed = ReembedPayloadSchema.safeParse(payload);
|
|
15
|
+
if (!parsed.success) {
|
|
16
|
+
throw new Error(`Invalid reembed payload: ${parsed.error.message}`);
|
|
17
|
+
}
|
|
18
|
+
if (!isExtendedCtx(ctx)) {
|
|
19
|
+
throw new Error('reembed requires the extended handler context (providers + vecStore)');
|
|
20
|
+
}
|
|
21
|
+
const { memory_id } = parsed.data;
|
|
22
|
+
const memory = ctx.memoryRepo.get(memory_id);
|
|
23
|
+
if (!memory) {
|
|
24
|
+
console.log(`[reembed] memory ${memory_id} no longer exists — skipping`);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const [vec] = await ctx.providers.embed.embed([memory.text]);
|
|
28
|
+
if (!vec)
|
|
29
|
+
throw new Error(`embed provider returned no vector for memory ${memory_id}`);
|
|
30
|
+
await ctx.vecStore.upsert(memory_id, vec);
|
|
31
|
+
ctx.db.prepare('UPDATE memories SET embedding_provider = ?, embedding_model = ?, embedding_dim = ?, updated_at = ? WHERE id = ?').run(ctx.providers.embed.name, ctx.providers.embed.model, ctx.providers.embed.dim, Date.now(), memory_id);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=reembed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reembed.js","sourceRoot":"","sources":["../../../src/pipeline/handlers/reembed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAEhE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,cAAc,GAAe;IACxC,IAAI,EAAE,SAAS;IAEf,KAAK,CAAC,MAAM,CAAC,OAAgB,EAAE,GAAe;QAC5C,MAAM,MAAM,GAAG,oBAAoB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACvD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,4BAA4B,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACtE,CAAC;QACD,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,sEAAsE,CAAC,CAAC;QAC1F,CAAC;QAED,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC;QAClC,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,GAAG,CAAC,oBAAoB,SAAS,8BAA8B,CAAC,CAAC;YACzE,OAAO;QACT,CAAC;QAED,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;QAC7D,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,SAAS,EAAE,CAAC,CAAC;QACvF,MAAM,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAE1C,GAAG,CAAC,EAAE,CAAC,OAAO,CACZ,iHAAiH,CAClH,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,SAAS,CAAC,CAAC;IAC7G,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { DB } from '../storage/db.js';
|
|
2
|
+
import type { Job, JobKind } from '../contracts/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Data-access object for the jobs table.
|
|
5
|
+
* All methods are synchronous (better-sqlite3 is sync).
|
|
6
|
+
*/
|
|
7
|
+
export declare class JobRepo {
|
|
8
|
+
private readonly db;
|
|
9
|
+
constructor(db: DB);
|
|
10
|
+
/** Insert a new job in pending state, return its generated id. */
|
|
11
|
+
enqueue(kind: JobKind, payload: unknown): string;
|
|
12
|
+
/**
|
|
13
|
+
* Atomically claim the oldest pending job: pending → running.
|
|
14
|
+
* Returns the updated Job row, or null if the queue is empty.
|
|
15
|
+
* Uses a CTE-based UPDATE so only one concurrent caller wins the row.
|
|
16
|
+
*/
|
|
17
|
+
claimPending(): Job | null;
|
|
18
|
+
/** Transition a running job to completed. */
|
|
19
|
+
complete(id: string): void;
|
|
20
|
+
/**
|
|
21
|
+
* Record a handler failure: increment attempts and record the error.
|
|
22
|
+
* The new state is 'failed'. The worker checks attempts after this call
|
|
23
|
+
* and either re-enqueues (back to 'pending') or calls markPoison.
|
|
24
|
+
*/
|
|
25
|
+
fail(id: string, error: string): void;
|
|
26
|
+
/**
|
|
27
|
+
* Move a failed job back to pending so the worker will retry it.
|
|
28
|
+
* Only call this when attempts < MAX_ATTEMPTS.
|
|
29
|
+
*/
|
|
30
|
+
requeueForRetry(id: string): void;
|
|
31
|
+
/** Transition a job to the poison state (permanently failed). */
|
|
32
|
+
markPoison(id: string): void;
|
|
33
|
+
/** Transition a job to paused (e.g. budget exceeded). */
|
|
34
|
+
pause(id: string): void;
|
|
35
|
+
/**
|
|
36
|
+
* Record a non-failure note on the job (e.g. budget pause reason) without
|
|
37
|
+
* touching `attempts`. Use for state transitions that are not handler errors.
|
|
38
|
+
*/
|
|
39
|
+
setLastError(id: string, note: string): void;
|
|
40
|
+
/** Read a single job by id. Returns null if not found. */
|
|
41
|
+
get(id: string): Job | null;
|
|
42
|
+
/**
|
|
43
|
+
* Boot-time crash recovery. Call once at daemon start, before the worker.
|
|
44
|
+
*
|
|
45
|
+
* - 'running' jobs are orphans: the previous process died mid-handle (on
|
|
46
|
+
* Windows, schtasks /end and Task Manager kills bypass the SIGTERM
|
|
47
|
+
* handler entirely). Requeue them.
|
|
48
|
+
* - 'failed' jobs with attempts < maxAttempts were waiting on an IN-MEMORY
|
|
49
|
+
* retry timer (worker.ts setTimeout) that died with the process — without
|
|
50
|
+
* this they are stranded in 'failed' forever. Requeue them too.
|
|
51
|
+
*
|
|
52
|
+
* `attempts` is preserved in both cases so poison thresholds still apply.
|
|
53
|
+
* Handlers must tolerate re-execution of partially-applied work (distill/
|
|
54
|
+
* reembed write via idempotent upserts; a rare duplicate memory from a
|
|
55
|
+
* mid-write crash is deduped downstream by consolidation).
|
|
56
|
+
*/
|
|
57
|
+
recoverOrphans(maxAttempts?: number): {
|
|
58
|
+
requeuedRunning: number;
|
|
59
|
+
requeuedFailed: number;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Retention purge: completed jobs are transient bookkeeping (7d), poison
|
|
63
|
+
* jobs are kept longer (30d) for `queue` command forensics. Other states
|
|
64
|
+
* are never touched.
|
|
65
|
+
*/
|
|
66
|
+
purgeOld(opts?: {
|
|
67
|
+
completedDays?: number;
|
|
68
|
+
poisonDays?: number;
|
|
69
|
+
}): {
|
|
70
|
+
completed: number;
|
|
71
|
+
poison: number;
|
|
72
|
+
};
|
|
73
|
+
/** List all jobs currently in the 'poison' state, oldest first (FEAT-405 manual purge). */
|
|
74
|
+
listPoison(): Job[];
|
|
75
|
+
/**
|
|
76
|
+
* Delete specific poison jobs by id (FEAT-405 `queue purge --poison`).
|
|
77
|
+
* Guarded to state = 'poison' so a job that transitions out of poison
|
|
78
|
+
* between the caller's read (for the forensics dump) and this delete is
|
|
79
|
+
* never silently swept up. Callers must capture ids via listPoison() first
|
|
80
|
+
* and write the forensics dump BEFORE calling this.
|
|
81
|
+
*/
|
|
82
|
+
purgePoisonByIds(ids: string[]): number;
|
|
83
|
+
/** State → count map for /health queue reporting. */
|
|
84
|
+
stateCounts(): Record<string, number>;
|
|
85
|
+
private _transition;
|
|
86
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
/**
|
|
3
|
+
* Data-access object for the jobs table.
|
|
4
|
+
* All methods are synchronous (better-sqlite3 is sync).
|
|
5
|
+
*/
|
|
6
|
+
export class JobRepo {
|
|
7
|
+
db;
|
|
8
|
+
constructor(db) {
|
|
9
|
+
this.db = db;
|
|
10
|
+
}
|
|
11
|
+
/** Insert a new job in pending state, return its generated id. */
|
|
12
|
+
enqueue(kind, payload) {
|
|
13
|
+
const id = randomUUID();
|
|
14
|
+
const now = Date.now();
|
|
15
|
+
this.db.prepare(`
|
|
16
|
+
INSERT INTO jobs (id, kind, payload_json, state, attempts, last_error, created_at, updated_at)
|
|
17
|
+
VALUES (?, ?, ?, 'pending', 0, NULL, ?, ?)
|
|
18
|
+
`).run(id, kind, JSON.stringify(payload), now, now);
|
|
19
|
+
return id;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Atomically claim the oldest pending job: pending → running.
|
|
23
|
+
* Returns the updated Job row, or null if the queue is empty.
|
|
24
|
+
* Uses a CTE-based UPDATE so only one concurrent caller wins the row.
|
|
25
|
+
*/
|
|
26
|
+
claimPending() {
|
|
27
|
+
// SQLite does not support UPDATE ... RETURNING with a subquery on some versions,
|
|
28
|
+
// so we use a transaction: SELECT the candidate, then UPDATE if still pending.
|
|
29
|
+
const claim = this.db.transaction(() => {
|
|
30
|
+
const candidate = this.db.prepare(`
|
|
31
|
+
SELECT * FROM jobs
|
|
32
|
+
WHERE state = 'pending'
|
|
33
|
+
ORDER BY created_at ASC
|
|
34
|
+
LIMIT 1
|
|
35
|
+
`).get();
|
|
36
|
+
if (!candidate)
|
|
37
|
+
return null;
|
|
38
|
+
const now = Date.now();
|
|
39
|
+
const changes = this.db.prepare(`
|
|
40
|
+
UPDATE jobs
|
|
41
|
+
SET state = 'running', updated_at = ?
|
|
42
|
+
WHERE id = ? AND state = 'pending'
|
|
43
|
+
`).run(now, candidate.id).changes;
|
|
44
|
+
if (changes === 0)
|
|
45
|
+
return null; // race: another worker grabbed it
|
|
46
|
+
return { ...candidate, state: 'running', updated_at: now };
|
|
47
|
+
});
|
|
48
|
+
return claim();
|
|
49
|
+
}
|
|
50
|
+
/** Transition a running job to completed. */
|
|
51
|
+
complete(id) {
|
|
52
|
+
this._transition(id, 'completed');
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Record a handler failure: increment attempts and record the error.
|
|
56
|
+
* The new state is 'failed'. The worker checks attempts after this call
|
|
57
|
+
* and either re-enqueues (back to 'pending') or calls markPoison.
|
|
58
|
+
*/
|
|
59
|
+
fail(id, error) {
|
|
60
|
+
const now = Date.now();
|
|
61
|
+
this.db.prepare(`
|
|
62
|
+
UPDATE jobs
|
|
63
|
+
SET state = 'failed', last_error = ?, attempts = attempts + 1, updated_at = ?
|
|
64
|
+
WHERE id = ?
|
|
65
|
+
`).run(error, now, id);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Move a failed job back to pending so the worker will retry it.
|
|
69
|
+
* Only call this when attempts < MAX_ATTEMPTS.
|
|
70
|
+
*/
|
|
71
|
+
requeueForRetry(id) {
|
|
72
|
+
this._transition(id, 'pending');
|
|
73
|
+
}
|
|
74
|
+
/** Transition a job to the poison state (permanently failed). */
|
|
75
|
+
markPoison(id) {
|
|
76
|
+
this._transition(id, 'poison');
|
|
77
|
+
}
|
|
78
|
+
/** Transition a job to paused (e.g. budget exceeded). */
|
|
79
|
+
pause(id) {
|
|
80
|
+
this._transition(id, 'paused');
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Record a non-failure note on the job (e.g. budget pause reason) without
|
|
84
|
+
* touching `attempts`. Use for state transitions that are not handler errors.
|
|
85
|
+
*/
|
|
86
|
+
setLastError(id, note) {
|
|
87
|
+
const now = Date.now();
|
|
88
|
+
this.db.prepare('UPDATE jobs SET last_error = ?, updated_at = ? WHERE id = ?').run(note, now, id);
|
|
89
|
+
}
|
|
90
|
+
/** Read a single job by id. Returns null if not found. */
|
|
91
|
+
get(id) {
|
|
92
|
+
const row = this.db.prepare('SELECT * FROM jobs WHERE id = ?').get(id);
|
|
93
|
+
return row ?? null;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Boot-time crash recovery. Call once at daemon start, before the worker.
|
|
97
|
+
*
|
|
98
|
+
* - 'running' jobs are orphans: the previous process died mid-handle (on
|
|
99
|
+
* Windows, schtasks /end and Task Manager kills bypass the SIGTERM
|
|
100
|
+
* handler entirely). Requeue them.
|
|
101
|
+
* - 'failed' jobs with attempts < maxAttempts were waiting on an IN-MEMORY
|
|
102
|
+
* retry timer (worker.ts setTimeout) that died with the process — without
|
|
103
|
+
* this they are stranded in 'failed' forever. Requeue them too.
|
|
104
|
+
*
|
|
105
|
+
* `attempts` is preserved in both cases so poison thresholds still apply.
|
|
106
|
+
* Handlers must tolerate re-execution of partially-applied work (distill/
|
|
107
|
+
* reembed write via idempotent upserts; a rare duplicate memory from a
|
|
108
|
+
* mid-write crash is deduped downstream by consolidation).
|
|
109
|
+
*/
|
|
110
|
+
recoverOrphans(maxAttempts = 3) {
|
|
111
|
+
const now = Date.now();
|
|
112
|
+
const requeuedRunning = this.db.prepare(`
|
|
113
|
+
UPDATE jobs SET state = 'pending', updated_at = ?
|
|
114
|
+
WHERE state = 'running'
|
|
115
|
+
`).run(now).changes;
|
|
116
|
+
const requeuedFailed = this.db.prepare(`
|
|
117
|
+
UPDATE jobs SET state = 'pending', updated_at = ?
|
|
118
|
+
WHERE state = 'failed' AND attempts < ?
|
|
119
|
+
`).run(now, maxAttempts).changes;
|
|
120
|
+
return { requeuedRunning, requeuedFailed };
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Retention purge: completed jobs are transient bookkeeping (7d), poison
|
|
124
|
+
* jobs are kept longer (30d) for `queue` command forensics. Other states
|
|
125
|
+
* are never touched.
|
|
126
|
+
*/
|
|
127
|
+
purgeOld(opts = {}) {
|
|
128
|
+
const now = Date.now();
|
|
129
|
+
const dayMs = 24 * 60 * 60 * 1000;
|
|
130
|
+
const completedCutoff = now - (opts.completedDays ?? 7) * dayMs;
|
|
131
|
+
const poisonCutoff = now - (opts.poisonDays ?? 30) * dayMs;
|
|
132
|
+
const completed = this.db.prepare(`DELETE FROM jobs WHERE state = 'completed' AND updated_at < ?`).run(completedCutoff).changes;
|
|
133
|
+
const poison = this.db.prepare(`DELETE FROM jobs WHERE state = 'poison' AND updated_at < ?`).run(poisonCutoff).changes;
|
|
134
|
+
return { completed, poison };
|
|
135
|
+
}
|
|
136
|
+
/** List all jobs currently in the 'poison' state, oldest first (FEAT-405 manual purge). */
|
|
137
|
+
listPoison() {
|
|
138
|
+
return this.db.prepare(`
|
|
139
|
+
SELECT * FROM jobs WHERE state = 'poison' ORDER BY updated_at ASC
|
|
140
|
+
`).all();
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Delete specific poison jobs by id (FEAT-405 `queue purge --poison`).
|
|
144
|
+
* Guarded to state = 'poison' so a job that transitions out of poison
|
|
145
|
+
* between the caller's read (for the forensics dump) and this delete is
|
|
146
|
+
* never silently swept up. Callers must capture ids via listPoison() first
|
|
147
|
+
* and write the forensics dump BEFORE calling this.
|
|
148
|
+
*/
|
|
149
|
+
purgePoisonByIds(ids) {
|
|
150
|
+
if (ids.length === 0)
|
|
151
|
+
return 0;
|
|
152
|
+
const placeholders = ids.map(() => '?').join(',');
|
|
153
|
+
return this.db.prepare(`DELETE FROM jobs WHERE state = 'poison' AND id IN (${placeholders})`).run(...ids).changes;
|
|
154
|
+
}
|
|
155
|
+
/** State → count map for /health queue reporting. */
|
|
156
|
+
stateCounts() {
|
|
157
|
+
const rows = this.db.prepare(`SELECT state, COUNT(*) AS n FROM jobs GROUP BY state`).all();
|
|
158
|
+
const out = {};
|
|
159
|
+
for (const r of rows)
|
|
160
|
+
out[r.state] = r.n;
|
|
161
|
+
return out;
|
|
162
|
+
}
|
|
163
|
+
_transition(id, state) {
|
|
164
|
+
const now = Date.now();
|
|
165
|
+
this.db.prepare('UPDATE jobs SET state = ?, updated_at = ? WHERE id = ?').run(state, now, id);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=job-repo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"job-repo.js","sourceRoot":"","sources":["../../src/pipeline/job-repo.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock providers for CI / integration testing.
|
|
3
|
+
*
|
|
4
|
+
* Used when ASTRA_MEMORY_MOCK_PROVIDERS=1 is set (or injected directly in tests).
|
|
5
|
+
*
|
|
6
|
+
* - MockLLMProvider: compaction returns the input text unchanged;
|
|
7
|
+
* extraction checks a small deterministic keyword table (see below) and
|
|
8
|
+
* returns one atom per matched keyword, or an empty atoms list if none match.
|
|
9
|
+
* - MockEmbedProvider: deterministic vector (dim defaults to
|
|
10
|
+
* DEFAULT_EMBED_DIM = 1024, configurable) seeded from text hash. No
|
|
11
|
+
* network, no Ollama required.
|
|
12
|
+
*
|
|
13
|
+
* These mocks satisfy the LLMProvider / EmbedProvider contracts and make
|
|
14
|
+
* the full 8-stage distillation pipeline runnable in CI.
|
|
15
|
+
*
|
|
16
|
+
* TEST-ONLY deterministic extraction vocabulary (SLICE-SMOKE-1 orchestrator
|
|
17
|
+
* decision, 2026-07-04: extending this file additively was approved as a
|
|
18
|
+
* relaxation of "no product-code changes" for test-double code specifically
|
|
19
|
+
* — see the smoke-suite run brief. Exclusively consumed by
|
|
20
|
+
* tests/smoke/_fixtures/session-canonical.json; fixture and this table must
|
|
21
|
+
* stay in lockstep, and this file is never reachable outside
|
|
22
|
+
* ASTRA_MEMORY_MOCK_PROVIDERS=1 (CI/test only — real serving never sets it).
|
|
23
|
+
* Each row is an independent case-insensitive substring match against the
|
|
24
|
+
* full extraction input; matching keywords each append one fixed atom (no
|
|
25
|
+
* parsing, no branching beyond the match itself):
|
|
26
|
+
*
|
|
27
|
+
* trigger keyword -> atom type -> entity emitted
|
|
28
|
+
* ---------------------------------------------------------------------
|
|
29
|
+
* "sqlite-vec" / "sqlite_vec" -> decision -> none (ORIGINAL, unchanged
|
|
30
|
+
* byte-for-byte since before
|
|
31
|
+
* SLICE-SMOKE-1)
|
|
32
|
+
* "priya nair" -> fact -> person: "Priya Nair"
|
|
33
|
+
* "astramemory-local" -> fact -> repo: "astramemory-local"
|
|
34
|
+
* "typescript" -> fact -> tech: "TypeScript"
|
|
35
|
+
* "todo:" -> todo -> none
|
|
36
|
+
* "prefers markdown summaries" -> note -> none (closest valid
|
|
37
|
+
* MemoryType — the schema
|
|
38
|
+
* has no 'preference' type)
|
|
39
|
+
*/
|
|
40
|
+
import type { ProviderSet } from '../providers/index.js';
|
|
41
|
+
export type MockProviderSet = ProviderSet;
|
|
42
|
+
/**
|
|
43
|
+
* Returns a ProviderSet backed entirely by mock providers.
|
|
44
|
+
* Safe to call multiple times — each call returns fresh instances.
|
|
45
|
+
* `dim` defaults to DEFAULT_EMBED_DIM (1024); pass e.g. cfg.embedding.dim
|
|
46
|
+
* to exercise a non-default dim under ASTRA_MEMORY_MOCK_PROVIDERS=1
|
|
47
|
+
* (FEAT-409 AC-2).
|
|
48
|
+
*/
|
|
49
|
+
export declare function makeMockProviders(dim?: number): MockProviderSet;
|