nlm-memory 0.21.0 → 0.21.13
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/README.md +67 -12
- package/assets/replay-eval-dark.svg +26 -0
- package/assets/replay-eval-light.svg +26 -0
- package/dist/cli/digest.js +34 -7
- package/dist/cli/digest.js.map +1 -1
- package/dist/cli/nlm.d.ts +14 -0
- package/dist/cli/nlm.js +450 -65
- package/dist/cli/nlm.js.map +1 -1
- package/dist/cli/reprocess-job-adapters.d.ts +35 -0
- package/dist/cli/reprocess-job-adapters.js +80 -0
- package/dist/cli/reprocess-job-adapters.js.map +1 -0
- package/dist/cli/scope-coverage.js +4 -1
- package/dist/cli/scope-coverage.js.map +1 -1
- package/dist/cli/supersede.js +8 -7
- package/dist/cli/supersede.js.map +1 -1
- package/dist/core/actions/actions-log.d.ts +65 -8
- package/dist/core/actions/actions-log.js +134 -17
- package/dist/core/actions/actions-log.js.map +1 -1
- package/dist/core/actions/overlay.d.ts +11 -2
- package/dist/core/actions/overlay.js +18 -6
- package/dist/core/actions/overlay.js.map +1 -1
- package/dist/core/adapters/from-source.js +11 -3
- package/dist/core/adapters/from-source.js.map +1 -1
- package/dist/core/adapters/fs-wiki-writer.d.ts +44 -0
- package/dist/core/adapters/fs-wiki-writer.js +132 -0
- package/dist/core/adapters/fs-wiki-writer.js.map +1 -0
- package/dist/core/adapters/hermes-agent.d.ts +15 -2
- package/dist/core/adapters/hermes-agent.js +57 -11
- package/dist/core/adapters/hermes-agent.js.map +1 -1
- package/dist/core/adapters/memory-wiki-writer.d.ts +8 -0
- package/dist/core/adapters/memory-wiki-writer.js +16 -0
- package/dist/core/adapters/memory-wiki-writer.js.map +1 -0
- package/dist/core/adapters/muse.d.ts +51 -0
- package/dist/core/adapters/muse.js +271 -0
- package/dist/core/adapters/muse.js.map +1 -0
- package/dist/core/adapters/opencode.d.ts +11 -4
- package/dist/core/adapters/opencode.js +41 -7
- package/dist/core/adapters/opencode.js.map +1 -1
- package/dist/core/alerts/alert-state.d.ts +17 -0
- package/dist/core/alerts/alert-state.js +45 -0
- package/dist/core/alerts/alert-state.js.map +1 -0
- package/dist/core/alerts/check-and-alert.d.ts +28 -0
- package/dist/core/alerts/check-and-alert.js +53 -0
- package/dist/core/alerts/check-and-alert.js.map +1 -0
- package/dist/core/alerts/drift-transition.d.ts +27 -0
- package/dist/core/alerts/drift-transition.js +56 -0
- package/dist/core/alerts/drift-transition.js.map +1 -0
- package/dist/core/alerts/embedder-transition.d.ts +23 -0
- package/dist/core/alerts/embedder-transition.js +40 -0
- package/dist/core/alerts/embedder-transition.js.map +1 -0
- package/dist/core/alerts/fire-alert.d.ts +24 -0
- package/dist/core/alerts/fire-alert.js +72 -0
- package/dist/core/alerts/fire-alert.js.map +1 -0
- package/dist/core/alerts/job-alert.d.ts +12 -0
- package/dist/core/alerts/job-alert.js +37 -0
- package/dist/core/alerts/job-alert.js.map +1 -0
- package/dist/core/alerts/types.d.ts +104 -0
- package/dist/core/alerts/types.js +11 -0
- package/dist/core/alerts/types.js.map +1 -0
- package/dist/core/alerts/wiki-alert.d.ts +15 -0
- package/dist/core/alerts/wiki-alert.js +31 -0
- package/dist/core/alerts/wiki-alert.js.map +1 -0
- package/dist/core/classifier/prompt.d.ts +13 -0
- package/dist/core/classifier/prompt.js +52 -2
- package/dist/core/classifier/prompt.js.map +1 -1
- package/dist/core/dataset/build-dataset.d.ts +16 -1
- package/dist/core/dataset/build-dataset.js +105 -45
- package/dist/core/dataset/build-dataset.js.map +1 -1
- package/dist/core/digest/compose.d.ts +8 -0
- package/dist/core/digest/compose.js +54 -0
- package/dist/core/digest/compose.js.map +1 -1
- package/dist/core/digest/hook-injection.d.ts +1 -1
- package/dist/core/digest/hook-injection.js +9 -1
- package/dist/core/digest/hook-injection.js.map +1 -1
- package/dist/core/digest/hook-version-parity.d.ts +31 -0
- package/dist/core/digest/hook-version-parity.js +56 -0
- package/dist/core/digest/hook-version-parity.js.map +1 -0
- package/dist/core/embedding/pg-embed-backfill.js +1 -1
- package/dist/core/embedding/pg-embed-backfill.js.map +1 -1
- package/dist/core/exemplars/capture-from-session.d.ts +1 -1
- package/dist/core/exemplars/capture-from-session.js +3 -3
- package/dist/core/exemplars/capture-from-session.js.map +1 -1
- package/dist/core/exemplars/embed-backfill.d.ts +9 -0
- package/dist/core/exemplars/embed-backfill.js +9 -1
- package/dist/core/exemplars/embed-backfill.js.map +1 -1
- package/dist/core/exemplars/recall-code.d.ts +1 -1
- package/dist/core/exemplars/recall-code.js +2 -2
- package/dist/core/exemplars/recall-code.js.map +1 -1
- package/dist/core/facts/backfill-facts.d.ts +1 -1
- package/dist/core/facts/backfill-facts.js +4 -4
- package/dist/core/facts/backfill-facts.js.map +1 -1
- package/dist/core/facts/embed-backfill.d.ts +54 -0
- package/dist/core/facts/embed-backfill.js +109 -0
- package/dist/core/facts/embed-backfill.js.map +1 -0
- package/dist/core/facts/reconcile-facts.d.ts +42 -0
- package/dist/core/facts/reconcile-facts.js +133 -0
- package/dist/core/facts/reconcile-facts.js.map +1 -0
- package/dist/core/health/embed-failure-state.d.ts +4 -0
- package/dist/core/health/embed-failure-state.js +12 -0
- package/dist/core/health/embed-failure-state.js.map +1 -0
- package/dist/core/health/warmup-retry.d.ts +27 -0
- package/dist/core/health/warmup-retry.js +53 -0
- package/dist/core/health/warmup-retry.js.map +1 -0
- package/dist/core/health/warmup-state.d.ts +15 -0
- package/dist/core/health/warmup-state.js +15 -1
- package/dist/core/health/warmup-state.js.map +1 -1
- package/dist/core/hook/cite-memo.d.ts +11 -7
- package/dist/core/hook/cite-memo.js +25 -17
- package/dist/core/hook/cite-memo.js.map +1 -1
- package/dist/core/hook/hook-log.d.ts +13 -2
- package/dist/core/hook/hook-log.js +16 -8
- package/dist/core/hook/hook-log.js.map +1 -1
- package/dist/core/hook/memo.d.ts +10 -6
- package/dist/core/hook/memo.js +25 -17
- package/dist/core/hook/memo.js.map +1 -1
- package/dist/core/hook/pointer-block.d.ts +8 -1
- package/dist/core/hook/pointer-block.js +17 -4
- package/dist/core/hook/pointer-block.js.map +1 -1
- package/dist/core/hook/resolve-conversation-by-query.d.ts +6 -5
- package/dist/core/hook/resolve-conversation-by-query.js +24 -12
- package/dist/core/hook/resolve-conversation-by-query.js.map +1 -1
- package/dist/core/ingest/ingest-session.d.ts +1 -1
- package/dist/core/ingest/ingest-session.js +3 -3
- package/dist/core/ingest/ingest-session.js.map +1 -1
- package/dist/core/ingest/reclassify-oversized.d.ts +1 -1
- package/dist/core/ingest/reclassify-oversized.js +2 -2
- package/dist/core/ingest/reclassify-oversized.js.map +1 -1
- package/dist/core/ingest/reprocess.d.ts +1 -1
- package/dist/core/ingest/reprocess.js +2 -2
- package/dist/core/ingest/reprocess.js.map +1 -1
- package/dist/core/jobs/job-supervisor.d.ts +168 -0
- package/dist/core/jobs/job-supervisor.js +335 -0
- package/dist/core/jobs/job-supervisor.js.map +1 -0
- package/dist/core/learner/model.d.ts +63 -0
- package/dist/core/learner/model.js +30 -0
- package/dist/core/learner/model.js.map +1 -0
- package/dist/core/learner/service.d.ts +42 -0
- package/dist/core/learner/service.js +74 -0
- package/dist/core/learner/service.js.map +1 -0
- package/dist/core/learner/summary.d.ts +28 -0
- package/dist/core/learner/summary.js +70 -0
- package/dist/core/learner/summary.js.map +1 -0
- package/dist/core/learner/validate.d.ts +18 -0
- package/dist/core/learner/validate.js +95 -0
- package/dist/core/learner/validate.js.map +1 -0
- package/dist/core/metrics/re-derivation.d.ts +31 -2
- package/dist/core/metrics/re-derivation.js +36 -4
- package/dist/core/metrics/re-derivation.js.map +1 -1
- package/dist/core/outcome/coverage.d.ts +1 -1
- package/dist/core/outcome/coverage.js +2 -2
- package/dist/core/outcome/coverage.js.map +1 -1
- package/dist/core/outcome/rollup.d.ts +1 -1
- package/dist/core/outcome/rollup.js +4 -4
- package/dist/core/outcome/rollup.js.map +1 -1
- package/dist/core/providers/provider-registry.d.ts +40 -23
- package/dist/core/providers/provider-registry.js +99 -81
- package/dist/core/providers/provider-registry.js.map +1 -1
- package/dist/core/recall/citation-log.d.ts +10 -5
- package/dist/core/recall/citation-log.js +21 -10
- package/dist/core/recall/citation-log.js.map +1 -1
- package/dist/core/recall/hook-recall-log.d.ts +5 -2
- package/dist/core/recall/hook-recall-log.js +12 -6
- package/dist/core/recall/hook-recall-log.js.map +1 -1
- package/dist/core/recall/miss-log.d.ts +7 -4
- package/dist/core/recall/miss-log.js +18 -11
- package/dist/core/recall/miss-log.js.map +1 -1
- package/dist/core/recall/query-log.d.ts +8 -5
- package/dist/core/recall/query-log.js +16 -9
- package/dist/core/recall/query-log.js.map +1 -1
- package/dist/core/recall/recall-service.d.ts +10 -1
- package/dist/core/recall/recall-service.js +31 -12
- package/dist/core/recall/recall-service.js.map +1 -1
- package/dist/core/recall/recent-log.d.ts +6 -1
- package/dist/core/recall/recent-log.js +13 -5
- package/dist/core/recall/recent-log.js.map +1 -1
- package/dist/core/recall/related-concepts.d.ts +29 -0
- package/dist/core/recall/related-concepts.js +67 -0
- package/dist/core/recall/related-concepts.js.map +1 -0
- package/dist/core/recall/related-exemplars.d.ts +1 -1
- package/dist/core/recall/related-exemplars.js +2 -2
- package/dist/core/recall/related-exemplars.js.map +1 -1
- package/dist/core/recall/related-facts.d.ts +1 -1
- package/dist/core/recall/related-facts.js +3 -3
- package/dist/core/recall/related-facts.js.map +1 -1
- package/dist/core/recall-facts/fact-query-log.d.ts +8 -4
- package/dist/core/recall-facts/fact-query-log.js +16 -8
- package/dist/core/recall-facts/fact-query-log.js.map +1 -1
- package/dist/core/recall-facts/fact-recall-service.d.ts +2 -2
- package/dist/core/recall-facts/fact-recall-service.js +12 -12
- package/dist/core/recall-facts/fact-recall-service.js.map +1 -1
- package/dist/core/scheduler/scan-once.js +15 -14
- package/dist/core/scheduler/scan-once.js.map +1 -1
- package/dist/core/scheduler/scheduler.d.ts +3 -0
- package/dist/core/scheduler/scheduler.js +15 -11
- package/dist/core/scheduler/scheduler.js.map +1 -1
- package/dist/core/signals/failure-mode-recall.d.ts +1 -1
- package/dist/core/signals/failure-mode-recall.js +2 -2
- package/dist/core/signals/failure-mode-recall.js.map +1 -1
- package/dist/core/signals/stamp-scope.d.ts +2 -2
- package/dist/core/signals/stamp-scope.js +2 -2
- package/dist/core/signals/stamp-scope.js.map +1 -1
- package/dist/core/sources/source-registry.d.ts +49 -28
- package/dist/core/sources/source-registry.js +113 -70
- package/dist/core/sources/source-registry.js.map +1 -1
- package/dist/core/storage/pg-code-exemplar-store.d.ts +19 -10
- package/dist/core/storage/pg-code-exemplar-store.js +58 -27
- package/dist/core/storage/pg-code-exemplar-store.js.map +1 -1
- package/dist/core/storage/pg-entity-store.d.ts +6 -1
- package/dist/core/storage/pg-entity-store.js +33 -18
- package/dist/core/storage/pg-entity-store.js.map +1 -1
- package/dist/core/storage/pg-fact-ingest.d.ts +1 -1
- package/dist/core/storage/pg-fact-ingest.js +10 -7
- package/dist/core/storage/pg-fact-ingest.js.map +1 -1
- package/dist/core/storage/pg-fact-store.d.ts +29 -17
- package/dist/core/storage/pg-fact-store.js +99 -46
- package/dist/core/storage/pg-fact-store.js.map +1 -1
- package/dist/core/storage/pg-learner-store.d.ts +27 -0
- package/dist/core/storage/pg-learner-store.js +174 -0
- package/dist/core/storage/pg-learner-store.js.map +1 -0
- package/dist/core/storage/pg-session-store.d.ts +24 -20
- package/dist/core/storage/pg-session-store.js +162 -90
- package/dist/core/storage/pg-session-store.js.map +1 -1
- package/dist/core/storage/pg-signal-store.d.ts +10 -5
- package/dist/core/storage/pg-signal-store.js +24 -12
- package/dist/core/storage/pg-signal-store.js.map +1 -1
- package/dist/core/storage/pg-storage.d.ts +4 -0
- package/dist/core/storage/pg-storage.js +6 -0
- package/dist/core/storage/pg-storage.js.map +1 -1
- package/dist/core/storage/pg-workstream-store.d.ts +16 -11
- package/dist/core/storage/pg-workstream-store.js +46 -29
- package/dist/core/storage/pg-workstream-store.js.map +1 -1
- package/dist/core/storage/sqlite-code-exemplar-store.d.ts +24 -10
- package/dist/core/storage/sqlite-code-exemplar-store.js +84 -40
- package/dist/core/storage/sqlite-code-exemplar-store.js.map +1 -1
- package/dist/core/storage/sqlite-entity-store.d.ts +8 -1
- package/dist/core/storage/sqlite-entity-store.js +46 -27
- package/dist/core/storage/sqlite-entity-store.js.map +1 -1
- package/dist/core/storage/sqlite-fact-store.d.ts +45 -19
- package/dist/core/storage/sqlite-fact-store.js +172 -64
- package/dist/core/storage/sqlite-fact-store.js.map +1 -1
- package/dist/core/storage/sqlite-learner-store.d.ts +33 -0
- package/dist/core/storage/sqlite-learner-store.js +178 -0
- package/dist/core/storage/sqlite-learner-store.js.map +1 -0
- package/dist/core/storage/sqlite-outcome-store.d.ts +37 -22
- package/dist/core/storage/sqlite-outcome-store.js +90 -37
- package/dist/core/storage/sqlite-outcome-store.js.map +1 -1
- package/dist/core/storage/sqlite-session-store.d.ts +29 -20
- package/dist/core/storage/sqlite-session-store.js +207 -121
- package/dist/core/storage/sqlite-session-store.js.map +1 -1
- package/dist/core/storage/sqlite-signal-store.d.ts +12 -5
- package/dist/core/storage/sqlite-signal-store.js +27 -15
- package/dist/core/storage/sqlite-signal-store.js.map +1 -1
- package/dist/core/storage/sqlite-storage.d.ts +4 -0
- package/dist/core/storage/sqlite-storage.js +10 -2
- package/dist/core/storage/sqlite-storage.js.map +1 -1
- package/dist/core/storage/sqlite-workstream-store.d.ts +16 -11
- package/dist/core/storage/sqlite-workstream-store.js +52 -31
- package/dist/core/storage/sqlite-workstream-store.js.map +1 -1
- package/dist/core/storage/supersedence-log.d.ts +10 -7
- package/dist/core/storage/supersedence-log.js +19 -14
- package/dist/core/storage/supersedence-log.js.map +1 -1
- package/dist/core/tenancy/default-team.d.ts +6 -0
- package/dist/core/tenancy/default-team.js +7 -0
- package/dist/core/tenancy/default-team.js.map +1 -0
- package/dist/core/tenancy/hosted-mode.d.ts +9 -0
- package/dist/core/tenancy/hosted-mode.js +12 -0
- package/dist/core/tenancy/hosted-mode.js.map +1 -0
- package/dist/core/tenancy/team-auth.d.ts +16 -0
- package/dist/core/tenancy/team-auth.js +22 -0
- package/dist/core/tenancy/team-auth.js.map +1 -0
- package/dist/core/tenancy/team-token-store.d.ts +45 -0
- package/dist/core/tenancy/team-token-store.js +52 -0
- package/dist/core/tenancy/team-token-store.js.map +1 -0
- package/dist/core/tenancy/tenant-clause.d.ts +37 -0
- package/dist/core/tenancy/tenant-clause.js +11 -0
- package/dist/core/tenancy/tenant-clause.js.map +1 -0
- package/dist/core/tenancy/tenant-state-path.d.ts +28 -0
- package/dist/core/tenancy/tenant-state-path.js +49 -0
- package/dist/core/tenancy/tenant-state-path.js.map +1 -0
- package/dist/core/wiki/project.d.ts +17 -0
- package/dist/core/wiki/project.js +37 -0
- package/dist/core/wiki/project.js.map +1 -0
- package/dist/core/wiki/reconcile.d.ts +15 -0
- package/dist/core/wiki/reconcile.js +14 -0
- package/dist/core/wiki/reconcile.js.map +1 -0
- package/dist/core/wiki/render.d.ts +5 -0
- package/dist/core/wiki/render.js +84 -0
- package/dist/core/wiki/render.js.map +1 -0
- package/dist/core/wiki/rollup.d.ts +28 -0
- package/dist/core/wiki/rollup.js +91 -0
- package/dist/core/wiki/rollup.js.map +1 -0
- package/dist/core/wiki/select.d.ts +8 -0
- package/dist/core/wiki/select.js +7 -0
- package/dist/core/wiki/select.js.map +1 -0
- package/dist/core/wiki/slug.d.ts +36 -0
- package/dist/core/wiki/slug.js +71 -0
- package/dist/core/wiki/slug.js.map +1 -0
- package/dist/core/wiki/types.d.ts +37 -0
- package/dist/core/wiki/types.js +2 -0
- package/dist/core/wiki/types.js.map +1 -0
- package/dist/core/work-digest/build-work-digest.d.ts +1 -1
- package/dist/core/work-digest/build-work-digest.js +3 -3
- package/dist/core/work-digest/build-work-digest.js.map +1 -1
- package/dist/core/workstream/bind.d.ts +1 -1
- package/dist/core/workstream/bind.js +10 -10
- package/dist/core/workstream/bind.js.map +1 -1
- package/dist/core/workstream/rollup.d.ts +1 -1
- package/dist/core/workstream/rollup.js +6 -6
- package/dist/core/workstream/rollup.js.map +1 -1
- package/dist/hook/hook-helpers.d.ts +14 -0
- package/dist/hook/hook-helpers.js +29 -2
- package/dist/hook/hook-helpers.js.map +1 -1
- package/dist/hook/pre-compact-hook.js +6 -4
- package/dist/hook/pre-compact-hook.js.map +1 -1
- package/dist/hook/prompt-recall-hook.d.ts +5 -2
- package/dist/hook/prompt-recall-hook.js +28 -17
- package/dist/hook/prompt-recall-hook.js.map +1 -1
- package/dist/hook/recall-over-http.d.ts +27 -3
- package/dist/hook/recall-over-http.js +44 -11
- package/dist/hook/recall-over-http.js.map +1 -1
- package/dist/hook/session-end-hook.js +7 -5
- package/dist/hook/session-end-hook.js.map +1 -1
- package/dist/hook/session-start-hook.d.ts +14 -1
- package/dist/hook/session-start-hook.js +55 -15
- package/dist/hook/session-start-hook.js.map +1 -1
- package/dist/hook/stop-hook.js +9 -7
- package/dist/hook/stop-hook.js.map +1 -1
- package/dist/http/app.d.ts +41 -3
- package/dist/http/app.js +355 -96
- package/dist/http/app.js.map +1 -1
- package/dist/install/claude-code.d.ts +17 -0
- package/dist/install/claude-code.js +44 -5
- package/dist/install/claude-code.js.map +1 -1
- package/dist/install/codex.d.ts +23 -2
- package/dist/install/codex.js +111 -14
- package/dist/install/codex.js.map +1 -1
- package/dist/install/cursor.d.ts +2 -2
- package/dist/install/cursor.js +7 -7
- package/dist/install/cursor.js.map +1 -1
- package/dist/install/hermes.d.ts +8 -0
- package/dist/install/hermes.js +28 -5
- package/dist/install/hermes.js.map +1 -1
- package/dist/install/local-source.d.ts +20 -0
- package/dist/install/local-source.js +28 -0
- package/dist/install/local-source.js.map +1 -0
- package/dist/install/mcp-block.d.ts +77 -0
- package/dist/install/mcp-block.js +99 -0
- package/dist/install/mcp-block.js.map +1 -0
- package/dist/install/pi.d.ts +26 -0
- package/dist/install/pi.js +43 -0
- package/dist/install/pi.js.map +1 -1
- package/dist/install/setup.js +6 -0
- package/dist/install/setup.js.map +1 -1
- package/dist/install/windsurf.d.ts +2 -2
- package/dist/install/windsurf.js +7 -7
- package/dist/install/windsurf.js.map +1 -1
- package/dist/llm/classifier-box.d.ts +5 -0
- package/dist/llm/classifier-box.js +5 -0
- package/dist/llm/classifier-box.js.map +1 -1
- package/dist/mcp/server.d.ts +73 -16
- package/dist/mcp/server.js +306 -83
- package/dist/mcp/server.js.map +1 -1
- package/dist/ports/clock.d.ts +12 -0
- package/dist/ports/clock.js +10 -0
- package/dist/ports/clock.js.map +1 -0
- package/dist/ports/code-exemplar-store.d.ts +13 -13
- package/dist/ports/entity-store.d.ts +5 -1
- package/dist/ports/fact-store.d.ts +0 -0
- package/dist/ports/fact-store.js +0 -0
- package/dist/ports/fact-store.js.map +1 -1
- package/dist/ports/learner-store.d.ts +80 -0
- package/dist/ports/learner-store.js +19 -0
- package/dist/ports/learner-store.js.map +1 -0
- package/dist/ports/outcome.d.ts +3 -3
- package/dist/ports/session-store.d.ts +20 -14
- package/dist/ports/session-store.js +5 -0
- package/dist/ports/session-store.js.map +1 -1
- package/dist/ports/signal-store.d.ts +12 -8
- package/dist/ports/spawn-child.d.ts +14 -0
- package/dist/ports/spawn-child.js +10 -0
- package/dist/ports/spawn-child.js.map +1 -0
- package/dist/ports/storage.d.ts +6 -0
- package/dist/ports/transcript-adapter.d.ts +11 -0
- package/dist/ports/wiki-writer.d.ts +19 -0
- package/dist/ports/wiki-writer.js +12 -0
- package/dist/ports/wiki-writer.js.map +1 -0
- package/dist/ports/workstream-store.d.ts +19 -12
- package/dist/shared/types.d.ts +22 -0
- package/dist/shared/types.js.map +1 -1
- package/dist/shared/version.d.ts +9 -0
- package/dist/shared/version.js +11 -0
- package/dist/shared/version.js.map +1 -0
- package/dist/ui/assets/index-D6F3xAis.js +11 -0
- package/dist/ui/index.html +1 -1
- package/migrations/033_actions_kind_check.sql +58 -0
- package/migrations/034_tenancy_teams_and_stamps.sql +40 -0
- package/migrations/035_tenancy_entity_rekey.sql +75 -0
- package/migrations/036_tenant_name_uniqueness.sql +59 -0
- package/migrations/037_sessions_covering_index.sql +25 -0
- package/migrations/038_sources_muse.sql +33 -0
- package/migrations/039_learner_evidence.sql +51 -0
- package/migrations/pg/033_actions_kind_check.sql +17 -0
- package/migrations/pg/034_tenancy.sql +77 -0
- package/migrations/pg/035_tenant_name_uniqueness.sql +15 -0
- package/migrations/pg/036_sources_muse.sql +12 -0
- package/migrations/pg/037_learner_evidence.sql +55 -0
- package/nlm/index.js +246 -55
- package/package.json +10 -5
- package/plugin/.codex-plugin/plugin.json +2 -2
- package/plugin/scripts/prompt-recall-hook.mjs +244 -55
- package/plugin/scripts/session-start-hook.mjs +273 -53
- package/plugin/scripts/stop-hook.mjs +195 -37
- package/dist/ui/assets/index-CSaBtgXD.js +0 -11
|
@@ -11,10 +11,20 @@
|
|
|
11
11
|
* `redact()` strips secrets on the way out — every HTTP response sends
|
|
12
12
|
* redacted rows, with the key only retrievable via getSecret() inside the
|
|
13
13
|
* daemon process.
|
|
14
|
+
*
|
|
15
|
+
* Tenancy (program spec §4, M2 plan Wave B5): `providers` is a STAMP table.
|
|
16
|
+
* Every method takes `tenantId` as its non-optional first parameter and
|
|
17
|
+
* routes its WHERE fragment through `tenantClause`; INSERTs stamp
|
|
18
|
+
* `tenant_id`. `getSecret` is the top-risk-3 surface (spec §4.5): a
|
|
19
|
+
* tenant-mismatched id returns the same not-found shape (`null`) as a
|
|
20
|
+
* missing row — no existence oracle, and no plaintext key crosses a tenant
|
|
21
|
+
* boundary via an id an attacker merely guessed.
|
|
14
22
|
*/
|
|
23
|
+
import { tenantClause, tenantClausePg } from "../tenancy/tenant-clause.js";
|
|
15
24
|
function rowFromDb(r, includeSecret) {
|
|
16
25
|
return {
|
|
17
26
|
id: r.id,
|
|
27
|
+
tenantId: r.tenant_id,
|
|
18
28
|
kind: r.kind,
|
|
19
29
|
name: r.name,
|
|
20
30
|
baseUrl: r.base_url,
|
|
@@ -47,29 +57,37 @@ export class ProviderRegistry {
|
|
|
47
57
|
constructor(db) {
|
|
48
58
|
this.db = db;
|
|
49
59
|
}
|
|
50
|
-
async list() {
|
|
51
|
-
const
|
|
60
|
+
async list(tenantId) {
|
|
61
|
+
const tc = tenantClause(tenantId);
|
|
62
|
+
const rows = this.db.prepare(`SELECT * FROM providers WHERE ${tc.sql} ORDER BY id ASC`).all(tc.param);
|
|
52
63
|
return rows.map((r) => rowFromDb(r, false));
|
|
53
64
|
}
|
|
54
|
-
async get(id) {
|
|
55
|
-
const
|
|
65
|
+
async get(tenantId, id) {
|
|
66
|
+
const tc = tenantClause(tenantId);
|
|
67
|
+
const row = this.db.prepare(`SELECT * FROM providers WHERE id = ? AND ${tc.sql}`).get(id, tc.param);
|
|
56
68
|
return row ? rowFromDb(row, false) : null;
|
|
57
69
|
}
|
|
58
|
-
async getByName(name) {
|
|
59
|
-
const
|
|
70
|
+
async getByName(tenantId, name) {
|
|
71
|
+
const tc = tenantClause(tenantId);
|
|
72
|
+
const row = this.db.prepare(`SELECT * FROM providers WHERE name = ? AND ${tc.sql}`).get(name, tc.param);
|
|
60
73
|
return row ? rowFromDb(row, false) : null;
|
|
61
74
|
}
|
|
62
|
-
/**
|
|
63
|
-
|
|
64
|
-
|
|
75
|
+
/**
|
|
76
|
+
* Returns the secret. Use only inside the daemon — never echo to HTTP.
|
|
77
|
+
* A tenant-mismatched id returns null, identical to a missing row (top
|
|
78
|
+
* risk 3, spec §4.5) — no existence oracle, no cross-tenant key leak.
|
|
79
|
+
*/
|
|
80
|
+
async getSecret(tenantId, id) {
|
|
81
|
+
const tc = tenantClause(tenantId);
|
|
82
|
+
const row = this.db.prepare(`SELECT * FROM providers WHERE id = ? AND ${tc.sql}`).get(id, tc.param);
|
|
65
83
|
return row?.api_key ?? null;
|
|
66
84
|
}
|
|
67
|
-
async insert(input) {
|
|
85
|
+
async insert(tenantId, input) {
|
|
68
86
|
const baseUrl = input.baseUrl ?? DEFAULT_BASE_URLS[input.kind];
|
|
69
87
|
const defaultModel = input.defaultModel ?? DEFAULT_MODELS[input.kind];
|
|
70
88
|
const result = this.db.prepare(`
|
|
71
|
-
INSERT INTO providers (kind, name, base_url, api_key, default_model, enabled)
|
|
72
|
-
VALUES (@kind, @name, @base_url, @api_key, @default_model, @enabled)
|
|
89
|
+
INSERT INTO providers (kind, name, base_url, api_key, default_model, enabled, tenant_id)
|
|
90
|
+
VALUES (@kind, @name, @base_url, @api_key, @default_model, @enabled, @tenant_id)
|
|
73
91
|
`).run({
|
|
74
92
|
kind: input.kind,
|
|
75
93
|
name: input.name,
|
|
@@ -77,44 +95,47 @@ export class ProviderRegistry {
|
|
|
77
95
|
api_key: input.apiKey ?? null,
|
|
78
96
|
default_model: defaultModel ?? null,
|
|
79
97
|
enabled: input.enabled === false ? 0 : 1,
|
|
98
|
+
tenant_id: tenantId,
|
|
80
99
|
});
|
|
81
100
|
const id = Number(result.lastInsertRowid);
|
|
82
|
-
const row = await this.get(id);
|
|
101
|
+
const row = await this.get(tenantId, id);
|
|
83
102
|
if (!row)
|
|
84
103
|
throw new Error(`ProviderRegistry.insert: row ${id} not found after insert`);
|
|
85
104
|
return row;
|
|
86
105
|
}
|
|
87
|
-
async update(id, patch) {
|
|
106
|
+
async update(tenantId, id, patch) {
|
|
88
107
|
const fields = [];
|
|
89
|
-
const params =
|
|
108
|
+
const params = [];
|
|
90
109
|
if (patch.name !== undefined) {
|
|
91
|
-
fields.push("name =
|
|
92
|
-
params
|
|
110
|
+
fields.push("name = ?");
|
|
111
|
+
params.push(patch.name);
|
|
93
112
|
}
|
|
94
113
|
if (patch.baseUrl !== undefined) {
|
|
95
|
-
fields.push("base_url =
|
|
96
|
-
params
|
|
114
|
+
fields.push("base_url = ?");
|
|
115
|
+
params.push(patch.baseUrl);
|
|
97
116
|
}
|
|
98
117
|
if (patch.apiKey !== undefined) {
|
|
99
|
-
fields.push("api_key =
|
|
100
|
-
params
|
|
118
|
+
fields.push("api_key = ?");
|
|
119
|
+
params.push(patch.apiKey);
|
|
101
120
|
}
|
|
102
121
|
if (patch.defaultModel !== undefined) {
|
|
103
|
-
fields.push("default_model =
|
|
104
|
-
params
|
|
122
|
+
fields.push("default_model = ?");
|
|
123
|
+
params.push(patch.defaultModel);
|
|
105
124
|
}
|
|
106
125
|
if (patch.enabled !== undefined) {
|
|
107
|
-
fields.push("enabled =
|
|
108
|
-
params
|
|
126
|
+
fields.push("enabled = ?");
|
|
127
|
+
params.push(patch.enabled ? 1 : 0);
|
|
109
128
|
}
|
|
110
129
|
if (fields.length === 0)
|
|
111
|
-
return this.get(id);
|
|
130
|
+
return this.get(tenantId, id);
|
|
112
131
|
fields.push("updated_at = datetime('now')");
|
|
113
|
-
|
|
114
|
-
|
|
132
|
+
const tc = tenantClause(tenantId);
|
|
133
|
+
this.db.prepare(`UPDATE providers SET ${fields.join(", ")} WHERE id = ? AND ${tc.sql}`).run(...params, id, tc.param);
|
|
134
|
+
return this.get(tenantId, id);
|
|
115
135
|
}
|
|
116
|
-
async delete(id) {
|
|
117
|
-
const
|
|
136
|
+
async delete(tenantId, id) {
|
|
137
|
+
const tc = tenantClause(tenantId);
|
|
138
|
+
const result = this.db.prepare(`DELETE FROM providers WHERE id = ? AND ${tc.sql}`).run(id, tc.param);
|
|
118
139
|
return result.changes > 0;
|
|
119
140
|
}
|
|
120
141
|
/**
|
|
@@ -123,17 +144,18 @@ export class ProviderRegistry {
|
|
|
123
144
|
* forward; Ollama is always seeded since it needs no key. SQLite-only —
|
|
124
145
|
* not on ProviderRegistryPort (see the port's doc comment).
|
|
125
146
|
*/
|
|
126
|
-
async seedDefaults() {
|
|
127
|
-
const
|
|
147
|
+
async seedDefaults(tenantId) {
|
|
148
|
+
const tc = tenantClause(tenantId);
|
|
149
|
+
const count = this.db.prepare(`SELECT COUNT(*) AS c FROM providers WHERE ${tc.sql}`).get(tc.param);
|
|
128
150
|
if ((count?.c ?? 0) > 0)
|
|
129
151
|
return;
|
|
130
|
-
await this.insert({
|
|
152
|
+
await this.insert(tenantId, {
|
|
131
153
|
kind: "ollama",
|
|
132
154
|
name: "Ollama (local)",
|
|
133
155
|
baseUrl: process.env["NLM_OLLAMA_URL"] ?? "http://localhost:11434",
|
|
134
156
|
});
|
|
135
157
|
const deepseekKey = process.env["DEEPSEEK_API_KEY"];
|
|
136
|
-
await this.insert({
|
|
158
|
+
await this.insert(tenantId, {
|
|
137
159
|
kind: "deepseek",
|
|
138
160
|
name: "DeepSeek",
|
|
139
161
|
apiKey: deepseekKey ?? null,
|
|
@@ -141,6 +163,15 @@ export class ProviderRegistry {
|
|
|
141
163
|
});
|
|
142
164
|
}
|
|
143
165
|
}
|
|
166
|
+
function pgRowToProvider(r) {
|
|
167
|
+
return {
|
|
168
|
+
id: r.id, tenantId: r.tenant_id, kind: r.kind, name: r.name, baseUrl: r.base_url,
|
|
169
|
+
apiKey: null, hasApiKey: r.api_key !== null && r.api_key.length > 0,
|
|
170
|
+
defaultModel: r.default_model, enabled: r.enabled,
|
|
171
|
+
createdAt: r.created_at, updatedAt: r.updated_at,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const PG_PROVIDER_COLUMNS = `id, tenant_id, kind, name, base_url, api_key, default_model, enabled, created_at, updated_at`;
|
|
144
175
|
/**
|
|
145
176
|
* PgProviderRegistry — CRUD over `providers` for the PG storage path.
|
|
146
177
|
* API mirrors ProviderRegistry exactly.
|
|
@@ -150,61 +181,45 @@ export class PgProviderRegistry {
|
|
|
150
181
|
constructor(pool) {
|
|
151
182
|
this.pool = pool;
|
|
152
183
|
}
|
|
153
|
-
async list() {
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
return result.rows.map(
|
|
157
|
-
id: r.id, kind: r.kind, name: r.name, baseUrl: r.base_url,
|
|
158
|
-
apiKey: null, hasApiKey: r.api_key !== null && r.api_key.length > 0,
|
|
159
|
-
defaultModel: r.default_model, enabled: r.enabled,
|
|
160
|
-
createdAt: r.created_at, updatedAt: r.updated_at,
|
|
161
|
-
}));
|
|
162
|
-
}
|
|
163
|
-
async get(id) {
|
|
164
|
-
const result = await this.pool.query(`SELECT id, kind, name, base_url, api_key, default_model, enabled, created_at, updated_at
|
|
165
|
-
FROM providers WHERE id = $1`, [id]);
|
|
166
|
-
if (!result.rows[0])
|
|
167
|
-
return null;
|
|
168
|
-
const r = result.rows[0];
|
|
169
|
-
return {
|
|
170
|
-
id: r.id, kind: r.kind, name: r.name, baseUrl: r.base_url,
|
|
171
|
-
apiKey: null, hasApiKey: r.api_key !== null && r.api_key.length > 0,
|
|
172
|
-
defaultModel: r.default_model, enabled: r.enabled,
|
|
173
|
-
createdAt: r.created_at, updatedAt: r.updated_at,
|
|
174
|
-
};
|
|
184
|
+
async list(tenantId) {
|
|
185
|
+
const tc = tenantClausePg(tenantId, 1);
|
|
186
|
+
const result = await this.pool.query(`SELECT ${PG_PROVIDER_COLUMNS} FROM providers WHERE ${tc.sql} ORDER BY id`, [tc.param]);
|
|
187
|
+
return result.rows.map(pgRowToProvider);
|
|
175
188
|
}
|
|
176
|
-
async
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
defaultModel: r.default_model, enabled: r.enabled,
|
|
186
|
-
createdAt: r.created_at, updatedAt: r.updated_at,
|
|
187
|
-
};
|
|
189
|
+
async get(tenantId, id) {
|
|
190
|
+
const tc = tenantClausePg(tenantId, 2);
|
|
191
|
+
const result = await this.pool.query(`SELECT ${PG_PROVIDER_COLUMNS} FROM providers WHERE id = $1 AND ${tc.sql}`, [id, tc.param]);
|
|
192
|
+
return result.rows[0] ? pgRowToProvider(result.rows[0]) : null;
|
|
193
|
+
}
|
|
194
|
+
async getByName(tenantId, name) {
|
|
195
|
+
const tc = tenantClausePg(tenantId, 2);
|
|
196
|
+
const result = await this.pool.query(`SELECT ${PG_PROVIDER_COLUMNS} FROM providers WHERE name = $1 AND ${tc.sql}`, [name, tc.param]);
|
|
197
|
+
return result.rows[0] ? pgRowToProvider(result.rows[0]) : null;
|
|
188
198
|
}
|
|
189
|
-
|
|
190
|
-
|
|
199
|
+
/**
|
|
200
|
+
* A tenant-mismatched id returns null, identical to a missing row (top
|
|
201
|
+
* risk 3, spec §4.5) — no existence oracle, no cross-tenant key leak.
|
|
202
|
+
*/
|
|
203
|
+
async getSecret(tenantId, id) {
|
|
204
|
+
const tc = tenantClausePg(tenantId, 2);
|
|
205
|
+
const result = await this.pool.query(`SELECT api_key FROM providers WHERE id = $1 AND ${tc.sql}`, [id, tc.param]);
|
|
191
206
|
return result.rows[0]?.api_key ?? null;
|
|
192
207
|
}
|
|
193
|
-
async insert(input) {
|
|
194
|
-
const result = await this.pool.query(`INSERT INTO providers (kind, name, base_url, api_key, default_model, enabled)
|
|
195
|
-
VALUES ($1, $2, $3, $4, $5, $6)
|
|
196
|
-
RETURNING id, created_at, updated_at`, [input.kind, input.name, input.baseUrl ?? null, input.apiKey ?? null, input.defaultModel ?? null, input.enabled ?? true]);
|
|
208
|
+
async insert(tenantId, input) {
|
|
209
|
+
const result = await this.pool.query(`INSERT INTO providers (kind, name, base_url, api_key, default_model, enabled, tenant_id)
|
|
210
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
211
|
+
RETURNING id, created_at, updated_at`, [input.kind, input.name, input.baseUrl ?? null, input.apiKey ?? null, input.defaultModel ?? null, input.enabled ?? true, tenantId]);
|
|
197
212
|
const row = result.rows[0];
|
|
198
213
|
if (!row)
|
|
199
214
|
throw new Error("PgProviderRegistry.insert: RETURNING yielded no row");
|
|
200
215
|
return {
|
|
201
|
-
id: row.id, kind: input.kind, name: input.name, baseUrl: input.baseUrl ?? null,
|
|
216
|
+
id: row.id, tenantId, kind: input.kind, name: input.name, baseUrl: input.baseUrl ?? null,
|
|
202
217
|
apiKey: null, hasApiKey: (input.apiKey ?? "").length > 0,
|
|
203
218
|
defaultModel: input.defaultModel ?? null, enabled: input.enabled ?? true,
|
|
204
219
|
createdAt: row.created_at, updatedAt: row.updated_at,
|
|
205
220
|
};
|
|
206
221
|
}
|
|
207
|
-
async update(id, patch) {
|
|
222
|
+
async update(tenantId, id, patch) {
|
|
208
223
|
const sets = ["updated_at = NOW()"];
|
|
209
224
|
const params = [];
|
|
210
225
|
let idx = 1;
|
|
@@ -229,13 +244,16 @@ export class PgProviderRegistry {
|
|
|
229
244
|
params.push(patch.enabled);
|
|
230
245
|
}
|
|
231
246
|
if (sets.length === 1)
|
|
232
|
-
return this.get(id);
|
|
247
|
+
return this.get(tenantId, id);
|
|
233
248
|
params.push(id);
|
|
234
|
-
|
|
235
|
-
|
|
249
|
+
const tc = tenantClausePg(tenantId, idx + 1);
|
|
250
|
+
params.push(tc.param);
|
|
251
|
+
await this.pool.query(`UPDATE providers SET ${sets.join(", ")} WHERE id = $${idx} AND ${tc.sql}`, params);
|
|
252
|
+
return this.get(tenantId, id);
|
|
236
253
|
}
|
|
237
|
-
async delete(id) {
|
|
238
|
-
const
|
|
254
|
+
async delete(tenantId, id) {
|
|
255
|
+
const tc = tenantClausePg(tenantId, 2);
|
|
256
|
+
const result = await this.pool.query(`DELETE FROM providers WHERE id = $1 AND ${tc.sql}`, [id, tc.param]);
|
|
239
257
|
return (result.rowCount ?? 0) > 0;
|
|
240
258
|
}
|
|
241
259
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-registry.js","sourceRoot":"","sources":["../../../src/core/providers/provider-registry.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"provider-registry.js","sourceRoot":"","sources":["../../../src/core/providers/provider-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,8 +4,11 @@
|
|
|
4
4
|
* future learned reranker: each row is a (query, returned_id, was_cited)
|
|
5
5
|
* triple once joined against ~/.nlm/query_log.jsonl by conversationId.
|
|
6
6
|
*
|
|
7
|
-
* Path
|
|
8
|
-
*
|
|
7
|
+
* Path is tenant-derived (core/tenancy/tenant-state-path.ts): the default
|
|
8
|
+
* team's log is ~/.nlm/citation-log.jsonl, overridable via
|
|
9
|
+
* NLM_CITATION_LOG; every other tenant is isolated under
|
|
10
|
+
* ~/.nlm/tenants/<tenantId>/citation-log.jsonl and ignores the env
|
|
11
|
+
* override. Telemetry path — never raises.
|
|
9
12
|
*/
|
|
10
13
|
export type CitationKind = "tool_use" | "prose";
|
|
11
14
|
export interface CitationEntry {
|
|
@@ -32,6 +35,8 @@ export interface CitationStats {
|
|
|
32
35
|
* The write path drops them at the source; only attributable citations land.
|
|
33
36
|
*/
|
|
34
37
|
export declare function isAttributableConversationId(id: string): boolean;
|
|
35
|
-
export declare function readCitationLog(days: number, logPath?: string): Promise<CitationEntry[]>;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
export declare function readCitationLog(tenantId: string, days: number, logPath?: string): Promise<CitationEntry[]>;
|
|
39
|
+
/** Returns whether the citation was actually written. A dropped citation must
|
|
40
|
+
* not be reported as logged — callers surface this to the agent. */
|
|
41
|
+
export declare function appendCitation(tenantId: string, entry: CitationEntry, logPath?: string): Promise<boolean>;
|
|
42
|
+
export declare function citationStats(tenantId: string, days: number, logPath?: string): Promise<CitationStats>;
|
|
@@ -4,14 +4,21 @@
|
|
|
4
4
|
* future learned reranker: each row is a (query, returned_id, was_cited)
|
|
5
5
|
* triple once joined against ~/.nlm/query_log.jsonl by conversationId.
|
|
6
6
|
*
|
|
7
|
-
* Path
|
|
8
|
-
*
|
|
7
|
+
* Path is tenant-derived (core/tenancy/tenant-state-path.ts): the default
|
|
8
|
+
* team's log is ~/.nlm/citation-log.jsonl, overridable via
|
|
9
|
+
* NLM_CITATION_LOG; every other tenant is isolated under
|
|
10
|
+
* ~/.nlm/tenants/<tenantId>/citation-log.jsonl and ignores the env
|
|
11
|
+
* override. Telemetry path — never raises.
|
|
9
12
|
*/
|
|
10
13
|
import { appendFile, mkdir, readFile, stat } from "node:fs/promises";
|
|
11
|
-
import { dirname
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
import { dirname } from "node:path";
|
|
15
|
+
import { tenantStatePath } from "../tenancy/tenant-state-path.js";
|
|
16
|
+
import { DEFAULT_TEAM_ID } from "../tenancy/default-team.js";
|
|
17
|
+
function defaultLogPath(tenantId) {
|
|
18
|
+
if (tenantId === DEFAULT_TEAM_ID) {
|
|
19
|
+
return process.env["NLM_CITATION_LOG"] ?? tenantStatePath(tenantId, "citation-log.jsonl");
|
|
20
|
+
}
|
|
21
|
+
return tenantStatePath(tenantId, "citation-log.jsonl");
|
|
15
22
|
}
|
|
16
23
|
/**
|
|
17
24
|
* A citation is only usable telemetry if it can be joined to the query fire
|
|
@@ -26,7 +33,7 @@ export function isAttributableConversationId(id) {
|
|
|
26
33
|
const lower = id.toLowerCase();
|
|
27
34
|
return lower !== "unknown" && lower !== "mcp_tool" && !/^(conv_)?test/.test(lower);
|
|
28
35
|
}
|
|
29
|
-
export async function readCitationLog(days, logPath = defaultLogPath()) {
|
|
36
|
+
export async function readCitationLog(tenantId, days, logPath = defaultLogPath(tenantId)) {
|
|
30
37
|
let raw;
|
|
31
38
|
try {
|
|
32
39
|
raw = await readFile(logPath, "utf8");
|
|
@@ -63,11 +70,13 @@ export async function readCitationLog(days, logPath = defaultLogPath()) {
|
|
|
63
70
|
}
|
|
64
71
|
return results;
|
|
65
72
|
}
|
|
66
|
-
|
|
73
|
+
/** Returns whether the citation was actually written. A dropped citation must
|
|
74
|
+
* not be reported as logged — callers surface this to the agent. */
|
|
75
|
+
export async function appendCitation(tenantId, entry, logPath = defaultLogPath(tenantId)) {
|
|
67
76
|
// Drop unattributable / fixture citations at the source so the log stays a
|
|
68
77
|
// clean training + metric substrate (see isAttributableConversationId).
|
|
69
78
|
if (!isAttributableConversationId(entry.conversationId))
|
|
70
|
-
return;
|
|
79
|
+
return false;
|
|
71
80
|
try {
|
|
72
81
|
await mkdir(dirname(logPath), { recursive: true });
|
|
73
82
|
const payload = {
|
|
@@ -80,12 +89,14 @@ export async function appendCitation(entry, logPath = defaultLogPath()) {
|
|
|
80
89
|
: {}),
|
|
81
90
|
};
|
|
82
91
|
await appendFile(logPath, JSON.stringify(payload) + "\n", "utf8");
|
|
92
|
+
return true;
|
|
83
93
|
}
|
|
84
94
|
catch {
|
|
85
95
|
// Telemetry failure must never break the call path.
|
|
96
|
+
return false;
|
|
86
97
|
}
|
|
87
98
|
}
|
|
88
|
-
export async function citationStats(days, logPath = defaultLogPath()) {
|
|
99
|
+
export async function citationStats(tenantId, days, logPath = defaultLogPath(tenantId)) {
|
|
89
100
|
const base = {
|
|
90
101
|
days,
|
|
91
102
|
total: 0,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"citation-log.js","sourceRoot":"","sources":["../../../src/core/recall/citation-log.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"citation-log.js","sourceRoot":"","sources":["../../../src/core/recall/citation-log.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,10 +8,13 @@
|
|
|
8
8
|
* The file also holds stop / session-end / pre-compact entries, which this
|
|
9
9
|
* reader ignores.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
11
|
+
* Path is tenant-derived (core/tenancy/tenant-state-path.ts): the default
|
|
12
|
+
* team reads $NLM_HOOK_LOG or ~/.nlm/hook-log.jsonl; every other tenant
|
|
13
|
+
* reads ~/.nlm/tenants/<tenantId>/hook-log.jsonl and ignores the env
|
|
14
|
+
* override. Read-only telemetry path — never raises.
|
|
12
15
|
*/
|
|
13
16
|
export interface HookRecallEntry {
|
|
14
17
|
readonly conversationId: string;
|
|
15
18
|
readonly injectedIds: ReadonlyArray<string>;
|
|
16
19
|
}
|
|
17
|
-
export declare function readHookRecallLog(days: number, logPath?: string): Promise<HookRecallEntry[]>;
|
|
20
|
+
export declare function readHookRecallLog(tenantId: string, days: number, logPath?: string): Promise<HookRecallEntry[]>;
|
|
@@ -8,15 +8,21 @@
|
|
|
8
8
|
* The file also holds stop / session-end / pre-compact entries, which this
|
|
9
9
|
* reader ignores.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
11
|
+
* Path is tenant-derived (core/tenancy/tenant-state-path.ts): the default
|
|
12
|
+
* team reads $NLM_HOOK_LOG or ~/.nlm/hook-log.jsonl; every other tenant
|
|
13
|
+
* reads ~/.nlm/tenants/<tenantId>/hook-log.jsonl and ignores the env
|
|
14
|
+
* override. Read-only telemetry path — never raises.
|
|
12
15
|
*/
|
|
13
16
|
import { readFile } from "node:fs/promises";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
function defaultLogPath() {
|
|
17
|
-
|
|
17
|
+
import { tenantStatePath } from "../tenancy/tenant-state-path.js";
|
|
18
|
+
import { DEFAULT_TEAM_ID } from "../tenancy/default-team.js";
|
|
19
|
+
function defaultLogPath(tenantId) {
|
|
20
|
+
if (tenantId === DEFAULT_TEAM_ID) {
|
|
21
|
+
return process.env["NLM_HOOK_LOG"] ?? tenantStatePath(tenantId, "hook-log.jsonl");
|
|
22
|
+
}
|
|
23
|
+
return tenantStatePath(tenantId, "hook-log.jsonl");
|
|
18
24
|
}
|
|
19
|
-
export async function readHookRecallLog(days, logPath = defaultLogPath()) {
|
|
25
|
+
export async function readHookRecallLog(tenantId, days, logPath = defaultLogPath(tenantId)) {
|
|
20
26
|
let raw;
|
|
21
27
|
try {
|
|
22
28
|
raw = await readFile(logPath, "utf8");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hook-recall-log.js","sourceRoot":"","sources":["../../../src/core/recall/hook-recall-log.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"hook-recall-log.js","sourceRoot":"","sources":["../../../src/core/recall/hook-recall-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAOhE,SAAS,cAAc,CAAC,QAAgB;IACtC,IAAI,QAAQ,KAAK,eAAe,EAAE,CAAC;QACjC,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,eAAe,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;IACpF,CAAC;IACD,OAAO,eAAe,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,QAAgB,EAChB,IAAY,EACZ,UAAkB,cAAc,CAAC,QAAQ,CAAC;IAE1C,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IACvD,MAAM,OAAO,GAAsB,EAAE,CAAC;IACtC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,SAAS;QAC3B,IAAI,GAA4B,CAAC;QACjC,IAAI,CAAC;YACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA4B,CAAC;QACpD,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;YAAE,SAAS;QACjD,IAAI,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,MAAM;YAAE,SAAS;QAC9E,MAAM,cAAc,GAAG,OAAO,GAAG,CAAC,gBAAgB,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACrG,IAAI,cAAc,KAAK,SAAS;YAAE,SAAS;QAC3C,MAAM,WAAW,GAAG,GAAG,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC;QACzF,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACvC,OAAO,CAAC,IAAI,CAAC,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
* fetched or cited but which the hook's pre-prompt recall never surfaced
|
|
4
4
|
* in this conversation. Source: Stop hook's miss-detection pass (spec E).
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* Path is tenant-derived (core/tenancy/tenant-state-path.ts): the default
|
|
7
|
+
* team's log is ~/.nlm/miss-log.jsonl, overridable via NLM_MISS_LOG; every
|
|
8
|
+
* other tenant is isolated under ~/.nlm/tenants/<tenantId>/miss-log.jsonl
|
|
9
|
+
* and ignores the env override.
|
|
7
10
|
* Disable emission entirely with NLM_MISS_LOG_ENABLED=0 — used by
|
|
8
11
|
* deployments that want recall but not telemetry. Telemetry path — never
|
|
9
12
|
* raises; failure to write is silently swallowed.
|
|
@@ -32,16 +35,16 @@ export interface MissStats {
|
|
|
32
35
|
}>;
|
|
33
36
|
readonly logPresent: boolean;
|
|
34
37
|
}
|
|
35
|
-
export declare function appendMiss(entry: MissEntry, logPath?: string): Promise<void>;
|
|
38
|
+
export declare function appendMiss(tenantId: string, entry: MissEntry, logPath?: string): Promise<void>;
|
|
36
39
|
/**
|
|
37
40
|
* Append multiple misses in one call. Each gets the same timestamp.
|
|
38
41
|
* Quieter than appendMiss × N when several misses fire in a single Stop
|
|
39
42
|
* hook invocation (which is the common case).
|
|
40
43
|
*/
|
|
41
|
-
export declare function appendMisses(entries: ReadonlyArray<MissEntry>, logPath?: string): Promise<void>;
|
|
44
|
+
export declare function appendMisses(tenantId: string, entries: ReadonlyArray<MissEntry>, logPath?: string): Promise<void>;
|
|
42
45
|
/**
|
|
43
46
|
* Read the miss log and aggregate by missedId. Used by the `nlm misses`
|
|
44
47
|
* CLI. Days filter applied at parse time. Bad lines (non-JSON or missing
|
|
45
48
|
* fields) are skipped silently.
|
|
46
49
|
*/
|
|
47
|
-
export declare function missStats(days: number, logPath?: string): Promise<MissStats>;
|
|
50
|
+
export declare function missStats(tenantId: string, days: number, logPath?: string): Promise<MissStats>;
|
|
@@ -3,16 +3,23 @@
|
|
|
3
3
|
* fetched or cited but which the hook's pre-prompt recall never surfaced
|
|
4
4
|
* in this conversation. Source: Stop hook's miss-detection pass (spec E).
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* Path is tenant-derived (core/tenancy/tenant-state-path.ts): the default
|
|
7
|
+
* team's log is ~/.nlm/miss-log.jsonl, overridable via NLM_MISS_LOG; every
|
|
8
|
+
* other tenant is isolated under ~/.nlm/tenants/<tenantId>/miss-log.jsonl
|
|
9
|
+
* and ignores the env override.
|
|
7
10
|
* Disable emission entirely with NLM_MISS_LOG_ENABLED=0 — used by
|
|
8
11
|
* deployments that want recall but not telemetry. Telemetry path — never
|
|
9
12
|
* raises; failure to write is silently swallowed.
|
|
10
13
|
*/
|
|
11
14
|
import { appendFile, mkdir, readFile, stat } from "node:fs/promises";
|
|
12
|
-
import { dirname
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
import { dirname } from "node:path";
|
|
16
|
+
import { tenantStatePath } from "../tenancy/tenant-state-path.js";
|
|
17
|
+
import { DEFAULT_TEAM_ID } from "../tenancy/default-team.js";
|
|
18
|
+
function defaultLogPath(tenantId) {
|
|
19
|
+
if (tenantId === DEFAULT_TEAM_ID) {
|
|
20
|
+
return process.env["NLM_MISS_LOG"] ?? tenantStatePath(tenantId, "miss-log.jsonl");
|
|
21
|
+
}
|
|
22
|
+
return tenantStatePath(tenantId, "miss-log.jsonl");
|
|
16
23
|
}
|
|
17
24
|
function isEnabled() {
|
|
18
25
|
const raw = process.env["NLM_MISS_LOG_ENABLED"];
|
|
@@ -20,10 +27,10 @@ function isEnabled() {
|
|
|
20
27
|
return true;
|
|
21
28
|
return raw !== "0" && raw.toLowerCase() !== "false";
|
|
22
29
|
}
|
|
23
|
-
export async function appendMiss(entry, logPath) {
|
|
30
|
+
export async function appendMiss(tenantId, entry, logPath) {
|
|
24
31
|
if (!isEnabled())
|
|
25
32
|
return;
|
|
26
|
-
const path = logPath ?? defaultLogPath();
|
|
33
|
+
const path = logPath ?? defaultLogPath(tenantId);
|
|
27
34
|
try {
|
|
28
35
|
await mkdir(dirname(path), { recursive: true });
|
|
29
36
|
const line = `${JSON.stringify({
|
|
@@ -41,12 +48,12 @@ export async function appendMiss(entry, logPath) {
|
|
|
41
48
|
* Quieter than appendMiss × N when several misses fire in a single Stop
|
|
42
49
|
* hook invocation (which is the common case).
|
|
43
50
|
*/
|
|
44
|
-
export async function appendMisses(entries, logPath) {
|
|
51
|
+
export async function appendMisses(tenantId, entries, logPath) {
|
|
45
52
|
if (!isEnabled())
|
|
46
53
|
return;
|
|
47
54
|
if (entries.length === 0)
|
|
48
55
|
return;
|
|
49
|
-
const path = logPath ?? defaultLogPath();
|
|
56
|
+
const path = logPath ?? defaultLogPath(tenantId);
|
|
50
57
|
try {
|
|
51
58
|
await mkdir(dirname(path), { recursive: true });
|
|
52
59
|
const ts = new Date().toISOString();
|
|
@@ -62,8 +69,8 @@ export async function appendMisses(entries, logPath) {
|
|
|
62
69
|
* CLI. Days filter applied at parse time. Bad lines (non-JSON or missing
|
|
63
70
|
* fields) are skipped silently.
|
|
64
71
|
*/
|
|
65
|
-
export async function missStats(days, logPath) {
|
|
66
|
-
const path = logPath ?? defaultLogPath();
|
|
72
|
+
export async function missStats(tenantId, days, logPath) {
|
|
73
|
+
const path = logPath ?? defaultLogPath(tenantId);
|
|
67
74
|
try {
|
|
68
75
|
await stat(path);
|
|
69
76
|
}
|