@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,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GET /dashboard/search — search debug page (FEAT-410 wave 2, SLICE-410-6).
|
|
3
|
+
*
|
|
4
|
+
* Plain GET `<form>` (query in the URL) rendering the per-candidate fusion
|
|
5
|
+
* score table from SLICE-410-3's `debug: true` search() path, plus the
|
|
6
|
+
* current fuse.ts weights (src/config/config.ts `search` defaults). Zero JS.
|
|
7
|
+
*
|
|
8
|
+
* Auth mirrors src/server/routes/dashboard.ts (Bearer header or the
|
|
9
|
+
* HttpOnly `astramem_dash` cookie bootstrapped there) but the check is
|
|
10
|
+
* duplicated locally by design — see dashboard-consolidation-html.ts for
|
|
11
|
+
* the same rationale. HTML escaping is likewise duplicated locally rather
|
|
12
|
+
* than importing dashboard-html.ts's `esc()` (SLICE-410-6 scope: this file
|
|
13
|
+
* + its tests only).
|
|
14
|
+
*/
|
|
15
|
+
import { search } from '../../search/search.js';
|
|
16
|
+
import { defaultConfig } from '../../config/config.js';
|
|
17
|
+
const COOKIE_NAME = 'astramem_dash';
|
|
18
|
+
const RESULT_LIMIT = 20;
|
|
19
|
+
function readCookie(req, name) {
|
|
20
|
+
const header = req.headers.cookie;
|
|
21
|
+
if (!header)
|
|
22
|
+
return undefined;
|
|
23
|
+
for (const part of header.split(';')) {
|
|
24
|
+
const eq = part.indexOf('=');
|
|
25
|
+
if (eq === -1)
|
|
26
|
+
continue;
|
|
27
|
+
if (part.slice(0, eq).trim() === name)
|
|
28
|
+
return part.slice(eq + 1).trim();
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
function esc(s) {
|
|
33
|
+
return s
|
|
34
|
+
.replace(/&/g, '&')
|
|
35
|
+
.replace(/</g, '<')
|
|
36
|
+
.replace(/>/g, '>')
|
|
37
|
+
.replace(/"/g, '"');
|
|
38
|
+
}
|
|
39
|
+
/** "0.4" -> ".4" to match the design doc's compact weight notation (α.4 β.4 …). */
|
|
40
|
+
function fmtWeight(n) {
|
|
41
|
+
return String(n).replace(/^0\./, '.').replace(/^-0\./, '-.');
|
|
42
|
+
}
|
|
43
|
+
function fmtScore(n) {
|
|
44
|
+
return n.toFixed(3);
|
|
45
|
+
}
|
|
46
|
+
export function dashboardSearchRoute(db, embed, token) {
|
|
47
|
+
return async (app) => {
|
|
48
|
+
app.get('/dashboard/search', async (req, reply) => {
|
|
49
|
+
const authHeader = req.headers.authorization;
|
|
50
|
+
const bearerOk = authHeader === `Bearer ${token}`;
|
|
51
|
+
const cookieOk = readCookie(req, COOKIE_NAME) === token;
|
|
52
|
+
if (!bearerOk && !cookieOk) {
|
|
53
|
+
return reply
|
|
54
|
+
.code(401)
|
|
55
|
+
.header('content-type', 'text/plain; charset=utf-8')
|
|
56
|
+
.send('401 Unauthorized');
|
|
57
|
+
}
|
|
58
|
+
const q = req.query;
|
|
59
|
+
const rawQuery = q.query;
|
|
60
|
+
const weights = defaultConfig().search;
|
|
61
|
+
// Optional filter fields — every implemented search() filter mode is
|
|
62
|
+
// exposed: entity (FEAT-402), as_of temporal time-travel (FEAT-401),
|
|
63
|
+
// since lower bound, type list. Empty strings mean "not set".
|
|
64
|
+
const filterInputs = {
|
|
65
|
+
entity: q.entity?.trim() || undefined,
|
|
66
|
+
type: q.type?.trim() || undefined,
|
|
67
|
+
as_of: q.as_of?.trim() || undefined,
|
|
68
|
+
since: q.since?.trim() || undefined,
|
|
69
|
+
};
|
|
70
|
+
const filters = {};
|
|
71
|
+
if (filterInputs.entity)
|
|
72
|
+
filters.entity = filterInputs.entity;
|
|
73
|
+
if (filterInputs.type)
|
|
74
|
+
filters.type = filterInputs.type.split(',').map(s => s.trim()).filter(Boolean);
|
|
75
|
+
// datetime-local values ("2026-07-04T09:30") parse as local time —
|
|
76
|
+
// matching the operator's clock on this local-first daemon.
|
|
77
|
+
if (filterInputs.as_of) {
|
|
78
|
+
const t = new Date(filterInputs.as_of).getTime();
|
|
79
|
+
if (!Number.isNaN(t))
|
|
80
|
+
filters.as_of = t;
|
|
81
|
+
}
|
|
82
|
+
if (filterInputs.since) {
|
|
83
|
+
const t = new Date(filterInputs.since).getTime();
|
|
84
|
+
if (!Number.isNaN(t))
|
|
85
|
+
filters.since = t;
|
|
86
|
+
}
|
|
87
|
+
// AC-2: no `query` key at all → initial load, form + weights only.
|
|
88
|
+
// Any present value (including "") is treated as a submitted search
|
|
89
|
+
// so a zero-candidate result renders the explicit AC-3 empty state
|
|
90
|
+
// rather than silently looking like the initial load.
|
|
91
|
+
const ranSearch = rawQuery !== undefined;
|
|
92
|
+
let hits = [];
|
|
93
|
+
if (ranSearch) {
|
|
94
|
+
hits = await search(rawQuery, filters, RESULT_LIMIT, { db, embed, weights, debug: true });
|
|
95
|
+
}
|
|
96
|
+
return reply
|
|
97
|
+
.code(200)
|
|
98
|
+
.header('content-type', 'text/html; charset=utf-8')
|
|
99
|
+
.header('cache-control', 'no-store')
|
|
100
|
+
.send(renderPage(rawQuery, weights, ranSearch, hits, filterInputs));
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function renderWeights(weights) {
|
|
105
|
+
return `α${fmtWeight(weights.alpha)} β${fmtWeight(weights.beta)} `
|
|
106
|
+
+ `γ${fmtWeight(weights.gamma)} δ${fmtWeight(weights.delta)} `
|
|
107
|
+
+ `ε${fmtWeight(weights.epsilon)} ζ${fmtWeight(weights.zeta)}`;
|
|
108
|
+
}
|
|
109
|
+
function renderTable(hits) {
|
|
110
|
+
const rows = hits.map((h, i) => `
|
|
111
|
+
<tr>
|
|
112
|
+
<td>${esc(h.id.slice(0, 8))}…</td>
|
|
113
|
+
<td>${esc(h.source)}</td>
|
|
114
|
+
<td>${fmtScore(h.bm25.normalized)}</td>
|
|
115
|
+
<td>${fmtScore(h.cosine.normalized)}</td>
|
|
116
|
+
<td>${fmtScore(h.importance)}</td>
|
|
117
|
+
<td>${fmtScore(h.freshness)}</td>
|
|
118
|
+
<td>${fmtScore(h.score)}</td>
|
|
119
|
+
<td>${i + 1}</td>
|
|
120
|
+
</tr>`).join('');
|
|
121
|
+
return `<table>
|
|
122
|
+
<thead>
|
|
123
|
+
<tr>
|
|
124
|
+
<th>id</th><th>source</th><th>bm25(norm)</th><th>cosine(norm)</th>
|
|
125
|
+
<th>importance</th><th>freshness</th><th>fused</th><th>rank</th>
|
|
126
|
+
</tr>
|
|
127
|
+
</thead>
|
|
128
|
+
<tbody>${rows}
|
|
129
|
+
</tbody>
|
|
130
|
+
</table>`;
|
|
131
|
+
}
|
|
132
|
+
function renderResults(ranSearch, hits) {
|
|
133
|
+
if (!ranSearch)
|
|
134
|
+
return '';
|
|
135
|
+
if (hits.length === 0)
|
|
136
|
+
return '<p class="empty">no results</p>';
|
|
137
|
+
return renderTable(hits);
|
|
138
|
+
}
|
|
139
|
+
const CSS = `
|
|
140
|
+
*{box-sizing:border-box;margin:0;padding:0}
|
|
141
|
+
body{background:#1a1a1a;color:#e0e0e0;font-family:monospace;font-size:13px;line-height:1.5;padding:16px}
|
|
142
|
+
h1{font-size:18px;color:#fff;margin-bottom:12px}
|
|
143
|
+
form{margin-bottom:8px}
|
|
144
|
+
input[type=text]{background:#0f0f0f;color:#e0e0e0;border:1px solid #333;padding:4px 8px;width:320px}
|
|
145
|
+
button{background:#2a2a2a;color:#e0e0e0;border:1px solid #444;padding:4px 10px;margin-left:4px}
|
|
146
|
+
.weights{color:#888;margin-bottom:16px}
|
|
147
|
+
nav{display:flex;gap:16px;margin:8px 0 16px;padding-bottom:8px;border-bottom:1px solid #333;font-size:12px}
|
|
148
|
+
nav a{color:#888;text-decoration:none}
|
|
149
|
+
nav a:hover{color:#3a7bd5}
|
|
150
|
+
nav .active{color:#fff;font-weight:bold}
|
|
151
|
+
.filters{margin-top:8px;display:flex;gap:12px;flex-wrap:wrap;color:#888}
|
|
152
|
+
.filters input{width:170px}
|
|
153
|
+
.filters input[type=datetime-local]{width:200px;background:#0f0f0f;color:#e0e0e0;border:1px solid #333;padding:3px 6px}
|
|
154
|
+
.hint{color:#666;font-size:11px;margin-top:6px}
|
|
155
|
+
table{border-collapse:collapse;width:100%}
|
|
156
|
+
th,td{border-bottom:1px solid #333;padding:4px 8px;text-align:left}
|
|
157
|
+
th{color:#aaa;text-transform:uppercase;font-size:11px;letter-spacing:.05em}
|
|
158
|
+
.empty{color:#888;margin-top:12px}
|
|
159
|
+
`;
|
|
160
|
+
function renderPage(rawQuery, weights, ranSearch, hits, f) {
|
|
161
|
+
const queryValue = esc(rawQuery ?? '');
|
|
162
|
+
return `<!DOCTYPE html>
|
|
163
|
+
<html lang="en">
|
|
164
|
+
<head>
|
|
165
|
+
<meta charset="utf-8">
|
|
166
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
167
|
+
<title>AstraMemory Dashboard — Search debug</title>
|
|
168
|
+
<style>${CSS}</style>
|
|
169
|
+
</head>
|
|
170
|
+
<body>
|
|
171
|
+
<h1>Search debug</h1>
|
|
172
|
+
<nav><a href="/dashboard">Mission Control</a> <a href="/dashboard/jobs">Jobs</a> <a href="/dashboard/consolidation">Consolidation</a> <span class="active">Search</span> <a href="/dashboard/api">API</a></nav>
|
|
173
|
+
<form method="get" action="/dashboard/search">
|
|
174
|
+
<input type="text" name="query" value="${queryValue}" placeholder="query...">
|
|
175
|
+
<button type="submit">run</button>
|
|
176
|
+
<div class="filters">
|
|
177
|
+
<label>entity <input type="text" name="entity" value="${esc(f.entity ?? '')}" placeholder="entity name"></label>
|
|
178
|
+
<label>type <input type="text" name="type" value="${esc(f.type ?? '')}" placeholder="fact,decision,…"></label>
|
|
179
|
+
<label>as of <input type="datetime-local" name="as_of" value="${esc(f.as_of ?? '')}"></label>
|
|
180
|
+
<label>since <input type="datetime-local" name="since" value="${esc(f.since ?? '')}"></label>
|
|
181
|
+
</div>
|
|
182
|
+
<p class="hint">modes: hybrid FTS(bm25)+vector fusion always on · entity filter (exact, then substring) · as-of = bitemporal time-travel · since = created_at lower bound · type = comma-separated list</p>
|
|
183
|
+
</form>
|
|
184
|
+
<p class="weights">weights: ${renderWeights(weights)}</p>
|
|
185
|
+
${renderResults(ranSearch, hits)}
|
|
186
|
+
</body>
|
|
187
|
+
</html>`;
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=dashboard-search-html.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-search-html.js","sourceRoot":"","sources":["../../../src/server/routes/dashboard-search-html.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GET /dashboard
|
|
3
|
+
*
|
|
4
|
+
* Read-only HTML metrics dashboard. Auth accepts (in order):
|
|
5
|
+
* 1. Authorization: Bearer <token> — same as every other route.
|
|
6
|
+
* 2. HttpOnly session cookie (set by the one-time bootstrap below).
|
|
7
|
+
* 3. ?token=<bearer> — bootstrap ONLY: exchanged for the cookie via a 302
|
|
8
|
+
* redirect to the clean URL, so the bearer never persists in browser
|
|
9
|
+
* history and is not re-sent by the <meta refresh> poll.
|
|
10
|
+
* Returns 401 plain text on missing/wrong credentials; the 401 log strips the
|
|
11
|
+
* query string so wrong-token attempts don't persist candidate secrets.
|
|
12
|
+
*
|
|
13
|
+
* No JS, no external assets. <meta refresh content="5"> drives auto-poll.
|
|
14
|
+
*/
|
|
15
|
+
import type { FastifyInstance } from 'fastify';
|
|
16
|
+
import type { DB } from '../../storage/db.js';
|
|
17
|
+
import type { Config } from '../../config/config.js';
|
|
18
|
+
import type { HealthState } from '../health-state.js';
|
|
19
|
+
export declare function dashboardRoute(db: DB, config: Config, token: string, healthState?: HealthState): (app: FastifyInstance) => Promise<void>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GET /dashboard
|
|
3
|
+
*
|
|
4
|
+
* Read-only HTML metrics dashboard. Auth accepts (in order):
|
|
5
|
+
* 1. Authorization: Bearer <token> — same as every other route.
|
|
6
|
+
* 2. HttpOnly session cookie (set by the one-time bootstrap below).
|
|
7
|
+
* 3. ?token=<bearer> — bootstrap ONLY: exchanged for the cookie via a 302
|
|
8
|
+
* redirect to the clean URL, so the bearer never persists in browser
|
|
9
|
+
* history and is not re-sent by the <meta refresh> poll.
|
|
10
|
+
* Returns 401 plain text on missing/wrong credentials; the 401 log strips the
|
|
11
|
+
* query string so wrong-token attempts don't persist candidate secrets.
|
|
12
|
+
*
|
|
13
|
+
* No JS, no external assets. <meta refresh content="5"> drives auto-poll.
|
|
14
|
+
*/
|
|
15
|
+
import { queryDashboard } from '../queries/dashboard.js';
|
|
16
|
+
import { renderDashboard } from './dashboard-html.js';
|
|
17
|
+
import { childLogger } from '../../log/logger.js';
|
|
18
|
+
const COOKIE_NAME = 'astramem_dash';
|
|
19
|
+
function readCookie(req, name) {
|
|
20
|
+
const header = req.headers.cookie;
|
|
21
|
+
if (!header)
|
|
22
|
+
return undefined;
|
|
23
|
+
for (const part of header.split(';')) {
|
|
24
|
+
const eq = part.indexOf('=');
|
|
25
|
+
if (eq === -1)
|
|
26
|
+
continue;
|
|
27
|
+
if (part.slice(0, eq).trim() === name)
|
|
28
|
+
return part.slice(eq + 1).trim();
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
export function dashboardRoute(db, config, token, healthState) {
|
|
33
|
+
return async (app) => {
|
|
34
|
+
app.get('/dashboard', async (req, reply) => {
|
|
35
|
+
const requestId = req['requestId'];
|
|
36
|
+
const log = childLogger({ request_id: requestId ?? 'unknown' });
|
|
37
|
+
const authHeader = req.headers.authorization;
|
|
38
|
+
const bearerOk = authHeader === `Bearer ${token}`;
|
|
39
|
+
const cookieOk = readCookie(req, COOKIE_NAME) === token;
|
|
40
|
+
if (!bearerOk && !cookieOk) {
|
|
41
|
+
const queryToken = req.query['token'];
|
|
42
|
+
if (queryToken === token) {
|
|
43
|
+
// Bootstrap: swap the URL token for an HttpOnly cookie and redirect
|
|
44
|
+
// to the clean path so the bearer leaves the address bar immediately.
|
|
45
|
+
// No Secure flag: the daemon is plain-HTTP on 127.0.0.1 by design.
|
|
46
|
+
return reply
|
|
47
|
+
.header('set-cookie', `${COOKIE_NAME}=${token}; HttpOnly; SameSite=Strict; Path=/dashboard`)
|
|
48
|
+
.redirect('/dashboard', 302);
|
|
49
|
+
}
|
|
50
|
+
// Strip the query string from the log — a wrong ?token= is a candidate
|
|
51
|
+
// credential and must not persist in log files.
|
|
52
|
+
log.warn({ method: req.method, path: req.url.split('?')[0] }, 'dashboard: unauthorized');
|
|
53
|
+
return reply
|
|
54
|
+
.code(401)
|
|
55
|
+
.header('content-type', 'text/plain; charset=utf-8')
|
|
56
|
+
.send('401 Unauthorized - supply Authorization: Bearer <token> or bootstrap once with ?token=<bearer>');
|
|
57
|
+
}
|
|
58
|
+
const data = await queryDashboard(db, healthState);
|
|
59
|
+
const html = renderDashboard(data, config);
|
|
60
|
+
return reply
|
|
61
|
+
.code(200)
|
|
62
|
+
.header('content-type', 'text/html; charset=utf-8')
|
|
63
|
+
.header('cache-control', 'no-store')
|
|
64
|
+
.send(html);
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=dashboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../../src/server/routes/dashboard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session digest route (KF-C): "what I learned this session".
|
|
3
|
+
* GET /sessions/:id/digest
|
|
4
|
+
* Derived at read time from memories(session_id); no stored digest state.
|
|
5
|
+
* status=pending while a distill job for this session is queued/running.
|
|
6
|
+
*/
|
|
7
|
+
import type { FastifyInstance } from 'fastify';
|
|
8
|
+
import type { DB } from '../../storage/db.js';
|
|
9
|
+
export declare function digestRoute(db: DB): (app: FastifyInstance) => Promise<void>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session digest route (KF-C): "what I learned this session".
|
|
3
|
+
* GET /sessions/:id/digest
|
|
4
|
+
* Derived at read time from memories(session_id); no stored digest state.
|
|
5
|
+
* status=pending while a distill job for this session is queued/running.
|
|
6
|
+
*/
|
|
7
|
+
export function digestRoute(db) {
|
|
8
|
+
return async (app) => {
|
|
9
|
+
app.get('/sessions/:id/digest', async (req, reply) => {
|
|
10
|
+
const { id } = req.params;
|
|
11
|
+
const session = db.prepare('SELECT id FROM sessions WHERE id = ?').get(id);
|
|
12
|
+
if (!session) {
|
|
13
|
+
return reply.code(404).send({ error: 'not found', session_id: id });
|
|
14
|
+
}
|
|
15
|
+
// A distill job for this session still queued or running → pending.
|
|
16
|
+
// json_extract (SQLite JSON1, bundled with better-sqlite3) — exact match,
|
|
17
|
+
// immune to LIKE-wildcard injection and payload key reordering.
|
|
18
|
+
const activeJob = db.prepare(`
|
|
19
|
+
SELECT id FROM jobs
|
|
20
|
+
WHERE kind = 'distill' AND state IN ('pending', 'running')
|
|
21
|
+
AND json_extract(payload_json, '$.session_id') = ?
|
|
22
|
+
LIMIT 1
|
|
23
|
+
`).get(id);
|
|
24
|
+
const rows = db.prepare('SELECT id, type, text FROM memories WHERE session_id = ? ORDER BY created_at ASC').all(id);
|
|
25
|
+
const counts = {};
|
|
26
|
+
for (const r of rows)
|
|
27
|
+
counts[r.type] = (counts[r.type] ?? 0) + 1;
|
|
28
|
+
return {
|
|
29
|
+
session_id: id,
|
|
30
|
+
status: activeJob ? 'pending' : 'ready',
|
|
31
|
+
counts,
|
|
32
|
+
memories: rows,
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=digest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"digest.js","sourceRoot":"","sources":["../../../src/server/routes/digest.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,MAAM,UAAU,WAAW,CAAC,EAAM;IAChC,OAAO,KAAK,EAAE,GAAoB,EAAE,EAAE;QACpC,GAAG,CAAC,GAAG,CAAC,sBAAsB,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;YACnD,MAAM,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC,MAAwB,CAAC;YAE5C,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,sCAAsC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC3E,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC;YACtE,CAAC;YAED,oEAAoE;YACpE,0EAA0E;YAC1E,gEAAgE;YAChE,MAAM,SAAS,GAAG,EAAE,CAAC,OAAO,CAAC;;;;;OAK5B,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAEX,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CACrB,kFAAkF,CACnF,CAAC,GAAG,CAAC,EAAE,CAAa,CAAC;YAEtB,MAAM,MAAM,GAA2B,EAAE,CAAC;YAC1C,KAAK,MAAM,CAAC,IAAI,IAAI;gBAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YAEjE,OAAO;gBACL,UAAU,EAAE,EAAE;gBACd,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO;gBACvC,MAAM;gBACN,QAAQ,EAAE,IAAI;aACf,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity query routes (FEAT-402 slice 2, AC-5):
|
|
3
|
+
* GET /entities?q=&limit= — autocomplete (name substring match)
|
|
4
|
+
* GET /entities/:id/memories — every memory linked to this entity
|
|
5
|
+
*
|
|
6
|
+
* Both routes sit behind the same Bearer-auth preHandler as every other
|
|
7
|
+
* non-public route (src/server/app.ts) — neither is in the /health,
|
|
8
|
+
* /version, /dashboard allowlist.
|
|
9
|
+
*/
|
|
10
|
+
import type { FastifyInstance } from 'fastify';
|
|
11
|
+
import type { DB } from '../../storage/db.js';
|
|
12
|
+
export declare function entitiesRoute(db: DB): (app: FastifyInstance) => Promise<void>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity query routes (FEAT-402 slice 2, AC-5):
|
|
3
|
+
* GET /entities?q=&limit= — autocomplete (name substring match)
|
|
4
|
+
* GET /entities/:id/memories — every memory linked to this entity
|
|
5
|
+
*
|
|
6
|
+
* Both routes sit behind the same Bearer-auth preHandler as every other
|
|
7
|
+
* non-public route (src/server/app.ts) — neither is in the /health,
|
|
8
|
+
* /version, /dashboard allowlist.
|
|
9
|
+
*/
|
|
10
|
+
import { EntityRepo } from '../../storage/entities.js';
|
|
11
|
+
import { MemoryRepo } from '../../storage/memories.js';
|
|
12
|
+
export function entitiesRoute(db) {
|
|
13
|
+
return async (app) => {
|
|
14
|
+
// GET /entities?q=pg — autocomplete. Empty q returns entities alphabetically.
|
|
15
|
+
app.get('/entities', async (req, reply) => {
|
|
16
|
+
const params = req.query;
|
|
17
|
+
const q = params.q ?? '';
|
|
18
|
+
const rawLimit = params.limit ? Number(params.limit) : 20;
|
|
19
|
+
const limit = Number.isFinite(rawLimit) ? Math.max(1, Math.min(100, rawLimit)) : 20;
|
|
20
|
+
const entityRepo = new EntityRepo(db);
|
|
21
|
+
const entities = entityRepo.search(q, limit);
|
|
22
|
+
return { entities };
|
|
23
|
+
});
|
|
24
|
+
// GET /entities/:id/memories — every memory currently linked to entity :id.
|
|
25
|
+
app.get('/entities/:id/memories', async (req, reply) => {
|
|
26
|
+
const { id } = req.params;
|
|
27
|
+
const entityRepo = new EntityRepo(db);
|
|
28
|
+
const entity = entityRepo.getById(id);
|
|
29
|
+
if (!entity) {
|
|
30
|
+
return reply.code(404).send({ error: 'not found', id });
|
|
31
|
+
}
|
|
32
|
+
const memRepo = new MemoryRepo(db);
|
|
33
|
+
const memoryIds = entityRepo.memoryIdsForEntities([id]);
|
|
34
|
+
// Currently-valid only (valid_to IS NULL — same semantics as
|
|
35
|
+
// validityFilterClause(undefined) in src/search/search.ts): a
|
|
36
|
+
// superseded/invalidated/archived memory is retired, not "currently
|
|
37
|
+
// linked" to the entity, even though the memory_entities row itself
|
|
38
|
+
// still points at it.
|
|
39
|
+
const memories = Array.from(memoryIds)
|
|
40
|
+
.map(mid => memRepo.get(mid))
|
|
41
|
+
.filter((m) => m !== null && m.valid_to === null);
|
|
42
|
+
return { entity, memories };
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=entities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entities.js","sourceRoot":"","sources":["../../../src/server/routes/entities.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAEvD,MAAM,UAAU,aAAa,CAAC,EAAM;IAClC,OAAO,KAAK,EAAE,GAAoB,EAAE,EAAE;QACpC,8EAA8E;QAC9E,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;YACxC,MAAM,MAAM,GAAG,GAAG,CAAC,KAA+B,CAAC;YACnD,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1D,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAEpF,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;YACtC,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;YAC7C,OAAO,EAAE,QAAQ,EAAE,CAAC;QACtB,CAAC,CAAC,CAAC;QAEH,4EAA4E;QAC5E,GAAG,CAAC,GAAG,CAAC,wBAAwB,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;YACrD,MAAM,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC,MAAwB,CAAC;YAC5C,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;YACtC,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACtC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;YAC1D,CAAC;YAED,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;YACnC,MAAM,SAAS,GAAG,UAAU,CAAC,oBAAoB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACxD,6DAA6D;YAC7D,8DAA8D;YAC9D,oEAAoE;YACpE,oEAAoE;YACpE,sBAAsB;YACtB,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;iBACnC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;iBAC5B,MAAM,CAAC,CAAC,CAAC,EAA8B,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC;YAEhF,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;QAC9B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { FastifyInstance } from 'fastify';
|
|
2
|
+
import { type Config } from '../../config/config.js';
|
|
3
|
+
import type { DB } from '../../storage/db.js';
|
|
4
|
+
import type { HealthState } from '../health-state.js';
|
|
5
|
+
/**
|
|
6
|
+
* db is optional so /health keeps working for any caller that doesn't wire a
|
|
7
|
+
* DB (defensive default) — the usefulness block degrades to zeros rather
|
|
8
|
+
* than 500ing.
|
|
9
|
+
*
|
|
10
|
+
* Wire compat: every pre-existing field is preserved and `ok` stays true
|
|
11
|
+
* whenever the daemon is reachable ("reachable and serving"). The additive
|
|
12
|
+
* `status` field carries the degraded-start signal (starting|ok|degraded).
|
|
13
|
+
*/
|
|
14
|
+
export declare function healthRoute(config?: Config, db?: DB, healthState?: HealthState): (app: FastifyInstance) => Promise<void>;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { PKG_VERSION, WIRE_VERSIONS_SUPPORTED, SCHEMA_VERSION } from '../lib/wire-meta.js';
|
|
2
|
+
import { defaultConfig } from '../../config/config.js';
|
|
3
|
+
import { usefulnessRate } from '../../storage/usefulness.js';
|
|
4
|
+
import { queryJobStates } from '../queries/dashboard.js';
|
|
5
|
+
import { statfsSync } from 'node:fs';
|
|
6
|
+
const SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000;
|
|
7
|
+
/**
|
|
8
|
+
* db is optional so /health keeps working for any caller that doesn't wire a
|
|
9
|
+
* DB (defensive default) — the usefulness block degrades to zeros rather
|
|
10
|
+
* than 500ing.
|
|
11
|
+
*
|
|
12
|
+
* Wire compat: every pre-existing field is preserved and `ok` stays true
|
|
13
|
+
* whenever the daemon is reachable ("reachable and serving"). The additive
|
|
14
|
+
* `status` field carries the degraded-start signal (starting|ok|degraded).
|
|
15
|
+
*/
|
|
16
|
+
export function healthRoute(config = defaultConfig(), db, healthState) {
|
|
17
|
+
return async (app) => {
|
|
18
|
+
app.get('/health', async () => {
|
|
19
|
+
const rate = db ? usefulnessRate(db, { sinceMs: Date.now() - SEVEN_DAYS_MS }) : { served: 0, used: 0, rate: null };
|
|
20
|
+
return {
|
|
21
|
+
ok: true,
|
|
22
|
+
version: PKG_VERSION,
|
|
23
|
+
wire_versions_supported: WIRE_VERSIONS_SUPPORTED,
|
|
24
|
+
schema_version: SCHEMA_VERSION,
|
|
25
|
+
security: {
|
|
26
|
+
redaction: config.security.redaction.enabled,
|
|
27
|
+
encryption: config.security.encryption.enabled,
|
|
28
|
+
},
|
|
29
|
+
// ADR-010: recall-usefulness rate (v1: measure only, does not feed ranking).
|
|
30
|
+
usefulness: {
|
|
31
|
+
served_7d: rate.served,
|
|
32
|
+
used_7d: rate.used,
|
|
33
|
+
rate_7d: rate.rate,
|
|
34
|
+
},
|
|
35
|
+
// Degraded-start (D3) + real health checks (P1.3) — additive only.
|
|
36
|
+
...(healthState
|
|
37
|
+
? {
|
|
38
|
+
status: healthState.status(),
|
|
39
|
+
uptime_s: healthState.uptimeSeconds(),
|
|
40
|
+
embed: {
|
|
41
|
+
ok: healthState.embed.ok,
|
|
42
|
+
last_ok_at: healthState.embed.lastOkAt,
|
|
43
|
+
last_error: healthState.embed.lastError,
|
|
44
|
+
attempts: healthState.embed.attempts,
|
|
45
|
+
},
|
|
46
|
+
worker: workerBlock(healthState),
|
|
47
|
+
...(db ? { queue: queueCounts(db), pending_proposals: pendingProposals(db) } : {}),
|
|
48
|
+
...(healthState.dataDir ? { disk_free_bytes: diskFree(healthState.dataDir) } : {}),
|
|
49
|
+
}
|
|
50
|
+
: {}),
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Generous liveness window: the worker stamps lastTickAt at tick START, so a
|
|
57
|
+
* single long-running job (LLM distill can take up to the 60s chat timeout)
|
|
58
|
+
* must not read as "worker dead". 90s covers the worst handler + margin.
|
|
59
|
+
*/
|
|
60
|
+
const WORKER_ALIVE_WINDOW_MS = 90_000;
|
|
61
|
+
function workerBlock(hs) {
|
|
62
|
+
const last = hs.worker.lastTickAt;
|
|
63
|
+
return {
|
|
64
|
+
alive: last !== null && Date.now() - last < WORKER_ALIVE_WINDOW_MS,
|
|
65
|
+
last_tick_at: last,
|
|
66
|
+
last_tick_ago_ms: last === null ? null : Date.now() - last,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/** FEAT-410 AC-2: delegates to the shared queryJobStates (queries/dashboard.ts)
|
|
70
|
+
* so /health and /dashboard compute job-state counts from one function. */
|
|
71
|
+
function queueCounts(db) {
|
|
72
|
+
try {
|
|
73
|
+
const rows = queryJobStates(db);
|
|
74
|
+
const out = {};
|
|
75
|
+
for (const r of rows)
|
|
76
|
+
out[r.state] = r.count;
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return {}; // jobs table absent (bare test DB) — degrade, never 500.
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function pendingProposals(db) {
|
|
84
|
+
try {
|
|
85
|
+
return db.prepare(`SELECT COUNT(*) AS n FROM consolidation_proposals WHERE status = 'pending'`).get().n;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return 0; // table absent (pre-008 schema in bare test DBs)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function diskFree(dataDir) {
|
|
92
|
+
try {
|
|
93
|
+
const s = statfsSync(dataDir);
|
|
94
|
+
return s.bavail * s.bsize;
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../../src/server/routes/health.ts"],"names":[],"mappings":"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"}
|