nlm-memory 0.4.0
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/.agents/plugins/marketplace.json +20 -0
- package/.github/workflows/ci.yml +30 -0
- package/LICENSE +151 -0
- package/README.md +119 -0
- package/dist/cli/classify-parity.d.ts +48 -0
- package/dist/cli/classify-parity.js +182 -0
- package/dist/cli/classify-parity.js.map +1 -0
- package/dist/cli/launchctl-helpers.d.ts +26 -0
- package/dist/cli/launchctl-helpers.js +42 -0
- package/dist/cli/launchctl-helpers.js.map +1 -0
- package/dist/cli/nlm.d.ts +25 -0
- package/dist/cli/nlm.js +832 -0
- package/dist/cli/nlm.js.map +1 -0
- package/dist/core/actions/actions-log.d.ts +40 -0
- package/dist/core/actions/actions-log.js +72 -0
- package/dist/core/actions/actions-log.js.map +1 -0
- package/dist/core/actions/overlay.d.ts +30 -0
- package/dist/core/actions/overlay.js +101 -0
- package/dist/core/actions/overlay.js.map +1 -0
- package/dist/core/adapters/aider.d.ts +33 -0
- package/dist/core/adapters/aider.js +167 -0
- package/dist/core/adapters/aider.js.map +1 -0
- package/dist/core/adapters/claude-code.d.ts +32 -0
- package/dist/core/adapters/claude-code.js +270 -0
- package/dist/core/adapters/claude-code.js.map +1 -0
- package/dist/core/adapters/common.d.ts +20 -0
- package/dist/core/adapters/common.js +60 -0
- package/dist/core/adapters/common.js.map +1 -0
- package/dist/core/adapters/from-source.d.ts +11 -0
- package/dist/core/adapters/from-source.js +55 -0
- package/dist/core/adapters/from-source.js.map +1 -0
- package/dist/core/adapters/hermes-agent.d.ts +34 -0
- package/dist/core/adapters/hermes-agent.js +192 -0
- package/dist/core/adapters/hermes-agent.js.map +1 -0
- package/dist/core/adapters/hermes.d.ts +31 -0
- package/dist/core/adapters/hermes.js +247 -0
- package/dist/core/adapters/hermes.js.map +1 -0
- package/dist/core/adapters/jsonl-generic.d.ts +56 -0
- package/dist/core/adapters/jsonl-generic.js +185 -0
- package/dist/core/adapters/jsonl-generic.js.map +1 -0
- package/dist/core/adapters/opencode.d.ts +36 -0
- package/dist/core/adapters/opencode.js +213 -0
- package/dist/core/adapters/opencode.js.map +1 -0
- package/dist/core/adapters/pi.d.ts +32 -0
- package/dist/core/adapters/pi.js +233 -0
- package/dist/core/adapters/pi.js.map +1 -0
- package/dist/core/classifier/prompt.d.ts +60 -0
- package/dist/core/classifier/prompt.js +178 -0
- package/dist/core/classifier/prompt.js.map +1 -0
- package/dist/core/dataset/build-dataset.d.ts +87 -0
- package/dist/core/dataset/build-dataset.js +335 -0
- package/dist/core/dataset/build-dataset.js.map +1 -0
- package/dist/core/embedding/chunk-body.d.ts +30 -0
- package/dist/core/embedding/chunk-body.js +60 -0
- package/dist/core/embedding/chunk-body.js.map +1 -0
- package/dist/core/embedding/embed-backfill.d.ts +36 -0
- package/dist/core/embedding/embed-backfill.js +168 -0
- package/dist/core/embedding/embed-backfill.js.map +1 -0
- package/dist/core/embedding/embed-normalize.d.ts +28 -0
- package/dist/core/embedding/embed-normalize.js +98 -0
- package/dist/core/embedding/embed-normalize.js.map +1 -0
- package/dist/core/facts/backfill-facts.d.ts +58 -0
- package/dist/core/facts/backfill-facts.js +169 -0
- package/dist/core/facts/backfill-facts.js.map +1 -0
- package/dist/core/facts/extract-facts.d.ts +20 -0
- package/dist/core/facts/extract-facts.js +37 -0
- package/dist/core/facts/extract-facts.js.map +1 -0
- package/dist/core/hook/citation-detect.d.ts +32 -0
- package/dist/core/hook/citation-detect.js +105 -0
- package/dist/core/hook/citation-detect.js.map +1 -0
- package/dist/core/hook/cite-memo.d.ts +20 -0
- package/dist/core/hook/cite-memo.js +68 -0
- package/dist/core/hook/cite-memo.js.map +1 -0
- package/dist/core/hook/claude-settings.d.ts +34 -0
- package/dist/core/hook/claude-settings.js +117 -0
- package/dist/core/hook/claude-settings.js.map +1 -0
- package/dist/core/hook/gate.d.ts +11 -0
- package/dist/core/hook/gate.js +19 -0
- package/dist/core/hook/gate.js.map +1 -0
- package/dist/core/hook/hook-log.d.ts +25 -0
- package/dist/core/hook/hook-log.js +28 -0
- package/dist/core/hook/hook-log.js.map +1 -0
- package/dist/core/hook/memo-sweep.d.ts +55 -0
- package/dist/core/hook/memo-sweep.js +134 -0
- package/dist/core/hook/memo-sweep.js.map +1 -0
- package/dist/core/hook/memo.d.ts +20 -0
- package/dist/core/hook/memo.js +66 -0
- package/dist/core/hook/memo.js.map +1 -0
- package/dist/core/hook/pointer-block.d.ts +14 -0
- package/dist/core/hook/pointer-block.js +19 -0
- package/dist/core/hook/pointer-block.js.map +1 -0
- package/dist/core/hook/select.d.ts +21 -0
- package/dist/core/hook/select.js +15 -0
- package/dist/core/hook/select.js.map +1 -0
- package/dist/core/hook/transcript.d.ts +31 -0
- package/dist/core/hook/transcript.js +103 -0
- package/dist/core/hook/transcript.js.map +1 -0
- package/dist/core/ingest/ingest-session.d.ts +40 -0
- package/dist/core/ingest/ingest-session.js +71 -0
- package/dist/core/ingest/ingest-session.js.map +1 -0
- package/dist/core/providers/provider-models.d.ts +24 -0
- package/dist/core/providers/provider-models.js +72 -0
- package/dist/core/providers/provider-models.js.map +1 -0
- package/dist/core/providers/provider-registry.d.ts +62 -0
- package/dist/core/providers/provider-registry.js +143 -0
- package/dist/core/providers/provider-registry.js.map +1 -0
- package/dist/core/recall/citation-log.d.ts +28 -0
- package/dist/core/recall/citation-log.js +90 -0
- package/dist/core/recall/citation-log.js.map +1 -0
- package/dist/core/recall/filter.d.ts +11 -0
- package/dist/core/recall/filter.js +20 -0
- package/dist/core/recall/filter.js.map +1 -0
- package/dist/core/recall/index.d.ts +6 -0
- package/dist/core/recall/index.js +5 -0
- package/dist/core/recall/index.js.map +1 -0
- package/dist/core/recall/match-fields.d.ts +10 -0
- package/dist/core/recall/match-fields.js +37 -0
- package/dist/core/recall/match-fields.js.map +1 -0
- package/dist/core/recall/query-log.d.ts +36 -0
- package/dist/core/recall/query-log.js +112 -0
- package/dist/core/recall/query-log.js.map +1 -0
- package/dist/core/recall/query-shape.d.ts +22 -0
- package/dist/core/recall/query-shape.js +64 -0
- package/dist/core/recall/query-shape.js.map +1 -0
- package/dist/core/recall/recall-service.d.ts +19 -0
- package/dist/core/recall/recall-service.js +252 -0
- package/dist/core/recall/recall-service.js.map +1 -0
- package/dist/core/recall/recent-log.d.ts +16 -0
- package/dist/core/recall/recent-log.js +46 -0
- package/dist/core/recall/recent-log.js.map +1 -0
- package/dist/core/recall/tokenize.d.ts +7 -0
- package/dist/core/recall/tokenize.js +18 -0
- package/dist/core/recall/tokenize.js.map +1 -0
- package/dist/core/recall/useful-scan.d.ts +52 -0
- package/dist/core/recall/useful-scan.js +300 -0
- package/dist/core/recall/useful-scan.js.map +1 -0
- package/dist/core/recall-facts/fact-query-log.d.ts +42 -0
- package/dist/core/recall-facts/fact-query-log.js +115 -0
- package/dist/core/recall-facts/fact-query-log.js.map +1 -0
- package/dist/core/recall-facts/fact-recall-service.d.ts +34 -0
- package/dist/core/recall-facts/fact-recall-service.js +246 -0
- package/dist/core/recall-facts/fact-recall-service.js.map +1 -0
- package/dist/core/scheduler/scan-once.d.ts +32 -0
- package/dist/core/scheduler/scan-once.js +100 -0
- package/dist/core/scheduler/scan-once.js.map +1 -0
- package/dist/core/scheduler/scheduler.d.ts +59 -0
- package/dist/core/scheduler/scheduler.js +158 -0
- package/dist/core/scheduler/scheduler.js.map +1 -0
- package/dist/core/sources/source-registry.d.ts +68 -0
- package/dist/core/sources/source-registry.js +208 -0
- package/dist/core/sources/source-registry.js.map +1 -0
- package/dist/core/storage/db-restore.d.ts +53 -0
- package/dist/core/storage/db-restore.js +113 -0
- package/dist/core/storage/db-restore.js.map +1 -0
- package/dist/core/storage/live-status.d.ts +15 -0
- package/dist/core/storage/live-status.js +43 -0
- package/dist/core/storage/live-status.js.map +1 -0
- package/dist/core/storage/migrate.d.ts +14 -0
- package/dist/core/storage/migrate.js +52 -0
- package/dist/core/storage/migrate.js.map +1 -0
- package/dist/core/storage/sqlite-fact-store.d.ts +50 -0
- package/dist/core/storage/sqlite-fact-store.js +256 -0
- package/dist/core/storage/sqlite-fact-store.js.map +1 -0
- package/dist/core/storage/sqlite-session-store.d.ts +152 -0
- package/dist/core/storage/sqlite-session-store.js +587 -0
- package/dist/core/storage/sqlite-session-store.js.map +1 -0
- package/dist/hook/pre-compact-hook.d.ts +26 -0
- package/dist/hook/pre-compact-hook.js +94 -0
- package/dist/hook/pre-compact-hook.js.map +1 -0
- package/dist/hook/prompt-recall-hook.d.ts +23 -0
- package/dist/hook/prompt-recall-hook.js +141 -0
- package/dist/hook/prompt-recall-hook.js.map +1 -0
- package/dist/hook/session-end-hook.d.ts +18 -0
- package/dist/hook/session-end-hook.js +67 -0
- package/dist/hook/session-end-hook.js.map +1 -0
- package/dist/hook/session-start-hook.d.ts +25 -0
- package/dist/hook/session-start-hook.js +129 -0
- package/dist/hook/session-start-hook.js.map +1 -0
- package/dist/hook/stop-hook.d.ts +38 -0
- package/dist/hook/stop-hook.js +171 -0
- package/dist/hook/stop-hook.js.map +1 -0
- package/dist/hook/subagent-start-hook.d.ts +30 -0
- package/dist/hook/subagent-start-hook.js +108 -0
- package/dist/hook/subagent-start-hook.js.map +1 -0
- package/dist/http/app.d.ts +65 -0
- package/dist/http/app.js +1009 -0
- package/dist/http/app.js.map +1 -0
- package/dist/install/claude-code.d.ts +57 -0
- package/dist/install/claude-code.js +76 -0
- package/dist/install/claude-code.js.map +1 -0
- package/dist/install/codex.d.ts +82 -0
- package/dist/install/codex.js +277 -0
- package/dist/install/codex.js.map +1 -0
- package/dist/install/hermes-agent.d.ts +35 -0
- package/dist/install/hermes-agent.js +48 -0
- package/dist/install/hermes-agent.js.map +1 -0
- package/dist/install/hermes.d.ts +29 -0
- package/dist/install/hermes.js +52 -0
- package/dist/install/hermes.js.map +1 -0
- package/dist/install/ollama.d.ts +54 -0
- package/dist/install/ollama.js +178 -0
- package/dist/install/ollama.js.map +1 -0
- package/dist/install/setup.d.ts +37 -0
- package/dist/install/setup.js +339 -0
- package/dist/install/setup.js.map +1 -0
- package/dist/llm/classifier-box.d.ts +29 -0
- package/dist/llm/classifier-box.js +43 -0
- package/dist/llm/classifier-box.js.map +1 -0
- package/dist/llm/deepseek-client.d.ts +40 -0
- package/dist/llm/deepseek-client.js +114 -0
- package/dist/llm/deepseek-client.js.map +1 -0
- package/dist/llm/env-autoload.d.ts +8 -0
- package/dist/llm/env-autoload.js +54 -0
- package/dist/llm/env-autoload.js.map +1 -0
- package/dist/llm/ollama-client.d.ts +47 -0
- package/dist/llm/ollama-client.js +156 -0
- package/dist/llm/ollama-client.js.map +1 -0
- package/dist/mcp/server.d.ts +64 -0
- package/dist/mcp/server.js +430 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/ports/fact-store.d.ts +82 -0
- package/dist/ports/fact-store.js +16 -0
- package/dist/ports/fact-store.js.map +1 -0
- package/dist/ports/llm-client.d.ts +42 -0
- package/dist/ports/llm-client.js +14 -0
- package/dist/ports/llm-client.js.map +1 -0
- package/dist/ports/logger.d.ts +13 -0
- package/dist/ports/logger.js +8 -0
- package/dist/ports/logger.js.map +1 -0
- package/dist/ports/session-store.d.ts +29 -0
- package/dist/ports/session-store.js +9 -0
- package/dist/ports/session-store.js.map +1 -0
- package/dist/ports/transcript-adapter.d.ts +48 -0
- package/dist/ports/transcript-adapter.js +15 -0
- package/dist/ports/transcript-adapter.js.map +1 -0
- package/dist/shared/types.d.ts +129 -0
- package/dist/shared/types.js +6 -0
- package/dist/shared/types.js.map +1 -0
- package/dist/ui/assets/index-BA6IpU8g.css +1 -0
- package/dist/ui/assets/index-B_qIVV0k.js +69 -0
- package/dist/ui/index.html +13 -0
- package/docs/methodology/re-derivation-rate.md +112 -0
- package/docs/methodology/useful-hit-rate.md +79 -0
- package/docs/plans/2026-05-20-fts5-lexical-recall.md +1088 -0
- package/docs/plans/2026-05-20-recall-daemon-wedge-fix.md +662 -0
- package/docs/plans/2026-05-20-recall-hook-design.md +131 -0
- package/docs/plans/2026-05-20-recall-hook-implementation.md +1222 -0
- package/docs/plans/desktop-product.md +69 -0
- package/docs/plans/factstore-design.md +236 -0
- package/logs/CHANGELOG/CHANGELOG-2026.md +1389 -0
- package/logs/CHANGELOG/CHANGELOG.md +320 -0
- package/migrations/000_initial_schema.sql +174 -0
- package/migrations/001_entity_type_rename.sql +17 -0
- package/migrations/002_adapter_state_extend.sql +12 -0
- package/migrations/003_session_embeddings.sql +11 -0
- package/migrations/004_facts.sql +46 -0
- package/migrations/005_sources.sql +31 -0
- package/migrations/006_providers.sql +33 -0
- package/migrations/007_source_tokens.sql +17 -0
- package/migrations/008_fts_rebuild.sql +9 -0
- package/migrations/009_session_embedding_chunks.sql +46 -0
- package/migrations/010_sources_opencode.sql +30 -0
- package/migrations/011_sources_hermes_agent.sql +30 -0
- package/migrations/012_sources_aider.sql +30 -0
- package/migrations/013_adapter_state_failure_count.sql +12 -0
- package/package.json +56 -0
- package/plugin/.codex-plugin/plugin.json +22 -0
- package/plugin/.mcp.json +8 -0
- package/plugin/README.md +51 -0
- package/plugin/hooks/hooks.json +25 -0
- package/plugin/scripts/prompt-recall-hook.mjs +202 -0
- package/plugin/scripts/stop-hook.mjs +306 -0
- package/plugin-hermes-agent/README.md +49 -0
- package/plugin-hermes-agent/__init__.py +75 -0
- package/plugin-hermes-agent/plugin.yaml +15 -0
- package/scripts/backfill-citations.mjs +0 -0
- package/scripts/build-codex-plugin.mjs +61 -0
- package/scripts/deepseek-probe.mjs +67 -0
- package/scripts/extract-triples.mjs +207 -0
- package/scripts/longmemeval/embedding-cache.ts +77 -0
- package/scripts/longmemeval/fetch-dataset.sh +25 -0
- package/scripts/longmemeval/run-harness.ts +315 -0
- package/scripts/longmemeval/scorer.ts +99 -0
- package/scripts/longmemeval/tsconfig.json +9 -0
- package/scripts/longmemeval/types.ts +35 -0
- package/scripts/nlm-daily-digest.py +239 -0
- package/scripts/nlm-daily-digest.sh +28 -0
- package/src/cli/classify-parity.ts +257 -0
- package/src/cli/launchctl-helpers.ts +49 -0
- package/src/cli/nlm.ts +885 -0
- package/src/core/actions/actions-log.ts +118 -0
- package/src/core/actions/overlay.ts +117 -0
- package/src/core/adapters/aider.ts +205 -0
- package/src/core/adapters/claude-code.ts +293 -0
- package/src/core/adapters/common.ts +54 -0
- package/src/core/adapters/from-source.ts +57 -0
- package/src/core/adapters/hermes-agent.ts +240 -0
- package/src/core/adapters/hermes.ts +277 -0
- package/src/core/adapters/jsonl-generic.ts +208 -0
- package/src/core/adapters/opencode.ts +281 -0
- package/src/core/adapters/pi.ts +264 -0
- package/src/core/classifier/prompt.ts +200 -0
- package/src/core/dataset/build-dataset.ts +463 -0
- package/src/core/embedding/chunk-body.ts +76 -0
- package/src/core/embedding/embed-backfill.ts +210 -0
- package/src/core/embedding/embed-normalize.ts +135 -0
- package/src/core/facts/backfill-facts.ts +254 -0
- package/src/core/facts/extract-facts.ts +50 -0
- package/src/core/hook/citation-detect.ts +124 -0
- package/src/core/hook/cite-memo.ts +68 -0
- package/src/core/hook/claude-settings.ts +166 -0
- package/src/core/hook/gate.ts +25 -0
- package/src/core/hook/hook-log.ts +41 -0
- package/src/core/hook/memo-sweep.ts +164 -0
- package/src/core/hook/memo.ts +67 -0
- package/src/core/hook/pointer-block.ts +26 -0
- package/src/core/hook/select.ts +32 -0
- package/src/core/hook/transcript.ts +121 -0
- package/src/core/ingest/ingest-session.ts +111 -0
- package/src/core/providers/provider-models.ts +100 -0
- package/src/core/providers/provider-registry.ts +196 -0
- package/src/core/recall/citation-log.ts +108 -0
- package/src/core/recall/filter.ts +27 -0
- package/src/core/recall/index.ts +6 -0
- package/src/core/recall/match-fields.ts +40 -0
- package/src/core/recall/query-log.ts +149 -0
- package/src/core/recall/query-shape.ts +66 -0
- package/src/core/recall/recall-service.ts +320 -0
- package/src/core/recall/recent-log.ts +59 -0
- package/src/core/recall/tokenize.ts +18 -0
- package/src/core/recall/useful-scan.ts +336 -0
- package/src/core/recall-facts/fact-query-log.ts +150 -0
- package/src/core/recall-facts/fact-recall-service.ts +327 -0
- package/src/core/scheduler/scan-once.ts +142 -0
- package/src/core/scheduler/scheduler.ts +225 -0
- package/src/core/sources/source-registry.ts +260 -0
- package/src/core/storage/db-restore.ts +133 -0
- package/src/core/storage/live-status.ts +45 -0
- package/src/core/storage/migrate.ts +72 -0
- package/src/core/storage/sqlite-fact-store.ts +304 -0
- package/src/core/storage/sqlite-session-store.ts +765 -0
- package/src/hook/prompt-recall-hook.ts +174 -0
- package/src/hook/session-end-hook.ts +81 -0
- package/src/hook/session-start-hook.ts +165 -0
- package/src/hook/stop-hook.ts +236 -0
- package/src/http/app.ts +1114 -0
- package/src/install/claude-code.ts +128 -0
- package/src/install/codex.ts +367 -0
- package/src/install/hermes-agent.ts +76 -0
- package/src/install/hermes.ts +78 -0
- package/src/install/ollama.ts +208 -0
- package/src/install/setup.ts +368 -0
- package/src/llm/classifier-box.ts +64 -0
- package/src/llm/deepseek-client.ts +150 -0
- package/src/llm/env-autoload.ts +55 -0
- package/src/llm/ollama-client.ts +189 -0
- package/src/mcp/server.ts +534 -0
- package/src/ports/fact-store.ts +102 -0
- package/src/ports/llm-client.ts +52 -0
- package/src/ports/logger.ts +16 -0
- package/src/ports/session-store.ts +45 -0
- package/src/ports/transcript-adapter.ts +55 -0
- package/src/shared/types.ts +145 -0
- package/src/ui/App.tsx +58 -0
- package/src/ui/components/PromoteOpenButton.tsx +65 -0
- package/src/ui/components/SessionDrawer.tsx +136 -0
- package/src/ui/components/SideNav.tsx +162 -0
- package/src/ui/components/Skeleton.tsx +107 -0
- package/src/ui/index.html +13 -0
- package/src/ui/lib/actions.ts +30 -0
- package/src/ui/lib/api.ts +92 -0
- package/src/ui/lib/dataset.ts +141 -0
- package/src/ui/lib/registries.ts +155 -0
- package/src/ui/lib/view-settings.ts +41 -0
- package/src/ui/main.tsx +15 -0
- package/src/ui/pages/Live.tsx +229 -0
- package/src/ui/pages/Pulse.tsx +415 -0
- package/src/ui/pages/Recall.tsx +190 -0
- package/src/ui/pages/River.tsx +308 -0
- package/src/ui/pages/Search.tsx +93 -0
- package/src/ui/pages/Stub.tsx +9 -0
- package/src/ui/pages/Thread.tsx +262 -0
- package/src/ui/pages/settings/Classifier.tsx +227 -0
- package/src/ui/pages/settings/Data.tsx +190 -0
- package/src/ui/pages/settings/Index.tsx +65 -0
- package/src/ui/pages/settings/Labels.tsx +224 -0
- package/src/ui/pages/settings/Providers.tsx +305 -0
- package/src/ui/pages/settings/SettingsSubnav.tsx +28 -0
- package/src/ui/pages/settings/Sources.tsx +326 -0
- package/src/ui/pages/settings/Views.tsx +96 -0
- package/src/ui/styles.css +1766 -0
- package/src/ui/tsconfig.json +21 -0
- package/src/ui/vite.config.ts +19 -0
- package/tests/fixtures/claude_code/short_session.jsonl +2 -0
- package/tests/fixtures/claude_code/standard_iso.jsonl +4 -0
- package/tests/fixtures/claude_code/tool_heavy.jsonl +8 -0
- package/tests/fixtures/claude_code/with_subagent.jsonl +7 -0
- package/tests/fixtures/facts.ts +17 -0
- package/tests/fixtures/golden-corpus.ts +85 -0
- package/tests/fixtures/hermes/paired_request_dump.json +24 -0
- package/tests/fixtures/hermes/paired_session.json +23 -0
- package/tests/fixtures/hermes/request_dump.json +28 -0
- package/tests/fixtures/hermes/session_iso.json +38 -0
- package/tests/fixtures/hermes/session_unix.json +38 -0
- package/tests/fixtures/hermes/system_only.json +18 -0
- package/tests/fixtures/pi/error-connection-abort.jsonl +8 -0
- package/tests/fixtures/pi/short-successful.jsonl +5 -0
- package/tests/fixtures/pi/with-custom-message.jsonl +6 -0
- package/tests/fixtures/sessions.ts +22 -0
- package/tests/integration/backfill-facts.test.ts +362 -0
- package/tests/integration/citation-explicit.test.ts +111 -0
- package/tests/integration/cite-event.test.ts +169 -0
- package/tests/integration/cite-memo.test.ts +87 -0
- package/tests/integration/db-restore.test.ts +153 -0
- package/tests/integration/embed-backfill.test.ts +176 -0
- package/tests/integration/fact-supersedence.test.ts +313 -0
- package/tests/integration/fts-index.test.ts +60 -0
- package/tests/integration/getbyids-sqlite.test.ts +60 -0
- package/tests/integration/hermes-agent-hooks.test.ts +248 -0
- package/tests/integration/hook-claude-settings.test.ts +205 -0
- package/tests/integration/hook-log.test.ts +54 -0
- package/tests/integration/hook-memo.test.ts +68 -0
- package/tests/integration/hook-pre-compact.test.ts +105 -0
- package/tests/integration/hook-subagent-start.test.ts +102 -0
- package/tests/integration/http.test.ts +401 -0
- package/tests/integration/keyword-search-fts.test.ts +66 -0
- package/tests/integration/mcp-recall-logging.test.ts +88 -0
- package/tests/integration/mcp.test.ts +248 -0
- package/tests/integration/memo-sweep.test.ts +91 -0
- package/tests/integration/prompt-recall-hook.test.ts +88 -0
- package/tests/integration/provider-registry.test.ts +107 -0
- package/tests/integration/recall-golden.test.ts +59 -0
- package/tests/integration/recall-sqlite.test.ts +169 -0
- package/tests/integration/scheduler.test.ts +391 -0
- package/tests/integration/session-end-hook.test.ts +48 -0
- package/tests/integration/session-start-hook.test.ts +126 -0
- package/tests/integration/source-registry.test.ts +120 -0
- package/tests/integration/sqlite-fact-store.test.ts +346 -0
- package/tests/integration/stop-hook.test.ts +560 -0
- package/tests/integration/wal-checkpoint.test.ts +49 -0
- package/tests/unit/cli/launchctl-helpers.test.ts +60 -0
- package/tests/unit/core/adapters/aider.test.ts +230 -0
- package/tests/unit/core/adapters/claude-code.test.ts +118 -0
- package/tests/unit/core/adapters/hermes-agent.test.ts +329 -0
- package/tests/unit/core/adapters/hermes.test.ts +81 -0
- package/tests/unit/core/adapters/jsonl-generic.test.ts +142 -0
- package/tests/unit/core/adapters/opencode.test.ts +354 -0
- package/tests/unit/core/adapters/pi.test.ts +110 -0
- package/tests/unit/core/classifier/prompt.test.ts +126 -0
- package/tests/unit/core/embedding/chunk-body.test.ts +100 -0
- package/tests/unit/core/facts/extract-facts.test.ts +117 -0
- package/tests/unit/core/filter.test.ts +40 -0
- package/tests/unit/core/hook/citation-detect-cite-session.test.ts +96 -0
- package/tests/unit/core/hook/citation-detect.test.ts +124 -0
- package/tests/unit/core/hook/gate.test.ts +29 -0
- package/tests/unit/core/hook/pointer-block.test.ts +22 -0
- package/tests/unit/core/hook/select.test.ts +66 -0
- package/tests/unit/core/match-fields.test.ts +39 -0
- package/tests/unit/core/mcp-cite-session.test.ts +51 -0
- package/tests/unit/core/providers/provider-models.test.ts +101 -0
- package/tests/unit/core/query-shape.test.ts +92 -0
- package/tests/unit/core/recall-facts/fact-recall-service.test.ts +258 -0
- package/tests/unit/core/recall-service.test.ts +200 -0
- package/tests/unit/core/storage/live-status.test.ts +54 -0
- package/tests/unit/core/tokenize.test.ts +32 -0
- package/tests/unit/core/useful-scan.test.ts +537 -0
- package/tests/unit/llm/embed.test.ts +93 -0
- package/tests/unit/llm/ollama-client.test.ts +124 -0
- package/tests/unit/scripts/longmemeval-scorer.test.ts +114 -0
- package/tsconfig.json +31 -0
- package/tsconfig.test.json +11 -0
- package/vitest.config.ts +22 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SqliteFactStore — the canonical FactStore implementation, sharing the same
|
|
3
|
+
* better-sqlite3 connection as SqliteSessionStore so session+facts ingest can
|
|
4
|
+
* commit in one transaction (Section 5 of factstore-design.md).
|
|
5
|
+
*
|
|
6
|
+
* Constructor takes an already-opened, already-migrated Database handle from
|
|
7
|
+
* SqliteSessionStore.rawDb(). It does not open its own connection. This is
|
|
8
|
+
* the only way to get a single-writer SQLite to behave atomically across
|
|
9
|
+
* both stores without WAL ordering surprises.
|
|
10
|
+
*
|
|
11
|
+
* Surface evolution:
|
|
12
|
+
* B.1 — insert, getById, findCurrent, list, listBySession, markSuperseded
|
|
13
|
+
* B.2 — insertManyInTxn (atomic session+facts ingest), embedding write helper
|
|
14
|
+
* B.3 — listForRecall (pre-filter for FactRecallService), semanticSearch,
|
|
15
|
+
* getHistory (supersedence chain inspection)
|
|
16
|
+
* B.4 — auto-supersedence on (subject, predicate) collision (deferred)
|
|
17
|
+
*/
|
|
18
|
+
export class SqliteFactStore {
|
|
19
|
+
db;
|
|
20
|
+
constructor(db) {
|
|
21
|
+
this.db = db;
|
|
22
|
+
}
|
|
23
|
+
async insert(fact) {
|
|
24
|
+
this.insertStmt().run(this.toRow(fact));
|
|
25
|
+
}
|
|
26
|
+
async insertMany(facts) {
|
|
27
|
+
if (facts.length === 0)
|
|
28
|
+
return;
|
|
29
|
+
const stmt = this.insertStmt();
|
|
30
|
+
const txn = this.db.transaction((rows) => {
|
|
31
|
+
for (const row of rows)
|
|
32
|
+
stmt.run(row);
|
|
33
|
+
});
|
|
34
|
+
txn(facts.map((f) => this.toRow(f)));
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Insert facts inside an already-open transaction (no own txn opened).
|
|
38
|
+
* Callable only from code that has already begun a transaction on the same
|
|
39
|
+
* connection — currently SqliteSessionStore.insertSession. Phase B.2: this
|
|
40
|
+
* is how session+facts ingest commits atomically (Section 5 of the plan).
|
|
41
|
+
*/
|
|
42
|
+
insertManyInTxn(facts) {
|
|
43
|
+
if (facts.length === 0)
|
|
44
|
+
return;
|
|
45
|
+
const stmt = this.insertStmt();
|
|
46
|
+
for (const f of facts)
|
|
47
|
+
stmt.run(this.toRow(f));
|
|
48
|
+
}
|
|
49
|
+
async getById(id) {
|
|
50
|
+
const row = this.db
|
|
51
|
+
.prepare(`SELECT id, kind, subject, predicate, value, source_session_id,
|
|
52
|
+
source_quote, created_at, superseded_by, confidence
|
|
53
|
+
FROM facts WHERE id = ?`)
|
|
54
|
+
.get(id);
|
|
55
|
+
return row ? this.rowToFact(row) : null;
|
|
56
|
+
}
|
|
57
|
+
async findCurrent(subject, predicate) {
|
|
58
|
+
const row = this.db
|
|
59
|
+
.prepare(`SELECT id, kind, subject, predicate, value, source_session_id,
|
|
60
|
+
source_quote, created_at, superseded_by, confidence
|
|
61
|
+
FROM facts
|
|
62
|
+
WHERE subject = ? AND predicate = ? AND superseded_by IS NULL
|
|
63
|
+
ORDER BY created_at DESC
|
|
64
|
+
LIMIT 1`)
|
|
65
|
+
.get(subject, predicate);
|
|
66
|
+
return row ? this.rowToFact(row) : null;
|
|
67
|
+
}
|
|
68
|
+
async list(query) {
|
|
69
|
+
const limit = Math.max(1, Math.trunc(query.limit ?? 50));
|
|
70
|
+
const includeSuperseded = query.includeSuperseded === true;
|
|
71
|
+
const where = ["subject = ?"];
|
|
72
|
+
const params = [query.subject];
|
|
73
|
+
if (query.predicate !== undefined) {
|
|
74
|
+
where.push("predicate = ?");
|
|
75
|
+
params.push(query.predicate);
|
|
76
|
+
}
|
|
77
|
+
if (!includeSuperseded)
|
|
78
|
+
where.push("superseded_by IS NULL");
|
|
79
|
+
params.push(limit);
|
|
80
|
+
const rows = this.db
|
|
81
|
+
.prepare(`SELECT id, kind, subject, predicate, value, source_session_id,
|
|
82
|
+
source_quote, created_at, superseded_by, confidence
|
|
83
|
+
FROM facts
|
|
84
|
+
WHERE ${where.join(" AND ")}
|
|
85
|
+
ORDER BY created_at DESC
|
|
86
|
+
LIMIT ?`)
|
|
87
|
+
.all(...params);
|
|
88
|
+
return rows.map((r) => this.rowToFact(r));
|
|
89
|
+
}
|
|
90
|
+
async listBySession(sessionId) {
|
|
91
|
+
const rows = this.db
|
|
92
|
+
.prepare(`SELECT id, kind, subject, predicate, value, source_session_id,
|
|
93
|
+
source_quote, created_at, superseded_by, confidence
|
|
94
|
+
FROM facts
|
|
95
|
+
WHERE source_session_id = ?
|
|
96
|
+
ORDER BY created_at ASC`)
|
|
97
|
+
.all(sessionId);
|
|
98
|
+
return rows.map((r) => this.rowToFact(r));
|
|
99
|
+
}
|
|
100
|
+
async listForRecall(filter) {
|
|
101
|
+
const where = [];
|
|
102
|
+
const params = [];
|
|
103
|
+
if (filter.subject !== undefined) {
|
|
104
|
+
where.push("subject = ?");
|
|
105
|
+
params.push(filter.subject);
|
|
106
|
+
}
|
|
107
|
+
if (filter.predicate !== undefined) {
|
|
108
|
+
where.push("predicate = ?");
|
|
109
|
+
params.push(filter.predicate);
|
|
110
|
+
}
|
|
111
|
+
if (filter.kind !== undefined) {
|
|
112
|
+
where.push("kind = ?");
|
|
113
|
+
params.push(filter.kind);
|
|
114
|
+
}
|
|
115
|
+
if (filter.minConfidence !== undefined) {
|
|
116
|
+
where.push("confidence >= ?");
|
|
117
|
+
params.push(filter.minConfidence);
|
|
118
|
+
}
|
|
119
|
+
if (filter.includeSuperseded !== true) {
|
|
120
|
+
where.push("superseded_by IS NULL");
|
|
121
|
+
}
|
|
122
|
+
const limit = Math.max(1, Math.trunc(filter.limit ?? 500));
|
|
123
|
+
params.push(limit);
|
|
124
|
+
const sql = `
|
|
125
|
+
SELECT id, kind, subject, predicate, value, source_session_id,
|
|
126
|
+
source_quote, created_at, superseded_by, confidence
|
|
127
|
+
FROM facts
|
|
128
|
+
${where.length > 0 ? "WHERE " + where.join(" AND ") : ""}
|
|
129
|
+
ORDER BY created_at DESC
|
|
130
|
+
LIMIT ?
|
|
131
|
+
`;
|
|
132
|
+
const rows = this.db
|
|
133
|
+
.prepare(sql)
|
|
134
|
+
.all(...params);
|
|
135
|
+
return rows.map((r) => this.rowToFact(r));
|
|
136
|
+
}
|
|
137
|
+
async semanticSearch(queryVector, limit) {
|
|
138
|
+
const k = Math.max(1, Math.trunc(limit));
|
|
139
|
+
const blob = Buffer.from(queryVector.buffer, queryVector.byteOffset, queryVector.byteLength);
|
|
140
|
+
const rows = this.db
|
|
141
|
+
.prepare(`
|
|
142
|
+
SELECT fact_id, distance
|
|
143
|
+
FROM fact_embeddings
|
|
144
|
+
WHERE embedding MATCH ?
|
|
145
|
+
AND k = ?
|
|
146
|
+
ORDER BY distance
|
|
147
|
+
`)
|
|
148
|
+
.all(blob, k);
|
|
149
|
+
return rows.map((r) => ({ factId: r.fact_id, distance: r.distance }));
|
|
150
|
+
}
|
|
151
|
+
async getHistory(subject, predicate) {
|
|
152
|
+
const sql = predicate
|
|
153
|
+
? `SELECT id, kind, subject, predicate, value, source_session_id,
|
|
154
|
+
source_quote, created_at, superseded_by, confidence
|
|
155
|
+
FROM facts
|
|
156
|
+
WHERE subject = ? AND predicate = ?
|
|
157
|
+
ORDER BY predicate ASC, created_at DESC`
|
|
158
|
+
: `SELECT id, kind, subject, predicate, value, source_session_id,
|
|
159
|
+
source_quote, created_at, superseded_by, confidence
|
|
160
|
+
FROM facts
|
|
161
|
+
WHERE subject = ?
|
|
162
|
+
ORDER BY predicate ASC, created_at DESC`;
|
|
163
|
+
const rows = predicate
|
|
164
|
+
? this.db.prepare(sql).all(subject, predicate)
|
|
165
|
+
: this.db.prepare(sql).all(subject);
|
|
166
|
+
const byPred = new Map();
|
|
167
|
+
for (const r of rows) {
|
|
168
|
+
const fact = this.rowToFact(r);
|
|
169
|
+
const bucket = byPred.get(fact.predicate);
|
|
170
|
+
if (bucket)
|
|
171
|
+
bucket.push(fact);
|
|
172
|
+
else
|
|
173
|
+
byPred.set(fact.predicate, [fact]);
|
|
174
|
+
}
|
|
175
|
+
const chains = [];
|
|
176
|
+
for (const [pred, history] of byPred.entries()) {
|
|
177
|
+
chains.push({ subject, predicate: pred, history });
|
|
178
|
+
}
|
|
179
|
+
return chains;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Insert (or replace) the embedding row for a fact. Best-effort: callers
|
|
183
|
+
* trap embedder errors so an unreachable Ollama doesn't roll back ingest.
|
|
184
|
+
* vec0 doesn't UPDATE, so this is a DELETE+INSERT pair.
|
|
185
|
+
*/
|
|
186
|
+
upsertEmbedding(factId, vector) {
|
|
187
|
+
const blob = Buffer.from(vector.buffer, vector.byteOffset, vector.byteLength);
|
|
188
|
+
this.db.prepare("DELETE FROM fact_embeddings WHERE fact_id = ?").run(factId);
|
|
189
|
+
this.db
|
|
190
|
+
.prepare("INSERT INTO fact_embeddings (fact_id, embedding) VALUES (?, ?)")
|
|
191
|
+
.run(factId, blob);
|
|
192
|
+
}
|
|
193
|
+
async markSuperseded(oldId, newId) {
|
|
194
|
+
if (newId !== null && oldId === newId) {
|
|
195
|
+
throw new Error("A fact cannot supersede itself");
|
|
196
|
+
}
|
|
197
|
+
const txn = this.db.transaction(() => {
|
|
198
|
+
const old = this.db
|
|
199
|
+
.prepare("SELECT id FROM facts WHERE id = ?")
|
|
200
|
+
.get(oldId);
|
|
201
|
+
if (!old)
|
|
202
|
+
throw new Error(`Fact ${oldId} not found`);
|
|
203
|
+
if (newId !== null) {
|
|
204
|
+
const next = this.db
|
|
205
|
+
.prepare("SELECT id FROM facts WHERE id = ?")
|
|
206
|
+
.get(newId);
|
|
207
|
+
if (!next)
|
|
208
|
+
throw new Error(`Fact ${newId} not found`);
|
|
209
|
+
}
|
|
210
|
+
this.db
|
|
211
|
+
.prepare("UPDATE facts SET superseded_by = ? WHERE id = ?")
|
|
212
|
+
.run(newId, oldId);
|
|
213
|
+
});
|
|
214
|
+
txn();
|
|
215
|
+
}
|
|
216
|
+
insertStmt() {
|
|
217
|
+
return this.db.prepare(`
|
|
218
|
+
INSERT INTO facts (
|
|
219
|
+
id, kind, subject, predicate, value, source_session_id,
|
|
220
|
+
source_quote, created_at, superseded_by, confidence
|
|
221
|
+
) VALUES (
|
|
222
|
+
@id, @kind, @subject, @predicate, @value, @source_session_id,
|
|
223
|
+
@source_quote, @created_at, @superseded_by, @confidence
|
|
224
|
+
)
|
|
225
|
+
`);
|
|
226
|
+
}
|
|
227
|
+
toRow(fact) {
|
|
228
|
+
return {
|
|
229
|
+
id: fact.id,
|
|
230
|
+
kind: fact.kind,
|
|
231
|
+
subject: fact.subject,
|
|
232
|
+
predicate: fact.predicate,
|
|
233
|
+
value: fact.value,
|
|
234
|
+
source_session_id: fact.sourceSessionId,
|
|
235
|
+
source_quote: fact.sourceQuote,
|
|
236
|
+
created_at: fact.createdAt,
|
|
237
|
+
superseded_by: fact.supersededBy,
|
|
238
|
+
confidence: fact.confidence,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
rowToFact(row) {
|
|
242
|
+
return {
|
|
243
|
+
id: row.id,
|
|
244
|
+
kind: row.kind,
|
|
245
|
+
subject: row.subject,
|
|
246
|
+
predicate: row.predicate,
|
|
247
|
+
value: row.value,
|
|
248
|
+
sourceSessionId: row.source_session_id,
|
|
249
|
+
sourceQuote: row.source_quote,
|
|
250
|
+
createdAt: row.created_at,
|
|
251
|
+
supersededBy: row.superseded_by,
|
|
252
|
+
confidence: row.confidence,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
//# sourceMappingURL=sqlite-fact-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-fact-store.js","sourceRoot":"","sources":["../../../src/core/storage/sqlite-fact-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SqliteSessionStore — the canonical SessionStore implementation backed by
|
|
3
|
+
* better-sqlite3 with the sqlite-vec extension loaded for KNN search.
|
|
4
|
+
*
|
|
5
|
+
* Layering note: core/ imports this concrete class only at the composition
|
|
6
|
+
* root (CLI / server bootstrap). The recall use case and every other piece
|
|
7
|
+
* of core depends on the SessionStore *port*, never on this file.
|
|
8
|
+
*
|
|
9
|
+
* Schema parity with the Python daemon: sessions row + session_entities +
|
|
10
|
+
* markers + session_embeddings (vec0). Idle-status overlay (computed from
|
|
11
|
+
* transcript mtime) is deferred to a later phase — A.2 returns the persisted
|
|
12
|
+
* status verbatim.
|
|
13
|
+
*/
|
|
14
|
+
import Database from "better-sqlite3";
|
|
15
|
+
import type { KeywordNeighbor, SemanticNeighbor, SessionFilter, SessionStore } from "../../ports/session-store.js";
|
|
16
|
+
import type { Session, SessionStatus } from "../../shared/types.js";
|
|
17
|
+
import type { Fact } from "../../shared/types.js";
|
|
18
|
+
import type { SqliteFactStore } from "./sqlite-fact-store.js";
|
|
19
|
+
export interface SqliteSessionStoreOptions {
|
|
20
|
+
readonly dbPath: string;
|
|
21
|
+
readonly migrationsDir: string;
|
|
22
|
+
readonly readonly?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/** Full ingest payload for SqliteSessionStore.insertSession. */
|
|
25
|
+
export interface IngestRecord {
|
|
26
|
+
readonly id: string;
|
|
27
|
+
readonly runtime: string;
|
|
28
|
+
readonly runtimeSessionId: string | null;
|
|
29
|
+
readonly startedAt: string;
|
|
30
|
+
readonly endedAt: string | null;
|
|
31
|
+
readonly durationMin: number | null;
|
|
32
|
+
readonly label: string;
|
|
33
|
+
readonly summary: string;
|
|
34
|
+
readonly body: string | null;
|
|
35
|
+
readonly status: SessionStatus;
|
|
36
|
+
readonly transcriptKind: string | null;
|
|
37
|
+
readonly transcriptPath: string | null;
|
|
38
|
+
readonly transcriptOffset: number | null;
|
|
39
|
+
readonly transcriptLength: number | null;
|
|
40
|
+
readonly entities: ReadonlyArray<string>;
|
|
41
|
+
readonly decisions: ReadonlyArray<string>;
|
|
42
|
+
readonly openQuestions: ReadonlyArray<string>;
|
|
43
|
+
}
|
|
44
|
+
export interface RecentWrite {
|
|
45
|
+
id: string;
|
|
46
|
+
runtime: string;
|
|
47
|
+
label: string;
|
|
48
|
+
summary: string;
|
|
49
|
+
createdAt: string;
|
|
50
|
+
}
|
|
51
|
+
export interface RecentMarker {
|
|
52
|
+
sessionId: string;
|
|
53
|
+
kind: "decision" | "open";
|
|
54
|
+
text: string;
|
|
55
|
+
label: string;
|
|
56
|
+
createdAt: string;
|
|
57
|
+
}
|
|
58
|
+
export declare class SqliteSessionStore implements SessionStore {
|
|
59
|
+
private readonly db;
|
|
60
|
+
constructor(opts: SqliteSessionStoreOptions);
|
|
61
|
+
close(): void;
|
|
62
|
+
/**
|
|
63
|
+
* Drains the WAL into the main database and truncates the -wal file.
|
|
64
|
+
* WAL mode is on but nothing else checkpoints, so the file grows
|
|
65
|
+
* unbounded under continuous readers. The daemon calls this on an
|
|
66
|
+
* interval. Synchronous — keep the WAL small so each call is cheap.
|
|
67
|
+
*/
|
|
68
|
+
checkpoint(): void;
|
|
69
|
+
/** Raw db handle for ingest helpers (Scheduler, scanOnce). Avoid using
|
|
70
|
+
* directly from the recall path — it bypasses the SessionStore port. */
|
|
71
|
+
rawDb(): Database.Database;
|
|
72
|
+
/** Recently-written sessions ordered by created_at desc. Powers /live Writes column. */
|
|
73
|
+
recentWrites(limit: number): RecentWrite[];
|
|
74
|
+
/** Recently-extracted markers ordered by session created_at desc. Powers /live Decisions column. */
|
|
75
|
+
recentMarkers(limit: number): RecentMarker[];
|
|
76
|
+
/**
|
|
77
|
+
* Atomic ingest: writes the session row, markers, entity rows + links,
|
|
78
|
+
* supersedes edge (if any), and the embedding (best-effort) in one
|
|
79
|
+
* transaction. Idempotent on re-ingest — ON CONFLICT updates the session
|
|
80
|
+
* in place; markers are deleted and rewritten; entity links use INSERT OR
|
|
81
|
+
* IGNORE; embedding row is DELETE+INSERT (vec0 doesn't UPDATE).
|
|
82
|
+
*
|
|
83
|
+
* Mirrors Python's SQLiteStore.insert_session. Markdown projection is not
|
|
84
|
+
* yet ported and skipped here.
|
|
85
|
+
*/
|
|
86
|
+
insertSession(record: IngestRecord, embedder?: import("../../ports/llm-client.js").LLMClient | null, supersedes?: string | null, factSink?: {
|
|
87
|
+
factStore: SqliteFactStore;
|
|
88
|
+
facts: ReadonlyArray<Fact>;
|
|
89
|
+
} | null): Promise<void>;
|
|
90
|
+
private deleteSessionChunks;
|
|
91
|
+
private insertChunkEmbedding;
|
|
92
|
+
/**
|
|
93
|
+
* Phase B.5 — backfill entry point. Writes facts (with deterministic
|
|
94
|
+
* supersedence + best-effort embeddings) for an EXISTING session row
|
|
95
|
+
* without touching it. Opens its own transaction; callers must not be
|
|
96
|
+
* inside one. The session row must already exist in `sessions` or the
|
|
97
|
+
* FK on facts.source_session_id rejects.
|
|
98
|
+
*
|
|
99
|
+
* Use this when ingesting facts after the fact — e.g. running the
|
|
100
|
+
* classifier across a historical corpus that predates the B.2 ingest
|
|
101
|
+
* write path. The live ingest path (`insertSession`) keeps using the
|
|
102
|
+
* internal helpers directly so session+facts commit together.
|
|
103
|
+
*/
|
|
104
|
+
insertFactsForSession(sessionId: string, factStore: SqliteFactStore, facts: ReadonlyArray<Fact>, embedder?: import("../../ports/llm-client.js").LLMClient | null): Promise<void>;
|
|
105
|
+
/**
|
|
106
|
+
* Sync core of the fact-ingest block. Runs inside an EXISTING transaction
|
|
107
|
+
* — opens no txn of its own. Used by both `insertSession` (Phase B.2
|
|
108
|
+
* atomic ingest) and `insertFactsForSession` (Phase B.5 backfill).
|
|
109
|
+
*
|
|
110
|
+
* Behavior (mirrored across both callers):
|
|
111
|
+
* 1. DELETE prior facts attributed to this session (idempotent on
|
|
112
|
+
* backfill, drops stale rows on re-ingest).
|
|
113
|
+
* 2. Insert all new facts atomically.
|
|
114
|
+
* 3. For each, mark the prior current (subject, predicate) fact as
|
|
115
|
+
* superseded — Phase B.4 deterministic supersedence policy.
|
|
116
|
+
*
|
|
117
|
+
* Ordering: inserts before updates so the supersedence FK target exists.
|
|
118
|
+
* CASCADE-SET-NULL on `superseded_by` handles chain repair on re-ingest.
|
|
119
|
+
*/
|
|
120
|
+
private applyFactsInTxn;
|
|
121
|
+
/**
|
|
122
|
+
* Best-effort per-fact embedding. Writes `${subject} ${predicate} ${value}`
|
|
123
|
+
* embeddings to fact_embeddings via FactStore.upsertEmbedding. Per-fact
|
|
124
|
+
* failures don't abort the batch, and never affect committed fact rows.
|
|
125
|
+
*/
|
|
126
|
+
private embedFacts;
|
|
127
|
+
list(filter?: SessionFilter): Promise<ReadonlyArray<Session>>;
|
|
128
|
+
getById(sessionId: string): Promise<Session | null>;
|
|
129
|
+
/**
|
|
130
|
+
* Batched session fetch for the recall path. Deliberately omits the
|
|
131
|
+
* `body` column — body is ~48KB/row of session markdown that recall
|
|
132
|
+
* never reads, and SELECTing it for the corpus is what wedged the
|
|
133
|
+
* daemon. Resolved sessions carry `body: ""`.
|
|
134
|
+
*/
|
|
135
|
+
getByIds(ids: ReadonlyArray<string>): Promise<ReadonlyArray<Session>>;
|
|
136
|
+
semanticSearch(queryVector: Float32Array, limit: number): Promise<ReadonlyArray<SemanticNeighbor>>;
|
|
137
|
+
/**
|
|
138
|
+
* Lexical recall via the sessions_fts FTS5 index. BM25 column weights
|
|
139
|
+
* favour label over summary over body. Returns sessions ranked best-first
|
|
140
|
+
* with a positive score (the negated bm25() value — bm25 is more negative
|
|
141
|
+
* for better matches). User input is tokenized and rebuilt into a quoted
|
|
142
|
+
* OR query so FTS5 metacharacters cannot reach the MATCH parser.
|
|
143
|
+
*/
|
|
144
|
+
keywordSearch(query: string, limit: number): Promise<ReadonlyArray<KeywordNeighbor>>;
|
|
145
|
+
updateStatus(sessionId: string, status: SessionStatus): Promise<void>;
|
|
146
|
+
insertSessionForTest(session: Session): void;
|
|
147
|
+
insertEmbeddingForTest(sessionId: string, vector: Float32Array): void;
|
|
148
|
+
insertChunkEmbeddingForTest(sessionId: string, chunkIdx: number, vector: Float32Array): void;
|
|
149
|
+
private loadEntities;
|
|
150
|
+
private loadMarkers;
|
|
151
|
+
private rowToSession;
|
|
152
|
+
}
|