nlm-memory 0.20.1 → 0.21.12
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 +69 -12
- package/assets/replay-eval-dark.svg +26 -0
- package/assets/replay-eval-light.svg +26 -0
- package/dist/cli/digest.js +69 -4
- package/dist/cli/digest.js.map +1 -1
- package/dist/cli/nlm.d.ts +14 -0
- package/dist/cli/nlm.js +556 -71
- 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-backfill.d.ts +34 -0
- package/dist/cli/scope-backfill.js +237 -0
- package/dist/cli/scope-backfill.js.map +1 -0
- package/dist/cli/scope-coverage.d.ts +44 -0
- package/dist/cli/scope-coverage.js +208 -0
- package/dist/cli/scope-coverage.js.map +1 -0
- 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/claude-code.d.ts +14 -0
- package/dist/core/adapters/claude-code.js +30 -0
- package/dist/core/adapters/claude-code.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 +46 -13
- package/dist/core/dataset/build-dataset.js.map +1 -1
- package/dist/core/digest/compose.d.ts +11 -3
- package/dist/core/digest/compose.js +70 -17
- package/dist/core/digest/compose.js.map +1 -1
- package/dist/core/digest/hook-injection.d.ts +43 -0
- package/dist/core/digest/hook-injection.js +87 -0
- package/dist/core/digest/hook-injection.js.map +1 -0
- 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 +2 -1
- package/dist/core/exemplars/capture-from-session.js +4 -4
- 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/extract-exemplar.d.ts +2 -0
- package/dist/core/exemplars/extract-exemplar.js +7 -1
- package/dist/core/exemplars/extract-exemplar.js.map +1 -1
- package/dist/core/exemplars/ingest-exemplar.d.ts +1 -0
- package/dist/core/exemplars/ingest-exemplar.js +1 -0
- package/dist/core/exemplars/ingest-exemplar.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/claude-settings.d.ts +1 -1
- package/dist/core/hook/claude-settings.js +0 -1
- package/dist/core/hook/claude-settings.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/backfill-derivables.d.ts +92 -0
- package/dist/core/ingest/backfill-derivables.js +175 -0
- package/dist/core/ingest/backfill-derivables.js.map +1 -0
- package/dist/core/ingest/ingest-session.d.ts +1 -1
- package/dist/core/ingest/ingest-session.js +23 -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 +8 -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 +7 -2
- package/dist/core/ingest/reprocess.js.map +1 -1
- package/dist/core/ingest/transcript-derivables.d.ts +27 -0
- package/dist/core/ingest/transcript-derivables.js +138 -0
- package/dist/core/ingest/transcript-derivables.js.map +1 -0
- 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 +33 -0
- package/dist/core/outcome/coverage.js +46 -0
- package/dist/core/outcome/coverage.js.map +1 -0
- package/dist/core/outcome/rollup.d.ts +33 -0
- package/dist/core/outcome/rollup.js +113 -0
- package/dist/core/outcome/rollup.js.map +1 -0
- 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 +7 -4
- package/dist/core/recall/hook-recall-log.js +14 -8
- 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 +13 -12
- package/dist/core/recall-facts/fact-recall-service.js.map +1 -1
- package/dist/core/scheduler/scan-once.js +15 -12
- 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 +45 -10
- package/dist/core/scheduler/scheduler.js.map +1 -1
- package/dist/core/scope/alias-map.d.ts +10 -0
- package/dist/core/scope/alias-map.js +41 -0
- package/dist/core/scope/alias-map.js.map +1 -0
- package/dist/core/scope/derive-scope.d.ts +8 -0
- package/dist/core/scope/derive-scope.js +54 -0
- package/dist/core/scope/derive-scope.js.map +1 -0
- package/dist/core/scope/scope-clause.d.ts +16 -0
- package/dist/core/scope/scope-clause.js +21 -0
- package/dist/core/scope/scope-clause.js.map +1 -0
- package/dist/core/scope/stamp-flag.d.ts +1 -0
- package/dist/core/scope/stamp-flag.js +4 -0
- package/dist/core/scope/stamp-flag.js.map +1 -0
- package/dist/core/signals/code-signal.d.ts +1 -0
- package/dist/core/signals/code-signal.js +1 -0
- package/dist/core/signals/code-signal.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/ingest-signal.d.ts +1 -1
- package/dist/core/signals/ingest-signal.js +3 -1
- package/dist/core/signals/ingest-signal.js.map +1 -1
- package/dist/core/signals/stamp-scope.d.ts +18 -0
- package/dist/core/signals/stamp-scope.js +28 -0
- package/dist/core/signals/stamp-scope.js.map +1 -0
- 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 +62 -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 +25 -21
- package/dist/core/storage/pg-session-store.js +186 -114
- 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 +26 -13
- 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 +17 -11
- package/dist/core/storage/pg-workstream-store.js +47 -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 +86 -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 +175 -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 +104 -0
- package/dist/core/storage/sqlite-outcome-store.js +211 -0
- package/dist/core/storage/sqlite-outcome-store.js.map +1 -0
- package/dist/core/storage/sqlite-session-store.d.ts +50 -21
- package/dist/core/storage/sqlite-session-store.js +233 -149
- 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 +29 -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 +17 -11
- package/dist/core/storage/sqlite-workstream-store.js +53 -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 +21 -14
- package/dist/core/storage/supersedence-log.js.map +1 -1
- package/dist/core/telemetry/probe-filter.d.ts +35 -0
- package/dist/core/telemetry/probe-filter.js +56 -0
- package/dist/core/telemetry/probe-filter.js.map +1 -0
- 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/update-check/check.d.ts +6 -0
- package/dist/core/update-check/check.js +35 -0
- package/dist/core/update-check/check.js.map +1 -1
- 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 +3 -2
- package/dist/core/workstream/bind.js +29 -10
- package/dist/core/workstream/bind.js.map +1 -1
- package/dist/core/workstream/model.d.ts +1 -0
- package/dist/core/workstream/model.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 +8 -5
- package/dist/hook/pre-compact-hook.js.map +1 -1
- package/dist/hook/prompt-recall-hook.d.ts +7 -3
- package/dist/hook/prompt-recall-hook.js +35 -20
- package/dist/hook/prompt-recall-hook.js.map +1 -1
- package/dist/hook/recall-over-http.d.ts +28 -3
- package/dist/hook/recall-over-http.js +58 -12
- 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 +57 -16
- package/dist/hook/session-start-hook.js.map +1 -1
- package/dist/hook/stop-hook.js +11 -8
- package/dist/hook/stop-hook.js.map +1 -1
- package/dist/http/app.d.ts +47 -3
- package/dist/http/app.js +379 -132
- 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 +94 -15
- package/dist/mcp/server.js +402 -79
- 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 +85 -0
- package/dist/ports/outcome.js +11 -0
- package/dist/ports/outcome.js.map +1 -0
- package/dist/ports/session-store.d.ts +20 -20
- 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 +20 -12
- package/dist/shared/net.d.ts +3 -0
- package/dist/shared/net.js +4 -0
- package/dist/shared/net.js.map +1 -0
- package/dist/shared/types.d.ts +55 -0
- package/dist/shared/types.js +4 -1
- 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/029_project_scope.sql +21 -0
- package/migrations/032_session_derivables.sql +11 -0
- 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/030_project_scope.sql +23 -0
- package/migrations/pg/031_widen_session_edges_kind.sql +11 -0
- package/migrations/pg/032_session_derivables.sql +17 -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 +258 -59
- package/package.json +10 -5
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/scripts/prompt-recall-hook.mjs +256 -58
- package/plugin/scripts/session-start-hook.mjs +283 -55
- package/plugin/scripts/stop-hook.mjs +199 -38
- package/dist/hook/subagent-start-hook.d.ts +0 -28
- package/dist/hook/subagent-start-hook.js +0 -81
- package/dist/hook/subagent-start-hook.js.map +0 -1
- package/dist/ui/assets/index-CMpQkbQy.js +0 -11
|
@@ -4,10 +4,13 @@
|
|
|
4
4
|
* supersedence at ingest time is not logged here — that lineage is already
|
|
5
5
|
* implicit in the session_edges row's predecessor reference.
|
|
6
6
|
*
|
|
7
|
-
* Path
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* Path is tenant-derived (core/tenancy/tenant-state-path.ts): the default
|
|
8
|
+
* team's log is ~/.nlm/supersedence-log.jsonl, overridable via
|
|
9
|
+
* NLM_SUPERSEDENCE_LOG; every other tenant is isolated under
|
|
10
|
+
* ~/.nlm/tenants/<tenantId>/supersedence-log.jsonl and ignores the env
|
|
11
|
+
* override. Telemetry path — never raises, but on failure it emits one
|
|
12
|
+
* warning line to stderr so a silent disk-full or permission issue doesn't
|
|
13
|
+
* leave the operator believing their audit trail is intact.
|
|
11
14
|
*/
|
|
12
15
|
export interface SupersedenceEntry {
|
|
13
16
|
readonly predecessorId: string;
|
|
@@ -16,7 +19,7 @@ export interface SupersedenceEntry {
|
|
|
16
19
|
readonly source?: string;
|
|
17
20
|
}
|
|
18
21
|
/** Read all supersedence log entries. Never raises — returns [] on missing file. */
|
|
19
|
-
export declare function readSupersedenceLog(): Promise<ReadonlyArray<SupersedenceEntry & {
|
|
22
|
+
export declare function readSupersedenceLog(tenantId: string, logPath?: string): Promise<ReadonlyArray<SupersedenceEntry & {
|
|
20
23
|
ts: string;
|
|
21
24
|
source?: string;
|
|
22
25
|
}>>;
|
|
@@ -27,5 +30,5 @@ export interface FactSupersedenceEntry {
|
|
|
27
30
|
}
|
|
28
31
|
/** Append a fact-level supersedence event to the shared audit JSONL.
|
|
29
32
|
* Entries carry `kind: "fact"` so the session-scoped reader skips them. */
|
|
30
|
-
export declare function appendFactSupersedence(entry: FactSupersedenceEntry, logPath?: string): Promise<void>;
|
|
31
|
-
export declare function appendSupersedence(entry: SupersedenceEntry, logPath?: string): Promise<void>;
|
|
33
|
+
export declare function appendFactSupersedence(tenantId: string, entry: FactSupersedenceEntry, logPath?: string): Promise<void>;
|
|
34
|
+
export declare function appendSupersedence(tenantId: string, entry: SupersedenceEntry, logPath?: string): Promise<void>;
|
|
@@ -4,26 +4,32 @@
|
|
|
4
4
|
* supersedence at ingest time is not logged here — that lineage is already
|
|
5
5
|
* implicit in the session_edges row's predecessor reference.
|
|
6
6
|
*
|
|
7
|
-
* Path
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* Path is tenant-derived (core/tenancy/tenant-state-path.ts): the default
|
|
8
|
+
* team's log is ~/.nlm/supersedence-log.jsonl, overridable via
|
|
9
|
+
* NLM_SUPERSEDENCE_LOG; every other tenant is isolated under
|
|
10
|
+
* ~/.nlm/tenants/<tenantId>/supersedence-log.jsonl and ignores the env
|
|
11
|
+
* override. Telemetry path — never raises, but on failure it emits one
|
|
12
|
+
* warning line to stderr so a silent disk-full or permission issue doesn't
|
|
13
|
+
* leave the operator believing their audit trail is intact.
|
|
11
14
|
*/
|
|
12
15
|
import { appendFile, mkdir, readFile } from "node:fs/promises";
|
|
13
|
-
import { dirname
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
import { dirname } from "node:path";
|
|
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_SUPERSEDENCE_LOG"] ?? tenantStatePath(tenantId, "supersedence-log.jsonl");
|
|
22
|
+
}
|
|
23
|
+
return tenantStatePath(tenantId, "supersedence-log.jsonl");
|
|
18
24
|
}
|
|
19
25
|
/** Read all supersedence log entries. Never raises — returns [] on missing file. */
|
|
20
|
-
export async function readSupersedenceLog() {
|
|
21
|
-
const path = defaultLogPath();
|
|
26
|
+
export async function readSupersedenceLog(tenantId, logPath = defaultLogPath(tenantId)) {
|
|
22
27
|
let raw;
|
|
23
28
|
try {
|
|
24
|
-
raw = await readFile(
|
|
29
|
+
raw = await readFile(logPath, "utf8");
|
|
25
30
|
}
|
|
26
31
|
catch {
|
|
32
|
+
// Log file missing or unreadable - no supersedence history recovered.
|
|
27
33
|
return [];
|
|
28
34
|
}
|
|
29
35
|
const results = [];
|
|
@@ -44,6 +50,7 @@ export async function readSupersedenceLog() {
|
|
|
44
50
|
});
|
|
45
51
|
}
|
|
46
52
|
catch {
|
|
53
|
+
// Malformed entry in log - skip and continue parsing.
|
|
47
54
|
continue;
|
|
48
55
|
}
|
|
49
56
|
}
|
|
@@ -51,7 +58,7 @@ export async function readSupersedenceLog() {
|
|
|
51
58
|
}
|
|
52
59
|
/** Append a fact-level supersedence event to the shared audit JSONL.
|
|
53
60
|
* Entries carry `kind: "fact"` so the session-scoped reader skips them. */
|
|
54
|
-
export async function appendFactSupersedence(entry, logPath = defaultLogPath()) {
|
|
61
|
+
export async function appendFactSupersedence(tenantId, entry, logPath = defaultLogPath(tenantId)) {
|
|
55
62
|
try {
|
|
56
63
|
await mkdir(dirname(logPath), { recursive: true });
|
|
57
64
|
const payload = {
|
|
@@ -68,7 +75,7 @@ export async function appendFactSupersedence(entry, logPath = defaultLogPath())
|
|
|
68
75
|
process.stderr.write(`nlm-memory: failed to append fact-supersedence-log entry at ${logPath}: ${msg}\n`);
|
|
69
76
|
}
|
|
70
77
|
}
|
|
71
|
-
export async function appendSupersedence(entry, logPath = defaultLogPath()) {
|
|
78
|
+
export async function appendSupersedence(tenantId, entry, logPath = defaultLogPath(tenantId)) {
|
|
72
79
|
try {
|
|
73
80
|
await mkdir(dirname(logPath), { recursive: true });
|
|
74
81
|
const payload = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"supersedence-log.js","sourceRoot":"","sources":["../../../src/core/storage/supersedence-log.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"supersedence-log.js","sourceRoot":"","sources":["../../../src/core/storage/supersedence-log.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Probe and test traffic filter.
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for classifying recall queries as probe/test traffic.
|
|
5
|
+
* Used by the digest composer (to strip probes from displayed counters) and by
|
|
6
|
+
* the pull-usefulness eval script (to strip probes from the scored baseline).
|
|
7
|
+
*
|
|
8
|
+
* Two match strategies with different trade-offs:
|
|
9
|
+
*
|
|
10
|
+
* Substring match (PROBE_SUBSTRINGS / isProbe):
|
|
11
|
+
* Catches probe traffic regardless of surrounding words. Accepted trade-off:
|
|
12
|
+
* any query containing the word "probe" -- including "how did we probe the API"
|
|
13
|
+
* -- will be stripped. In practice, probe traffic is always labelled with the
|
|
14
|
+
* bare word; real agent queries rarely include "probe" as a term. The
|
|
15
|
+
* alternative (exact-match "probe") would miss operational variants like
|
|
16
|
+
* "system probe" and "probing X", so substring is the right default for the
|
|
17
|
+
* digest composer path.
|
|
18
|
+
*
|
|
19
|
+
* Exact match (PROBE_EXACT_QUERIES):
|
|
20
|
+
* Required for pull-usefulness.ts. That script was baseline-calibrated at
|
|
21
|
+
* 72.4% genuine-pull using this exact set. Switching it to substring matching
|
|
22
|
+
* would silently change the denominator and invalidate historical comparisons.
|
|
23
|
+
* "x" and "" cannot be substring-matched -- a single character would strip
|
|
24
|
+
* virtually every query. They live here as exact entries only.
|
|
25
|
+
*/
|
|
26
|
+
/** Substrings that mark a recall query as probe/test traffic. */
|
|
27
|
+
export declare const PROBE_SUBSTRINGS: ReadonlyArray<string>;
|
|
28
|
+
/**
|
|
29
|
+
* Queries that are probe traffic only when the full query (trimmed, lowercased)
|
|
30
|
+
* is an exact match. "x" and "" are single-character or empty -- substring
|
|
31
|
+
* matching them would strip real queries.
|
|
32
|
+
*/
|
|
33
|
+
export declare const PROBE_EXACT_QUERIES: ReadonlySet<string>;
|
|
34
|
+
/** True when the query is recognisably probe/test traffic by either strategy. */
|
|
35
|
+
export declare function isProbe(query: string | null | undefined): boolean;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Probe and test traffic filter.
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for classifying recall queries as probe/test traffic.
|
|
5
|
+
* Used by the digest composer (to strip probes from displayed counters) and by
|
|
6
|
+
* the pull-usefulness eval script (to strip probes from the scored baseline).
|
|
7
|
+
*
|
|
8
|
+
* Two match strategies with different trade-offs:
|
|
9
|
+
*
|
|
10
|
+
* Substring match (PROBE_SUBSTRINGS / isProbe):
|
|
11
|
+
* Catches probe traffic regardless of surrounding words. Accepted trade-off:
|
|
12
|
+
* any query containing the word "probe" -- including "how did we probe the API"
|
|
13
|
+
* -- will be stripped. In practice, probe traffic is always labelled with the
|
|
14
|
+
* bare word; real agent queries rarely include "probe" as a term. The
|
|
15
|
+
* alternative (exact-match "probe") would miss operational variants like
|
|
16
|
+
* "system probe" and "probing X", so substring is the right default for the
|
|
17
|
+
* digest composer path.
|
|
18
|
+
*
|
|
19
|
+
* Exact match (PROBE_EXACT_QUERIES):
|
|
20
|
+
* Required for pull-usefulness.ts. That script was baseline-calibrated at
|
|
21
|
+
* 72.4% genuine-pull using this exact set. Switching it to substring matching
|
|
22
|
+
* would silently change the denominator and invalidate historical comparisons.
|
|
23
|
+
* "x" and "" cannot be substring-matched -- a single character would strip
|
|
24
|
+
* virtually every query. They live here as exact entries only.
|
|
25
|
+
*/
|
|
26
|
+
/** Substrings that mark a recall query as probe/test traffic. */
|
|
27
|
+
export const PROBE_SUBSTRINGS = [
|
|
28
|
+
// "concurrency probe" and "test probe" are redundant: "probe" covers both.
|
|
29
|
+
"probe",
|
|
30
|
+
"beacon",
|
|
31
|
+
"smoke",
|
|
32
|
+
"path test",
|
|
33
|
+
"recall test",
|
|
34
|
+
"cutover-test",
|
|
35
|
+
];
|
|
36
|
+
/**
|
|
37
|
+
* Queries that are probe traffic only when the full query (trimmed, lowercased)
|
|
38
|
+
* is an exact match. "x" and "" are single-character or empty -- substring
|
|
39
|
+
* matching them would strip real queries.
|
|
40
|
+
*/
|
|
41
|
+
export const PROBE_EXACT_QUERIES = new Set([
|
|
42
|
+
"pgvector",
|
|
43
|
+
"hono",
|
|
44
|
+
"x",
|
|
45
|
+
"",
|
|
46
|
+
]);
|
|
47
|
+
/** True when the query is recognisably probe/test traffic by either strategy. */
|
|
48
|
+
export function isProbe(query) {
|
|
49
|
+
if (query === null || query === undefined)
|
|
50
|
+
return false;
|
|
51
|
+
const q = query.trim().toLowerCase();
|
|
52
|
+
if (PROBE_EXACT_QUERIES.has(q))
|
|
53
|
+
return true;
|
|
54
|
+
return PROBE_SUBSTRINGS.some((p) => q.includes(p));
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=probe-filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"probe-filter.js","sourceRoot":"","sources":["../../../src/core/telemetry/probe-filter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,iEAAiE;AACjE,MAAM,CAAC,MAAM,gBAAgB,GAA0B;IACrD,2EAA2E;IAC3E,OAAO;IACP,QAAQ;IACR,OAAO;IACP,WAAW;IACX,aAAa;IACb,cAAc;CACf,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAwB,IAAI,GAAG,CAAC;IAC9D,UAAU;IACV,MAAM;IACN,GAAG;IACH,EAAE;CACH,CAAC,CAAC;AAEH,iFAAiF;AACjF,MAAM,UAAU,OAAO,CAAC,KAAgC;IACtD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACxD,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,IAAI,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5C,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fixed id of the single-tenant local deployment's team, seeded by
|
|
3
|
+
* migrations 034 (both lanes). A literal — never generated — so it can appear
|
|
4
|
+
* in sqlite column DEFAULTs (tenancy design doc, kept privately in .superpowers/).
|
|
5
|
+
*/
|
|
6
|
+
export declare const DEFAULT_TEAM_ID = "team_local";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fixed id of the single-tenant local deployment's team, seeded by
|
|
3
|
+
* migrations 034 (both lanes). A literal — never generated — so it can appear
|
|
4
|
+
* in sqlite column DEFAULTs (tenancy design doc, kept privately in .superpowers/).
|
|
5
|
+
*/
|
|
6
|
+
export const DEFAULT_TEAM_ID = "team_local";
|
|
7
|
+
//# sourceMappingURL=default-team.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"default-team.js","sourceRoot":"","sources":["../../../src/core/tenancy/default-team.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,YAAY,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NLM_HOSTED=1 switches the daemon to hosted posture. Under hosted mode,
|
|
3
|
+
* LOCAL-dispositioned routes (whole-DB dataset/backup/restore/stats,
|
|
4
|
+
* process-global classifier swap) and M6-FILTER routes (citation events,
|
|
5
|
+
* recall/facts stats+recent, hook-memo trio — file-state surfaces not yet
|
|
6
|
+
* tenant-attributed) return 403 before touching any handler (program spec
|
|
7
|
+
* §4.6). Local mode (the default, no env set) is unaffected.
|
|
8
|
+
*/
|
|
9
|
+
export declare function isHostedMode(): boolean;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NLM_HOSTED=1 switches the daemon to hosted posture. Under hosted mode,
|
|
3
|
+
* LOCAL-dispositioned routes (whole-DB dataset/backup/restore/stats,
|
|
4
|
+
* process-global classifier swap) and M6-FILTER routes (citation events,
|
|
5
|
+
* recall/facts stats+recent, hook-memo trio — file-state surfaces not yet
|
|
6
|
+
* tenant-attributed) return 403 before touching any handler (program spec
|
|
7
|
+
* §4.6). Local mode (the default, no env set) is unaffected.
|
|
8
|
+
*/
|
|
9
|
+
export function isHostedMode() {
|
|
10
|
+
return process.env["NLM_HOSTED"] === "1";
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=hosted-mode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hosted-mode.js","sourceRoot":"","sources":["../../../src/core/tenancy/hosted-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,GAAG,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* resolveTeamByToken — the one auth-only tenant-resolution function every
|
|
3
|
+
* gated network transport routes through (program spec §3: "The tenant is
|
|
4
|
+
* resolved from the authenticated credential and from nothing else").
|
|
5
|
+
*
|
|
6
|
+
* Mechanism: sha256-hex the presented bearer token, look up
|
|
7
|
+
* `team_tokens WHERE token_hash = $hash AND revoked_at IS NULL`, return the
|
|
8
|
+
* team_id. No ambient derivation, no request parameter, no fallback chain —
|
|
9
|
+
* a token that doesn't resolve returns null and the caller denies.
|
|
10
|
+
*/
|
|
11
|
+
import type { TeamTokenStorePort } from "./team-token-store.js";
|
|
12
|
+
export interface ResolvedTeam {
|
|
13
|
+
readonly teamId: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function hashTeamToken(token: string): string;
|
|
16
|
+
export declare function resolveTeamByToken(store: TeamTokenStorePort, presentedToken: string | undefined | null): Promise<ResolvedTeam | null>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* resolveTeamByToken — the one auth-only tenant-resolution function every
|
|
3
|
+
* gated network transport routes through (program spec §3: "The tenant is
|
|
4
|
+
* resolved from the authenticated credential and from nothing else").
|
|
5
|
+
*
|
|
6
|
+
* Mechanism: sha256-hex the presented bearer token, look up
|
|
7
|
+
* `team_tokens WHERE token_hash = $hash AND revoked_at IS NULL`, return the
|
|
8
|
+
* team_id. No ambient derivation, no request parameter, no fallback chain —
|
|
9
|
+
* a token that doesn't resolve returns null and the caller denies.
|
|
10
|
+
*/
|
|
11
|
+
import { createHash } from "node:crypto";
|
|
12
|
+
export function hashTeamToken(token) {
|
|
13
|
+
return createHash("sha256").update(token, "utf8").digest("hex");
|
|
14
|
+
}
|
|
15
|
+
export async function resolveTeamByToken(store, presentedToken) {
|
|
16
|
+
if (!presentedToken)
|
|
17
|
+
return null;
|
|
18
|
+
const hash = hashTeamToken(presentedToken);
|
|
19
|
+
const row = await store.findActiveByHash(hash);
|
|
20
|
+
return row ? { teamId: row.teamId } : null;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=team-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-auth.js","sourceRoot":"","sources":["../../../src/core/tenancy/team-auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAOzC,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,KAAyB,EACzB,cAAyC;IAEzC,IAAI,CAAC,cAAc;QAAE,OAAO,IAAI,CAAC;IACjC,MAAM,IAAI,GAAG,aAAa,CAAC,cAAc,CAAC,CAAC;IAC3C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC/C,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TeamTokenStore / PgTeamTokenStore — CRUD over the `team_tokens` table
|
|
3
|
+
* (program spec §2 M1, §3 M3). This IS the tenancy registry, not corpus
|
|
4
|
+
* data: methods take no `tenantId` param by design, same pinned exception as
|
|
5
|
+
* SourceRegistry.findByToken (src/core/sources/source-registry.ts) — the
|
|
6
|
+
* whole point of this store is to RESOLVE a tenant from a presented token,
|
|
7
|
+
* not to be scoped by one. team_tokens is TENANT-NEUTRAL and exempt from the
|
|
8
|
+
* tenantClause guard (tests/integration/tenant-guard.test.ts) for the same
|
|
9
|
+
* reason findByToken is exempt.
|
|
10
|
+
*/
|
|
11
|
+
import type Database from "better-sqlite3";
|
|
12
|
+
import type { Pool } from "pg";
|
|
13
|
+
export interface ResolvedTeamToken {
|
|
14
|
+
readonly teamId: string;
|
|
15
|
+
}
|
|
16
|
+
export interface TeamTokenStorePort {
|
|
17
|
+
/** AUTH lookup: resolves an active (non-revoked) token hash to its team. */
|
|
18
|
+
findActiveByHash(hash: string): Promise<ResolvedTeamToken | null>;
|
|
19
|
+
insert(hash: string, teamId: string): Promise<void>;
|
|
20
|
+
revoke(hash: string): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Idempotent insert-if-absent. Used for local-mode boot continuity (M3
|
|
23
|
+
* §3): an existing NLM_MCP_TOKEN's hash is seeded once for the default
|
|
24
|
+
* team so it keeps authenticating through the same resolveTeamByToken
|
|
25
|
+
* path as any future per-team token. A no-op if the hash already has a
|
|
26
|
+
* row (active OR revoked) — never resurrects a deliberately revoked token.
|
|
27
|
+
*/
|
|
28
|
+
ensureActive(hash: string, teamId: string): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
export declare class TeamTokenStore implements TeamTokenStorePort {
|
|
31
|
+
private readonly db;
|
|
32
|
+
constructor(db: Database.Database);
|
|
33
|
+
findActiveByHash(hash: string): Promise<ResolvedTeamToken | null>;
|
|
34
|
+
insert(hash: string, teamId: string): Promise<void>;
|
|
35
|
+
revoke(hash: string): Promise<void>;
|
|
36
|
+
ensureActive(hash: string, teamId: string): Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
export declare class PgTeamTokenStore implements TeamTokenStorePort {
|
|
39
|
+
private readonly pool;
|
|
40
|
+
constructor(pool: Pool);
|
|
41
|
+
findActiveByHash(hash: string): Promise<ResolvedTeamToken | null>;
|
|
42
|
+
insert(hash: string, teamId: string): Promise<void>;
|
|
43
|
+
revoke(hash: string): Promise<void>;
|
|
44
|
+
ensureActive(hash: string, teamId: string): Promise<void>;
|
|
45
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TeamTokenStore / PgTeamTokenStore — CRUD over the `team_tokens` table
|
|
3
|
+
* (program spec §2 M1, §3 M3). This IS the tenancy registry, not corpus
|
|
4
|
+
* data: methods take no `tenantId` param by design, same pinned exception as
|
|
5
|
+
* SourceRegistry.findByToken (src/core/sources/source-registry.ts) — the
|
|
6
|
+
* whole point of this store is to RESOLVE a tenant from a presented token,
|
|
7
|
+
* not to be scoped by one. team_tokens is TENANT-NEUTRAL and exempt from the
|
|
8
|
+
* tenantClause guard (tests/integration/tenant-guard.test.ts) for the same
|
|
9
|
+
* reason findByToken is exempt.
|
|
10
|
+
*/
|
|
11
|
+
export class TeamTokenStore {
|
|
12
|
+
db;
|
|
13
|
+
constructor(db) {
|
|
14
|
+
this.db = db;
|
|
15
|
+
}
|
|
16
|
+
async findActiveByHash(hash) {
|
|
17
|
+
const row = this.db.prepare("SELECT team_id FROM team_tokens WHERE token_hash = ? AND revoked_at IS NULL").get(hash);
|
|
18
|
+
return row ? { teamId: row.team_id } : null;
|
|
19
|
+
}
|
|
20
|
+
async insert(hash, teamId) {
|
|
21
|
+
this.db.prepare("INSERT INTO team_tokens (token_hash, team_id) VALUES (?, ?)").run(hash, teamId);
|
|
22
|
+
}
|
|
23
|
+
async revoke(hash) {
|
|
24
|
+
this.db.prepare("UPDATE team_tokens SET revoked_at = datetime('now') WHERE token_hash = ?").run(hash);
|
|
25
|
+
}
|
|
26
|
+
async ensureActive(hash, teamId) {
|
|
27
|
+
const existing = this.db.prepare("SELECT token_hash FROM team_tokens WHERE token_hash = ?").get(hash);
|
|
28
|
+
if (existing)
|
|
29
|
+
return;
|
|
30
|
+
await this.insert(hash, teamId);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export class PgTeamTokenStore {
|
|
34
|
+
pool;
|
|
35
|
+
constructor(pool) {
|
|
36
|
+
this.pool = pool;
|
|
37
|
+
}
|
|
38
|
+
async findActiveByHash(hash) {
|
|
39
|
+
const result = await this.pool.query("SELECT team_id FROM team_tokens WHERE token_hash = $1 AND revoked_at IS NULL", [hash]);
|
|
40
|
+
return result.rows[0] ? { teamId: result.rows[0].team_id } : null;
|
|
41
|
+
}
|
|
42
|
+
async insert(hash, teamId) {
|
|
43
|
+
await this.pool.query("INSERT INTO team_tokens (token_hash, team_id) VALUES ($1, $2)", [hash, teamId]);
|
|
44
|
+
}
|
|
45
|
+
async revoke(hash) {
|
|
46
|
+
await this.pool.query("UPDATE team_tokens SET revoked_at = NOW() WHERE token_hash = $1", [hash]);
|
|
47
|
+
}
|
|
48
|
+
async ensureActive(hash, teamId) {
|
|
49
|
+
await this.pool.query("INSERT INTO team_tokens (token_hash, team_id) VALUES ($1, $2) ON CONFLICT (token_hash) DO NOTHING", [hash, teamId]);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=team-token-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-token-store.js","sourceRoot":"","sources":["../../../src/core/tenancy/team-token-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA4BH,MAAM,OAAO,cAAc;IACI;IAA7B,YAA6B,EAAqB;QAArB,OAAE,GAAF,EAAE,CAAmB;IAAG,CAAC;IAEtD,KAAK,CAAC,gBAAgB,CAAC,IAAY;QACjC,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CACzB,6EAA6E,CAC9E,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACZ,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAY,EAAE,MAAc;QACvC,IAAI,CAAC,EAAE,CAAC,OAAO,CACb,6DAA6D,CAC9D,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAY;QACvB,IAAI,CAAC,EAAE,CAAC,OAAO,CACb,0EAA0E,CAC3E,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACd,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,IAAY,EAAE,MAAc;QAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAC9B,yDAAyD,CAC1D,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACZ,IAAI,QAAQ;YAAE,OAAO;QACrB,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAClC,CAAC;CACF;AAED,MAAM,OAAO,gBAAgB;IACE;IAA7B,YAA6B,IAAU;QAAV,SAAI,GAAJ,IAAI,CAAM;IAAG,CAAC;IAE3C,KAAK,CAAC,gBAAgB,CAAC,IAAY;QACjC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAClC,8EAA8E,EAC9E,CAAC,IAAI,CAAC,CACP,CAAC;QACF,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACpE,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAY,EAAE,MAAc;QACvC,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CACnB,+DAA+D,EAC/D,CAAC,IAAI,EAAE,MAAM,CAAC,CACf,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAY;QACvB,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CACnB,iEAAiE,EACjE,CAAC,IAAI,CAAC,CACP,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,IAAY,EAAE,MAAc;QAC7C,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CACnB,mGAAmG,EACnG,CAAC,IAAI,EAAE,MAAM,CAAC,CACf,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tenantClause / tenantClausePg — the single WHERE-fragment builder every
|
|
3
|
+
* corpus SQL string routes through (program spec §4.2). Wave C's guard test
|
|
4
|
+
* (tests/integration/tenant-guard.test.ts) scans src/core/storage/*.ts,
|
|
5
|
+
* actions-log.ts, build-dataset.ts, and http/app.ts for the literal text
|
|
6
|
+
* `tenant_id =`; the invariant this file exists to hold is that the literal
|
|
7
|
+
* appears ONLY here (migrations excepted).
|
|
8
|
+
*
|
|
9
|
+
* Two entry points because the two backends bind params differently, and
|
|
10
|
+
* both existing store idioms build a WHERE clause the same way — a
|
|
11
|
+
* `where: string[]` of fragments joined with " AND ", pushed alongside a
|
|
12
|
+
* parallel `params: unknown[]` array (see SqliteFactStore.list / .listBySessions,
|
|
13
|
+
* PgFactStore.list) — so a helper that returns one `{sql, param}` pair slots
|
|
14
|
+
* directly into that pattern for both:
|
|
15
|
+
*
|
|
16
|
+
* sqlite (better-sqlite3, positional `?`):
|
|
17
|
+
* const c = tenantClause(tenantId);
|
|
18
|
+
* where.push(c.sql); params.push(c.param);
|
|
19
|
+
*
|
|
20
|
+
* pg (node-postgres, numbered `$n`, tracked via a running `idx`):
|
|
21
|
+
* const c = tenantClausePg(tenantId, idx++);
|
|
22
|
+
* where.push(c.sql); params.push(c.param);
|
|
23
|
+
*
|
|
24
|
+
* For single-fragment templates (SqliteSessionStore.getById et al., built as
|
|
25
|
+
* a fixed template literal rather than a where[]/params[] pair), the fragment
|
|
26
|
+
* still composes: interpolate `c.sql` at the right spot in the template and
|
|
27
|
+
* append `c.param` to the positional argument list in the matching order.
|
|
28
|
+
*
|
|
29
|
+
* `column` defaults to the bare column name but accepts an alias-qualified
|
|
30
|
+
* form (e.g. "s.tenant_id") for joined queries.
|
|
31
|
+
*/
|
|
32
|
+
export interface TenantClause {
|
|
33
|
+
readonly sql: string;
|
|
34
|
+
readonly param: string;
|
|
35
|
+
}
|
|
36
|
+
export declare function tenantClause(tenantId: string, column?: string): TenantClause;
|
|
37
|
+
export declare function tenantClausePg(tenantId: string, paramIndex: number, column?: string): TenantClause;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function tenantClause(tenantId, column = "tenant_id") {
|
|
2
|
+
if (!tenantId)
|
|
3
|
+
throw new Error("tenantClause: tenantId is required");
|
|
4
|
+
return { sql: `${column} = ?`, param: tenantId };
|
|
5
|
+
}
|
|
6
|
+
export function tenantClausePg(tenantId, paramIndex, column = "tenant_id") {
|
|
7
|
+
if (!tenantId)
|
|
8
|
+
throw new Error("tenantClausePg: tenantId is required");
|
|
9
|
+
return { sql: `${column} = $${paramIndex}`, param: tenantId };
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=tenant-clause.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenant-clause.js","sourceRoot":"","sources":["../../../src/core/tenancy/tenant-clause.ts"],"names":[],"mappings":"AAoCA,MAAM,UAAU,YAAY,CAAC,QAAgB,EAAE,MAAM,GAAG,WAAW;IACjE,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACrE,OAAO,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,UAAkB,EAAE,MAAM,GAAG,WAAW;IACvF,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IACvE,OAAO,EAAE,GAAG,EAAE,GAAG,MAAM,OAAO,UAAU,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AAChE,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path derivation for the shared file-state modules (hook memo, hook log,
|
|
3
|
+
* query/citation/miss logs — the JSONL/JSON telemetry that predates
|
|
4
|
+
* per-tenant SQLite rows). The default team's paths are byte-identical to
|
|
5
|
+
* the pre-M6 layout (~/.nlm/<segments>); every other tenant is isolated
|
|
6
|
+
* under ~/.nlm/tenants/<sanitized-tenantId>/<same segments>, so file state
|
|
7
|
+
* stops leaking across tenants the way a shared ~/.nlm/query_log.jsonl did.
|
|
8
|
+
*
|
|
9
|
+
* Sanitization mirrors the conversation-id rule in core/hook/memo.ts
|
|
10
|
+
* ([^A-Za-z0-9_-] -> "_", with "unknown" as the fallback for an id that
|
|
11
|
+
* sanitizes to nothing) but is not injective on its own — "acme.co" and
|
|
12
|
+
* "acme_co" both sanitize to "acme_co", which would collide the two
|
|
13
|
+
* tenants' directories. An id already safe (matches [A-Za-z0-9_-]+) is used
|
|
14
|
+
* as-is; any other id gets the sanitized form plus an 8-hex-char sha256
|
|
15
|
+
* digest of the *raw* (pre-sanitization) id appended, so two ids that
|
|
16
|
+
* collide after sanitization always land in distinct directories.
|
|
17
|
+
*
|
|
18
|
+
* NLM_STATE_ROOT overrides the ~/.nlm base directory for every tenant,
|
|
19
|
+
* default team included (the two branches below share the same `base`).
|
|
20
|
+
* This is a root move, not a per-tenant redirect: it does not reintroduce
|
|
21
|
+
* the leak the per-file overrides (NLM_QUERY_LOG et al., which apply to the
|
|
22
|
+
* default team's file only) were scoped away from — every tenant's
|
|
23
|
+
* directory keeps moving together under the new root, so isolation between
|
|
24
|
+
* tenants is unaffected. Test-only; production leaves it unset.
|
|
25
|
+
*/
|
|
26
|
+
export declare const TENANTS_DIRNAME = "tenants";
|
|
27
|
+
/** ~/.nlm/<segments> for the default team; ~/.nlm/tenants/<t>/<segments> otherwise. */
|
|
28
|
+
export declare function tenantStatePath(tenantId: string, ...segments: string[]): string;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path derivation for the shared file-state modules (hook memo, hook log,
|
|
3
|
+
* query/citation/miss logs — the JSONL/JSON telemetry that predates
|
|
4
|
+
* per-tenant SQLite rows). The default team's paths are byte-identical to
|
|
5
|
+
* the pre-M6 layout (~/.nlm/<segments>); every other tenant is isolated
|
|
6
|
+
* under ~/.nlm/tenants/<sanitized-tenantId>/<same segments>, so file state
|
|
7
|
+
* stops leaking across tenants the way a shared ~/.nlm/query_log.jsonl did.
|
|
8
|
+
*
|
|
9
|
+
* Sanitization mirrors the conversation-id rule in core/hook/memo.ts
|
|
10
|
+
* ([^A-Za-z0-9_-] -> "_", with "unknown" as the fallback for an id that
|
|
11
|
+
* sanitizes to nothing) but is not injective on its own — "acme.co" and
|
|
12
|
+
* "acme_co" both sanitize to "acme_co", which would collide the two
|
|
13
|
+
* tenants' directories. An id already safe (matches [A-Za-z0-9_-]+) is used
|
|
14
|
+
* as-is; any other id gets the sanitized form plus an 8-hex-char sha256
|
|
15
|
+
* digest of the *raw* (pre-sanitization) id appended, so two ids that
|
|
16
|
+
* collide after sanitization always land in distinct directories.
|
|
17
|
+
*
|
|
18
|
+
* NLM_STATE_ROOT overrides the ~/.nlm base directory for every tenant,
|
|
19
|
+
* default team included (the two branches below share the same `base`).
|
|
20
|
+
* This is a root move, not a per-tenant redirect: it does not reintroduce
|
|
21
|
+
* the leak the per-file overrides (NLM_QUERY_LOG et al., which apply to the
|
|
22
|
+
* default team's file only) were scoped away from — every tenant's
|
|
23
|
+
* directory keeps moving together under the new root, so isolation between
|
|
24
|
+
* tenants is unaffected. Test-only; production leaves it unset.
|
|
25
|
+
*/
|
|
26
|
+
import { createHash } from "node:crypto";
|
|
27
|
+
import { homedir } from "node:os";
|
|
28
|
+
import { join } from "node:path";
|
|
29
|
+
import { DEFAULT_TEAM_ID } from "./default-team.js";
|
|
30
|
+
export const TENANTS_DIRNAME = "tenants";
|
|
31
|
+
const SAFE_TENANT_ID = /^[A-Za-z0-9_-]+$/;
|
|
32
|
+
function sanitizeTenantId(tenantId) {
|
|
33
|
+
if (SAFE_TENANT_ID.test(tenantId))
|
|
34
|
+
return tenantId;
|
|
35
|
+
const sanitized = tenantId.replace(/[^A-Za-z0-9_-]/g, "_") || "unknown";
|
|
36
|
+
const hash = createHash("sha256").update(tenantId).digest("hex").slice(0, 8);
|
|
37
|
+
return `${sanitized}_${hash}`;
|
|
38
|
+
}
|
|
39
|
+
function stateRoot() {
|
|
40
|
+
return process.env["NLM_STATE_ROOT"] || join(homedir(), ".nlm");
|
|
41
|
+
}
|
|
42
|
+
/** ~/.nlm/<segments> for the default team; ~/.nlm/tenants/<t>/<segments> otherwise. */
|
|
43
|
+
export function tenantStatePath(tenantId, ...segments) {
|
|
44
|
+
const base = stateRoot();
|
|
45
|
+
if (tenantId === DEFAULT_TEAM_ID)
|
|
46
|
+
return join(base, ...segments);
|
|
47
|
+
return join(base, TENANTS_DIRNAME, sanitizeTenantId(tenantId), ...segments);
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=tenant-state-path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenant-state-path.js","sourceRoot":"","sources":["../../../src/core/tenancy/tenant-state-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,CAAC,MAAM,eAAe,GAAG,SAAS,CAAC;AAEzC,MAAM,cAAc,GAAG,kBAAkB,CAAC;AAE1C,SAAS,gBAAgB,CAAC,QAAgB;IACxC,IAAI,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAC;IACnD,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,IAAI,SAAS,CAAC;IACxE,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7E,OAAO,GAAG,SAAS,IAAI,IAAI,EAAE,CAAC;AAChC,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC,CAAC;AAClE,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,GAAG,QAAkB;IACrE,MAAM,IAAI,GAAG,SAAS,EAAE,CAAC;IACzB,IAAI,QAAQ,KAAK,eAAe;QAAE,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,CAAC;IACjE,OAAO,IAAI,CAAC,IAAI,EAAE,eAAe,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EAAE,GAAG,QAAQ,CAAC,CAAC;AAC9E,CAAC"}
|
|
@@ -41,6 +41,12 @@ export interface UpdateCheckDeps {
|
|
|
41
41
|
readonly fetchImpl?: typeof fetch;
|
|
42
42
|
}
|
|
43
43
|
export declare function getUpdateStatus(deps: UpdateCheckDeps): Promise<UpdateStatus>;
|
|
44
|
+
/**
|
|
45
|
+
* Cache-only read: never fetches the registry, even on a miss or a stale
|
|
46
|
+
* (>24h) entry. For request paths (like GET /api/health) that must stay
|
|
47
|
+
* fast and never depend on npm being reachable.
|
|
48
|
+
*/
|
|
49
|
+
export declare function getCachedUpdateStatus(deps: Pick<UpdateCheckDeps, "currentVersion" | "cachePath" | "now">): Promise<UpdateStatus>;
|
|
44
50
|
/**
|
|
45
51
|
* Strict semver-newer check on simple `X.Y.Z` versions. Pre-release tags
|
|
46
52
|
* (`-rc.1`, `-beta`) sort BEFORE the bare version per semver, which is
|
|
@@ -74,6 +74,41 @@ export async function getUpdateStatus(deps) {
|
|
|
74
74
|
});
|
|
75
75
|
return status;
|
|
76
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Cache-only read: never fetches the registry, even on a miss or a stale
|
|
79
|
+
* (>24h) entry. For request paths (like GET /api/health) that must stay
|
|
80
|
+
* fast and never depend on npm being reachable.
|
|
81
|
+
*/
|
|
82
|
+
export async function getCachedUpdateStatus(deps) {
|
|
83
|
+
const now = (deps.now ?? (() => new Date()))();
|
|
84
|
+
const current = deps.currentVersion;
|
|
85
|
+
if (isOptedOut()) {
|
|
86
|
+
return {
|
|
87
|
+
current,
|
|
88
|
+
latest: null,
|
|
89
|
+
behind: false,
|
|
90
|
+
checkedAt: now.toISOString(),
|
|
91
|
+
disabled: "user-opt-out",
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
const cachePath = deps.cachePath ?? defaultCachePath();
|
|
95
|
+
const cached = await readCache(cachePath);
|
|
96
|
+
if (!cached) {
|
|
97
|
+
return {
|
|
98
|
+
current,
|
|
99
|
+
latest: null,
|
|
100
|
+
behind: false,
|
|
101
|
+
checkedAt: now.toISOString(),
|
|
102
|
+
disabled: "unknown-error",
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
current,
|
|
107
|
+
latest: cached.latest,
|
|
108
|
+
behind: cached.latest !== null && isStrictlyNewer(cached.latest, current),
|
|
109
|
+
checkedAt: cached.checkedAt,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
77
112
|
async function readCache(path) {
|
|
78
113
|
try {
|
|
79
114
|
const raw = await readFile(path, "utf8");
|