@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,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stage-0 secret redaction (spec docs/specs/2026-07-02-encryption-and-secret-redaction.md
|
|
3
|
+
* §4.2/§4.3, SEC-3..6/SEC-9).
|
|
4
|
+
*
|
|
5
|
+
* Single entry point: `redactText(input, opts)`. Invoked at the ingest choke
|
|
6
|
+
* point (POST /ingest/transcript, before the `transcripts` INSERT) and on the
|
|
7
|
+
* `/remember` manual-write path (spec OQ-2: yes). Downstream pipeline stages
|
|
8
|
+
* inherit already-redacted text — there is no second redaction pass.
|
|
9
|
+
*
|
|
10
|
+
* Placeholder format: `[REDACTED:<type>:<hash8>]` where hash8 = first 8 hex
|
|
11
|
+
* chars of SHA-256(secret value). Same secret -> same placeholder (dedup-safe
|
|
12
|
+
* across a transcript); the raw value is NEVER stored or logged (SEC-5).
|
|
13
|
+
*
|
|
14
|
+
* Detection order (never redact inside an already-inserted placeholder):
|
|
15
|
+
* 1. PEM private-key blocks (multiline, whole block)
|
|
16
|
+
* 2. Vendor/pattern detectors (AWS, GitHub, Azure, GCP, Slack, generic
|
|
17
|
+
* key=value, JWT, connection-string userinfo) + config custom patterns
|
|
18
|
+
* 3. Shannon-entropy detector over whatever text remains
|
|
19
|
+
*/
|
|
20
|
+
import { createHash } from 'node:crypto';
|
|
21
|
+
import { PEM_DETECTOR, PATTERN_DETECTORS, customDetector } from './detectors.js';
|
|
22
|
+
import { findEntropySecrets } from './entropy.js';
|
|
23
|
+
const PLACEHOLDER_RE_G = /\[REDACTED:[^\]]+\]/g;
|
|
24
|
+
function hash8(value) {
|
|
25
|
+
return createHash('sha256').update(value).digest('hex').slice(0, 8);
|
|
26
|
+
}
|
|
27
|
+
function placeholder(type, digest) {
|
|
28
|
+
return `[REDACTED:${type}:${digest}]`;
|
|
29
|
+
}
|
|
30
|
+
/** Spans already occupied by a previously-inserted placeholder in `text`. */
|
|
31
|
+
function protectedRanges(text) {
|
|
32
|
+
const ranges = [];
|
|
33
|
+
let m;
|
|
34
|
+
PLACEHOLDER_RE_G.lastIndex = 0;
|
|
35
|
+
while ((m = PLACEHOLDER_RE_G.exec(text)) !== null) {
|
|
36
|
+
ranges.push([m.index, m.index + m[0].length]);
|
|
37
|
+
}
|
|
38
|
+
return ranges;
|
|
39
|
+
}
|
|
40
|
+
function overlapsAny(start, end, ranges) {
|
|
41
|
+
return ranges.some(([rs, re]) => start < re && end > rs);
|
|
42
|
+
}
|
|
43
|
+
/** Run one PatternDetector over `text`, returning non-overlapping-with-protected spans. */
|
|
44
|
+
function runDetector(text, detector, guard) {
|
|
45
|
+
const flags = detector.flags.includes('g') ? detector.flags : `${detector.flags}g`;
|
|
46
|
+
const re = new RegExp(detector.source, flags.includes('d') ? flags : `${flags}d`);
|
|
47
|
+
const spans = [];
|
|
48
|
+
let m;
|
|
49
|
+
while ((m = re.exec(text)) !== null) {
|
|
50
|
+
let start;
|
|
51
|
+
let end;
|
|
52
|
+
let value;
|
|
53
|
+
const indices = m.indices;
|
|
54
|
+
const groupRange = detector.valueGroup !== undefined ? indices?.[detector.valueGroup] : undefined;
|
|
55
|
+
if (groupRange !== undefined) {
|
|
56
|
+
[start, end] = groupRange;
|
|
57
|
+
value = m[detector.valueGroup];
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
start = m.index;
|
|
61
|
+
end = m.index + m[0].length;
|
|
62
|
+
value = m[0];
|
|
63
|
+
}
|
|
64
|
+
if (end > start && !overlapsAny(start, end, guard)) {
|
|
65
|
+
spans.push({ type: detector.type, start, end, value });
|
|
66
|
+
}
|
|
67
|
+
if (re.lastIndex === m.index)
|
|
68
|
+
re.lastIndex++; // guard zero-length matches
|
|
69
|
+
}
|
|
70
|
+
return spans;
|
|
71
|
+
}
|
|
72
|
+
/** Drop spans that overlap an earlier (higher-priority) span from the same batch. */
|
|
73
|
+
function dedupeOverlaps(spans) {
|
|
74
|
+
const sorted = [...spans].sort((a, b) => a.start - b.start);
|
|
75
|
+
const kept = [];
|
|
76
|
+
let lastEnd = -1;
|
|
77
|
+
for (const s of sorted) {
|
|
78
|
+
if (s.start >= lastEnd) {
|
|
79
|
+
kept.push(s);
|
|
80
|
+
lastEnd = s.end;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return kept;
|
|
84
|
+
}
|
|
85
|
+
/** Replace `spans` (non-overlapping, sorted or not) in `text` with placeholders. */
|
|
86
|
+
function applySpans(text, spans) {
|
|
87
|
+
if (spans.length === 0)
|
|
88
|
+
return { text, events: [] };
|
|
89
|
+
const sorted = dedupeOverlaps(spans);
|
|
90
|
+
let out = '';
|
|
91
|
+
let cursor = 0;
|
|
92
|
+
const events = [];
|
|
93
|
+
for (const s of sorted) {
|
|
94
|
+
out += text.slice(cursor, s.start);
|
|
95
|
+
const digest = hash8(s.value);
|
|
96
|
+
out += placeholder(s.type, digest);
|
|
97
|
+
events.push({ type: s.type, hash8: digest, offset: s.start });
|
|
98
|
+
cursor = s.end;
|
|
99
|
+
}
|
|
100
|
+
out += text.slice(cursor);
|
|
101
|
+
return { text: out, events };
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Redact secrets from `input`. Pure function — no I/O, no DB writes (callers
|
|
105
|
+
* aggregate `events` into `redaction_log` themselves).
|
|
106
|
+
*/
|
|
107
|
+
export function redactText(input, opts = {}) {
|
|
108
|
+
const threshold = opts.entropyThreshold ?? 4.0;
|
|
109
|
+
const allEvents = [];
|
|
110
|
+
// ---- Stage 1: PEM blocks (multiline, first) ----
|
|
111
|
+
let text = input;
|
|
112
|
+
{
|
|
113
|
+
const guard = protectedRanges(text);
|
|
114
|
+
const spans = runDetector(text, PEM_DETECTOR, guard);
|
|
115
|
+
const applied = applySpans(text, spans);
|
|
116
|
+
text = applied.text;
|
|
117
|
+
allEvents.push(...applied.events);
|
|
118
|
+
}
|
|
119
|
+
// ---- Stage 2: vendor/pattern detectors + custom config patterns ----
|
|
120
|
+
{
|
|
121
|
+
const guard = protectedRanges(text);
|
|
122
|
+
const detectors = [
|
|
123
|
+
...PATTERN_DETECTORS,
|
|
124
|
+
...(opts.customPatterns ?? []).map(customDetector),
|
|
125
|
+
];
|
|
126
|
+
let spans = [];
|
|
127
|
+
for (const detector of detectors) {
|
|
128
|
+
try {
|
|
129
|
+
spans = spans.concat(runDetector(text, detector, guard));
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// Invalid custom regex from config — skip it rather than crash ingest.
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const applied = applySpans(text, spans);
|
|
136
|
+
text = applied.text;
|
|
137
|
+
allEvents.push(...applied.events);
|
|
138
|
+
}
|
|
139
|
+
// ---- Stage 3: entropy detector over what remains ----
|
|
140
|
+
{
|
|
141
|
+
const guard = protectedRanges(text);
|
|
142
|
+
const entropySpans = findEntropySecrets(text, threshold)
|
|
143
|
+
.filter(m => !overlapsAny(m.start, m.end, guard))
|
|
144
|
+
.map(m => ({ type: 'high_entropy', start: m.start, end: m.end, value: m.value }));
|
|
145
|
+
const applied = applySpans(text, entropySpans);
|
|
146
|
+
text = applied.text;
|
|
147
|
+
allEvents.push(...applied.events);
|
|
148
|
+
}
|
|
149
|
+
return { text, events: allEvents };
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Choke-point helper for route handlers: applies config (enabled flag,
|
|
153
|
+
* entropy threshold, custom patterns) and is a no-op passthrough when
|
|
154
|
+
* `security.redaction.enabled` is false (SEC-9).
|
|
155
|
+
*/
|
|
156
|
+
export function redactIfEnabled(input, config) {
|
|
157
|
+
if (!config.security.redaction.enabled) {
|
|
158
|
+
return { text: input, events: [] };
|
|
159
|
+
}
|
|
160
|
+
return redactText(input, {
|
|
161
|
+
entropyThreshold: config.security.redaction.entropyThreshold,
|
|
162
|
+
customPatterns: config.security.redaction.customPatterns,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/redact/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Score fusion for hybrid BM25 + cosine + importance + freshness ranking.
|
|
3
|
+
*
|
|
4
|
+
* Formula: raw = α·norm(bm25) + β·norm(cosine) + γ·importance + δ·freshness
|
|
5
|
+
* + ε·usefulness + ζ·entityBonus
|
|
6
|
+
* score = raw / (α + β + γ + δ + ε + ζ) ["active weight sum"]
|
|
7
|
+
*
|
|
8
|
+
* Wire-contract invariant: score MUST land in [0,1] (plugin Zod schema,
|
|
9
|
+
* memory-plugin#8) so the daemon response validates. Every component input
|
|
10
|
+
* is already bounded to [0,1] (normBm25/normCosine via normalizeScores,
|
|
11
|
+
* importance/freshness/usefulness by construction, entityBonus ∈ {0,1} —
|
|
12
|
+
* see entityBonusForQuery), so any convex-combination weight config keeps
|
|
13
|
+
* `raw` in [0, weightSum]; dividing by weightSum restores [0,1] even when
|
|
14
|
+
* the configured weights don't sum to 1 (default config sums to 1.1 — see
|
|
15
|
+
* config.ts search defaults — which without this normalization pushed
|
|
16
|
+
* perfect-match scores to ~1.04 and broke the wire contract).
|
|
17
|
+
*
|
|
18
|
+
* Defaults: α=β=0.4, γ=δ=ε=0.1, ζ=0. Pulled from config.search. The
|
|
19
|
+
* usefulness component (ADR-010 v1.x) is Laplace-smoothed to a neutral 0.5
|
|
20
|
+
* for atoms with no recall_used/memory_corrected signal, so ε only
|
|
21
|
+
* reshuffles atoms that have actually accumulated evidence.
|
|
22
|
+
*
|
|
23
|
+
* ζ (zeta, FEAT-402 slice 2 AC-6) is a distinct entity-relevance bonus: 1
|
|
24
|
+
* when a candidate is entity-linked to an entity mentioned in the query
|
|
25
|
+
* text, 0 otherwise — no-signal default is 0 (not usefulness's neutral 0.5),
|
|
26
|
+
* so with the default `zeta=0` weight the term contributes exactly 0 to
|
|
27
|
+
* every candidate and ranking order is byte-identical to pre-AC-6 behavior
|
|
28
|
+
* (see tests/search/fuse.test.ts zeta=0 no-op case and the eval harness
|
|
29
|
+
* zeta=0 snapshot test).
|
|
30
|
+
*
|
|
31
|
+
* Normalizing by the active weight sum is a per-call constant scalar (the
|
|
32
|
+
* weights config doesn't vary across hits in the same search), so it never
|
|
33
|
+
* changes relative ranking order for a fixed weight config — it is a
|
|
34
|
+
* monotone rescaling, applied uniformly to every candidate.
|
|
35
|
+
*/
|
|
36
|
+
export interface FuseInput {
|
|
37
|
+
normBm25: number;
|
|
38
|
+
normCosine: number;
|
|
39
|
+
importance: number;
|
|
40
|
+
freshness: number;
|
|
41
|
+
/** ADR-010 usefulness score [0,1]; 0.5 = no signal. */
|
|
42
|
+
usefulness?: number;
|
|
43
|
+
/** FEAT-402 AC-6 entity-relevance bonus, 0 or 1; 0 = no signal (unlike usefulness). */
|
|
44
|
+
entityBonus?: number;
|
|
45
|
+
alpha: number;
|
|
46
|
+
beta: number;
|
|
47
|
+
gamma: number;
|
|
48
|
+
delta: number;
|
|
49
|
+
/** usefulness weight; omitted = 0 (usefulness ignored) */
|
|
50
|
+
epsilon?: number;
|
|
51
|
+
/** entity-bonus weight; omitted or 0 = OFF (AC-6 default, ranking unchanged) */
|
|
52
|
+
zeta?: number;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Normalize an array of raw scores to [0,1] range.
|
|
56
|
+
* If all values are equal (range = 0) returns all ones.
|
|
57
|
+
*/
|
|
58
|
+
export declare function normalizeScores(scores: number[]): number[];
|
|
59
|
+
/**
|
|
60
|
+
* Compute fused score for a single hit whose components are already normalized.
|
|
61
|
+
*
|
|
62
|
+
* Returns a value in [0,1]: the weighted sum is divided by the sum of the
|
|
63
|
+
* active weights so the result stays in-range even when the configured
|
|
64
|
+
* weights don't sum to 1 (see module doc comment). Guards the degenerate
|
|
65
|
+
* all-zero-weights case by returning 0 rather than dividing by zero.
|
|
66
|
+
*/
|
|
67
|
+
export declare function fuseScores(input: FuseInput): number;
|
|
68
|
+
export interface RawHit {
|
|
69
|
+
id: string;
|
|
70
|
+
bm25?: number;
|
|
71
|
+
cosine?: number;
|
|
72
|
+
importance: number;
|
|
73
|
+
created_at: number;
|
|
74
|
+
}
|
|
75
|
+
export interface FusedHit {
|
|
76
|
+
id: string;
|
|
77
|
+
score: number;
|
|
78
|
+
source: 'fts' | 'vec' | 'both';
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Fuse a set of raw BM25 hits + cosine hits into a single ranked list.
|
|
82
|
+
*
|
|
83
|
+
* @param ftsHits Hits from FTS5, each with bm25 (negative in SQLite — we negate before normalization)
|
|
84
|
+
* @param vecHits Hits from vector search, each with cosine score [0,1] (1/(1+distance))
|
|
85
|
+
* @param metas Map of id → {importance, created_at} for all candidate ids
|
|
86
|
+
* @param weights α,β,γ,δ
|
|
87
|
+
* @param nowMs Current epoch ms for freshness computation
|
|
88
|
+
* @param freshnessDecayDays Half-life of freshness decay in days (default 30)
|
|
89
|
+
* @param usefulness Optional id → usefulness score [0,1] (ADR-010); missing ids default to 0.5
|
|
90
|
+
* @param entityBonus Optional id → entity-relevance bonus (FEAT-402 AC-6); missing ids default to 0
|
|
91
|
+
*/
|
|
92
|
+
export declare function fuseHits(ftsHits: Array<{
|
|
93
|
+
id: string;
|
|
94
|
+
bm25: number;
|
|
95
|
+
}>, vecHits: Array<{
|
|
96
|
+
id: string;
|
|
97
|
+
cosine: number;
|
|
98
|
+
}>, metas: Map<string, {
|
|
99
|
+
importance: number;
|
|
100
|
+
created_at: number;
|
|
101
|
+
}>, weights: {
|
|
102
|
+
alpha: number;
|
|
103
|
+
beta: number;
|
|
104
|
+
gamma: number;
|
|
105
|
+
delta: number;
|
|
106
|
+
epsilon?: number;
|
|
107
|
+
zeta?: number;
|
|
108
|
+
}, nowMs: number, freshnessDecayDays?: number, usefulness?: Map<string, number>, entityBonus?: Map<string, number>): FusedHit[];
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Score fusion for hybrid BM25 + cosine + importance + freshness ranking.
|
|
3
|
+
*
|
|
4
|
+
* Formula: raw = α·norm(bm25) + β·norm(cosine) + γ·importance + δ·freshness
|
|
5
|
+
* + ε·usefulness + ζ·entityBonus
|
|
6
|
+
* score = raw / (α + β + γ + δ + ε + ζ) ["active weight sum"]
|
|
7
|
+
*
|
|
8
|
+
* Wire-contract invariant: score MUST land in [0,1] (plugin Zod schema,
|
|
9
|
+
* memory-plugin#8) so the daemon response validates. Every component input
|
|
10
|
+
* is already bounded to [0,1] (normBm25/normCosine via normalizeScores,
|
|
11
|
+
* importance/freshness/usefulness by construction, entityBonus ∈ {0,1} —
|
|
12
|
+
* see entityBonusForQuery), so any convex-combination weight config keeps
|
|
13
|
+
* `raw` in [0, weightSum]; dividing by weightSum restores [0,1] even when
|
|
14
|
+
* the configured weights don't sum to 1 (default config sums to 1.1 — see
|
|
15
|
+
* config.ts search defaults — which without this normalization pushed
|
|
16
|
+
* perfect-match scores to ~1.04 and broke the wire contract).
|
|
17
|
+
*
|
|
18
|
+
* Defaults: α=β=0.4, γ=δ=ε=0.1, ζ=0. Pulled from config.search. The
|
|
19
|
+
* usefulness component (ADR-010 v1.x) is Laplace-smoothed to a neutral 0.5
|
|
20
|
+
* for atoms with no recall_used/memory_corrected signal, so ε only
|
|
21
|
+
* reshuffles atoms that have actually accumulated evidence.
|
|
22
|
+
*
|
|
23
|
+
* ζ (zeta, FEAT-402 slice 2 AC-6) is a distinct entity-relevance bonus: 1
|
|
24
|
+
* when a candidate is entity-linked to an entity mentioned in the query
|
|
25
|
+
* text, 0 otherwise — no-signal default is 0 (not usefulness's neutral 0.5),
|
|
26
|
+
* so with the default `zeta=0` weight the term contributes exactly 0 to
|
|
27
|
+
* every candidate and ranking order is byte-identical to pre-AC-6 behavior
|
|
28
|
+
* (see tests/search/fuse.test.ts zeta=0 no-op case and the eval harness
|
|
29
|
+
* zeta=0 snapshot test).
|
|
30
|
+
*
|
|
31
|
+
* Normalizing by the active weight sum is a per-call constant scalar (the
|
|
32
|
+
* weights config doesn't vary across hits in the same search), so it never
|
|
33
|
+
* changes relative ranking order for a fixed weight config — it is a
|
|
34
|
+
* monotone rescaling, applied uniformly to every candidate.
|
|
35
|
+
*/
|
|
36
|
+
/**
|
|
37
|
+
* Normalize an array of raw scores to [0,1] range.
|
|
38
|
+
* If all values are equal (range = 0) returns all ones.
|
|
39
|
+
*/
|
|
40
|
+
export function normalizeScores(scores) {
|
|
41
|
+
if (scores.length === 0)
|
|
42
|
+
return [];
|
|
43
|
+
const min = Math.min(...scores);
|
|
44
|
+
const max = Math.max(...scores);
|
|
45
|
+
const range = max - min;
|
|
46
|
+
// All-equal (including single-hit): every score is equally the best match
|
|
47
|
+
// within this component. Returning 0 would erase the component's signal
|
|
48
|
+
// entirely (a lone FTS hit would lose its whole BM25 contribution).
|
|
49
|
+
if (range === 0)
|
|
50
|
+
return scores.map(() => 1);
|
|
51
|
+
return scores.map(s => (s - min) / range);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Compute fused score for a single hit whose components are already normalized.
|
|
55
|
+
*
|
|
56
|
+
* Returns a value in [0,1]: the weighted sum is divided by the sum of the
|
|
57
|
+
* active weights so the result stays in-range even when the configured
|
|
58
|
+
* weights don't sum to 1 (see module doc comment). Guards the degenerate
|
|
59
|
+
* all-zero-weights case by returning 0 rather than dividing by zero.
|
|
60
|
+
*/
|
|
61
|
+
export function fuseScores(input) {
|
|
62
|
+
const raw = input.alpha * input.normBm25 +
|
|
63
|
+
input.beta * input.normCosine +
|
|
64
|
+
input.gamma * input.importance +
|
|
65
|
+
input.delta * input.freshness +
|
|
66
|
+
(input.epsilon ?? 0) * (input.usefulness ?? 0.5) +
|
|
67
|
+
(input.zeta ?? 0) * (input.entityBonus ?? 0);
|
|
68
|
+
const weightSum = input.alpha + input.beta + input.gamma + input.delta +
|
|
69
|
+
(input.epsilon ?? 0) + (input.zeta ?? 0);
|
|
70
|
+
if (weightSum === 0)
|
|
71
|
+
return 0;
|
|
72
|
+
// Defense-in-depth: components are bounded to [0,1] at their sources, but a
|
|
73
|
+
// future regression there must degrade to a capped score, not a wire-contract
|
|
74
|
+
// violation that makes plugin clients reject the whole response.
|
|
75
|
+
return Math.min(1, raw / weightSum);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Fuse a set of raw BM25 hits + cosine hits into a single ranked list.
|
|
79
|
+
*
|
|
80
|
+
* @param ftsHits Hits from FTS5, each with bm25 (negative in SQLite — we negate before normalization)
|
|
81
|
+
* @param vecHits Hits from vector search, each with cosine score [0,1] (1/(1+distance))
|
|
82
|
+
* @param metas Map of id → {importance, created_at} for all candidate ids
|
|
83
|
+
* @param weights α,β,γ,δ
|
|
84
|
+
* @param nowMs Current epoch ms for freshness computation
|
|
85
|
+
* @param freshnessDecayDays Half-life of freshness decay in days (default 30)
|
|
86
|
+
* @param usefulness Optional id → usefulness score [0,1] (ADR-010); missing ids default to 0.5
|
|
87
|
+
* @param entityBonus Optional id → entity-relevance bonus (FEAT-402 AC-6); missing ids default to 0
|
|
88
|
+
*/
|
|
89
|
+
export function fuseHits(ftsHits, vecHits, metas, weights, nowMs, freshnessDecayDays = 30, usefulness, entityBonus) {
|
|
90
|
+
// Build per-id raw maps
|
|
91
|
+
const ftsMap = new Map(ftsHits.map(h => [h.id, h.bm25]));
|
|
92
|
+
const vecMap = new Map(vecHits.map(h => [h.id, h.cosine]));
|
|
93
|
+
// Union of all candidate ids
|
|
94
|
+
const ids = new Set([...ftsMap.keys(), ...vecMap.keys()]);
|
|
95
|
+
// Normalize BM25 — SQLite bm25() returns negative values (lower = better match)
|
|
96
|
+
// Negate so higher positive = better, then normalize
|
|
97
|
+
const rawBm25Values = ftsHits.map(h => -h.bm25); // negate
|
|
98
|
+
const normBm25Arr = normalizeScores(rawBm25Values);
|
|
99
|
+
const normBm25Map = new Map(ftsHits.map((h, i) => [h.id, normBm25Arr[i] ?? 0]));
|
|
100
|
+
// Normalize cosine scores
|
|
101
|
+
const rawCosineValues = vecHits.map(h => h.cosine);
|
|
102
|
+
const normCosineArr = normalizeScores(rawCosineValues);
|
|
103
|
+
const normCosineMap = new Map(vecHits.map((h, i) => [h.id, normCosineArr[i] ?? 0]));
|
|
104
|
+
// Freshness: exponential decay, half-life = freshnessDecayDays
|
|
105
|
+
const decayMs = freshnessDecayDays * 24 * 60 * 60 * 1000;
|
|
106
|
+
const results = [];
|
|
107
|
+
for (const id of ids) {
|
|
108
|
+
const meta = metas.get(id);
|
|
109
|
+
const importance = meta?.importance ?? 0.5;
|
|
110
|
+
const createdAt = meta?.created_at ?? nowMs;
|
|
111
|
+
const ageDays = (nowMs - createdAt) / (24 * 60 * 60 * 1000);
|
|
112
|
+
// Clamp to 1: a future created_at (SaaS-sync clock skew — puller.ts stores
|
|
113
|
+
// remote-minted timestamps verbatim) makes ageDays negative and exp() > 1,
|
|
114
|
+
// which would push the fused score past the [0,1] wire contract.
|
|
115
|
+
const freshness = Math.min(1, Math.exp(-ageDays / (decayMs / (24 * 60 * 60 * 1000))));
|
|
116
|
+
const normBm25 = normBm25Map.get(id) ?? 0;
|
|
117
|
+
const normCosine = normCosineMap.get(id) ?? 0;
|
|
118
|
+
const score = fuseScores({
|
|
119
|
+
normBm25,
|
|
120
|
+
normCosine,
|
|
121
|
+
importance,
|
|
122
|
+
freshness,
|
|
123
|
+
usefulness: usefulness?.get(id),
|
|
124
|
+
entityBonus: entityBonus?.get(id),
|
|
125
|
+
...weights
|
|
126
|
+
});
|
|
127
|
+
const inFts = ftsMap.has(id);
|
|
128
|
+
const inVec = vecMap.has(id);
|
|
129
|
+
const source = inFts && inVec ? 'both' : inFts ? 'fts' : 'vec';
|
|
130
|
+
results.push({ id, score, source });
|
|
131
|
+
}
|
|
132
|
+
results.sort((a, b) => b.score - a.score);
|
|
133
|
+
return results;
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=fuse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fuse.js","sourceRoot":"","sources":["../../src/search/fuse.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query string parser for AstraMemory search.
|
|
3
|
+
*
|
|
4
|
+
* Parses structured filter tokens from a query string:
|
|
5
|
+
* type:decision → filters.type = ['decision']
|
|
6
|
+
* repo:my-repo → filters.repo = 'my-repo'
|
|
7
|
+
* project:wave2 → filters.project = 'wave2'
|
|
8
|
+
* since:7d → filters.since = epoch ms 7 days ago
|
|
9
|
+
* since:24h → filters.since = epoch ms 24 hours ago
|
|
10
|
+
* since:Nh → filters.since = epoch ms N hours ago
|
|
11
|
+
*
|
|
12
|
+
* Unknown prefixes are left in the bare query text (not applied as filters).
|
|
13
|
+
* Design choice: unknown filters are silently ignored (not rejected as 400)
|
|
14
|
+
* because the CLI passes arbitrary user text and we prefer forgiving parse.
|
|
15
|
+
*/
|
|
16
|
+
export interface ParsedQuery {
|
|
17
|
+
/** Bare search terms with filter tokens removed */
|
|
18
|
+
q: string;
|
|
19
|
+
/** Extracted structured filters */
|
|
20
|
+
filters: {
|
|
21
|
+
type?: string[];
|
|
22
|
+
repo?: string;
|
|
23
|
+
project?: string;
|
|
24
|
+
/** Epoch ms lower bound for created_at */
|
|
25
|
+
since?: number;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export declare function parseQuery(raw: string): ParsedQuery;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query string parser for AstraMemory search.
|
|
3
|
+
*
|
|
4
|
+
* Parses structured filter tokens from a query string:
|
|
5
|
+
* type:decision → filters.type = ['decision']
|
|
6
|
+
* repo:my-repo → filters.repo = 'my-repo'
|
|
7
|
+
* project:wave2 → filters.project = 'wave2'
|
|
8
|
+
* since:7d → filters.since = epoch ms 7 days ago
|
|
9
|
+
* since:24h → filters.since = epoch ms 24 hours ago
|
|
10
|
+
* since:Nh → filters.since = epoch ms N hours ago
|
|
11
|
+
*
|
|
12
|
+
* Unknown prefixes are left in the bare query text (not applied as filters).
|
|
13
|
+
* Design choice: unknown filters are silently ignored (not rejected as 400)
|
|
14
|
+
* because the CLI passes arbitrary user text and we prefer forgiving parse.
|
|
15
|
+
*/
|
|
16
|
+
const KNOWN_FILTERS = new Set(['type', 'repo', 'project', 'since']);
|
|
17
|
+
/**
|
|
18
|
+
* Parse a duration string like "7d" or "24h" into milliseconds.
|
|
19
|
+
* Returns null if format is unrecognized.
|
|
20
|
+
*/
|
|
21
|
+
function parseDuration(value) {
|
|
22
|
+
const dMatch = value.match(/^(\d+)d$/);
|
|
23
|
+
if (dMatch)
|
|
24
|
+
return Number(dMatch[1]) * 24 * 60 * 60 * 1000;
|
|
25
|
+
const hMatch = value.match(/^(\d+)h$/);
|
|
26
|
+
if (hMatch)
|
|
27
|
+
return Number(hMatch[1]) * 60 * 60 * 1000;
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
export function parseQuery(raw) {
|
|
31
|
+
const filters = {};
|
|
32
|
+
const bareTerms = [];
|
|
33
|
+
const tokens = raw.trim().split(/\s+/);
|
|
34
|
+
for (const token of tokens) {
|
|
35
|
+
if (!token)
|
|
36
|
+
continue;
|
|
37
|
+
const colonIdx = token.indexOf(':');
|
|
38
|
+
if (colonIdx > 0) {
|
|
39
|
+
const key = token.slice(0, colonIdx);
|
|
40
|
+
const val = token.slice(colonIdx + 1);
|
|
41
|
+
if (KNOWN_FILTERS.has(key) && val) {
|
|
42
|
+
switch (key) {
|
|
43
|
+
case 'type':
|
|
44
|
+
filters.type = filters.type ? [...filters.type, val] : [val];
|
|
45
|
+
break;
|
|
46
|
+
case 'repo':
|
|
47
|
+
filters.repo = val;
|
|
48
|
+
break;
|
|
49
|
+
case 'project':
|
|
50
|
+
filters.project = val;
|
|
51
|
+
break;
|
|
52
|
+
case 'since': {
|
|
53
|
+
const durationMs = parseDuration(val);
|
|
54
|
+
if (durationMs !== null) {
|
|
55
|
+
filters.since = Date.now() - durationMs;
|
|
56
|
+
}
|
|
57
|
+
// If format is unrecognized, drop silently (treat as ignored)
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Known filter processed — do not include in bare query
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Unknown token (no colon, or unknown prefix) → include in bare query
|
|
66
|
+
bareTerms.push(token);
|
|
67
|
+
}
|
|
68
|
+
return { q: bareTerms.join(' '), filters };
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/search/query.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAeH,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;AAEpE;;;GAGG;AACH,SAAS,aAAa,CAAC,KAAa;IAClC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACvC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAC3D,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACvC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IACtD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,MAAM,SAAS,GAAa,EAAE,CAAC;IAE/B,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAEvC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YACjB,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;YACrC,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;YACtC,IAAI,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;gBAClC,QAAQ,GAAG,EAAE,CAAC;oBACZ,KAAK,MAAM;wBACT,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;wBAC7D,MAAM;oBACR,KAAK,MAAM;wBACT,OAAO,CAAC,IAAI,GAAG,GAAG,CAAC;wBACnB,MAAM;oBACR,KAAK,SAAS;wBACZ,OAAO,CAAC,OAAO,GAAG,GAAG,CAAC;wBACtB,MAAM;oBACR,KAAK,OAAO,CAAC,CAAC,CAAC;wBACb,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;wBACtC,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;4BACxB,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC;wBAC1C,CAAC;wBACD,8DAA8D;wBAC9D,MAAM;oBACR,CAAC;gBACH,CAAC;gBACD,wDAAwD;gBACxD,SAAS;YACX,CAAC;QACH,CAAC;QACD,sEAAsE;QACtE,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;IAED,OAAO,EAAE,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,CAAC;AAC7C,CAAC"}
|