@remnic/core 9.21.0 → 9.22.1
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/dist/access-admin-ops-surface.d.ts +32 -12
- package/dist/access-admin-ops-surface.js +44 -43
- package/dist/access-audit.js +2 -2
- package/dist/access-boundary.d.ts +13 -10
- package/dist/access-boundary.js +44 -43
- package/dist/access-cli.js +125 -122
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +16 -9
- package/dist/access-http.js +56 -54
- package/dist/access-identity-continuity-surface.d.ts +9 -7
- package/dist/access-identity-continuity-surface.js +44 -43
- package/dist/access-lcm-surface.d.ts +12 -9
- package/dist/access-lcm-surface.js +44 -43
- package/dist/access-mcp-admin-tools.d.ts +18 -0
- package/dist/access-mcp-admin-tools.js +10 -0
- package/dist/access-mcp-admin-tools.js.map +1 -0
- package/dist/access-mcp-output-schemas.js +1 -1
- package/dist/access-mcp.d.ts +22 -10
- package/dist/access-mcp.js +52 -50
- package/dist/access-memory-search-fanout.d.ts +2 -2
- package/dist/{access-namespace-preflight-tmwQgCT6.d.ts → access-namespace-preflight-CmErR03h.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +3 -3
- package/dist/access-namespace-preflight.js +44 -43
- package/dist/access-observe-write-surface.d.ts +12 -9
- package/dist/access-observe-write-surface.js +44 -43
- package/dist/access-operations-batch.js +46 -45
- package/dist/access-operations.d.ts +16 -13
- package/dist/access-operations.js +48 -47
- package/dist/access-recall-concurrency.d.ts +12 -9
- package/dist/access-recall-concurrency.js +44 -43
- package/dist/access-recall-response.d.ts +12 -9
- package/dist/access-recall-response.js +44 -43
- package/dist/access-recall-surface.d.ts +14 -11
- package/dist/access-recall-surface.js +44 -43
- package/dist/access-schema.d.ts +76 -76
- package/dist/{access-service-BqUii7LY.d.ts → access-service-CKEROeFP.d.ts} +32 -11
- package/dist/access-service.d.ts +13 -10
- package/dist/access-service.js +46 -45
- package/dist/access-surface-catalog.d.ts +12 -9
- package/dist/access-surface-catalog.js +7 -0
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/access-wearables-meetings-surface.d.ts +78 -0
- package/dist/access-wearables-meetings-surface.js +22 -0
- package/dist/access-wearables-meetings-surface.js.map +1 -0
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +1 -1
- package/dist/active-recall.d.ts +1 -1
- package/dist/active-recall.js +7 -7
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/{auto-sync-UPTUVE4X.js → auto-sync-5OE5QOZB.js} +4 -4
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +9 -7
- package/dist/briefing.d.ts +2 -2
- package/dist/briefing.js +11 -11
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer.d.ts +2 -2
- package/dist/bulk-import/index.d.ts +3 -3
- package/dist/calibration.d.ts +1 -1
- package/dist/capabilities.d.ts +1 -1
- package/dist/{catalog-iWvWz61I.d.ts → catalog-BFTVo2Ez.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-behavior.js +2 -2
- package/dist/causal-chain.js +2 -2
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +15 -15
- package/dist/causal-retrieval.js +2 -2
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-Z54EM5YZ.js → chunk-2PHX3I5C.js} +10 -10
- package/dist/{chunk-JFDEYXF7.js → chunk-3NAHZQU3.js} +2 -2
- package/dist/{chunk-MJYYXODM.js → chunk-3UOSVTFR.js} +8 -8
- package/dist/{chunk-HPOY2PHQ.js → chunk-3ZW6ZQO6.js} +6 -6
- package/dist/{chunk-UV72DEZD.js → chunk-4B77XSG5.js} +5 -5
- package/dist/chunk-56BSXSHC.js +158 -0
- package/dist/chunk-56BSXSHC.js.map +1 -0
- package/dist/{chunk-IC2TCZJ2.js → chunk-57QKLRBV.js} +3 -1
- package/dist/chunk-57QKLRBV.js.map +1 -0
- package/dist/{chunk-LMHDFOVV.js → chunk-5CPI2QWG.js} +3 -3
- package/dist/{chunk-3ZUY2VQF.js → chunk-5FZQ74K5.js} +2 -2
- package/dist/{chunk-B7C3TF5H.js → chunk-6TWXQ4E2.js} +5 -5
- package/dist/{chunk-JN3IUA2Q.js → chunk-7I7AYIUQ.js} +3 -3
- package/dist/{chunk-TVVEYCNW.js → chunk-7K5Q6COX.js} +4 -4
- package/dist/{chunk-MONWCSVL.js → chunk-7RAJ3GXO.js} +2 -1
- package/dist/chunk-7RAJ3GXO.js.map +1 -0
- package/dist/{chunk-SQEDDWAM.js → chunk-A2RFKL3V.js} +5 -34
- package/dist/chunk-A2RFKL3V.js.map +1 -0
- package/dist/{chunk-5JQLAQUZ.js → chunk-ATEAL5EI.js} +6 -6
- package/dist/{chunk-4PYLBXX6.js → chunk-AYAROCWD.js} +2 -2
- package/dist/chunk-BLDBT6HZ.js +39 -0
- package/dist/chunk-BLDBT6HZ.js.map +1 -0
- package/dist/{chunk-EXU5IQ3S.js → chunk-CUUY5CC4.js} +6 -6
- package/dist/{chunk-X5QS5C2O.js → chunk-E3ZMFFQZ.js} +2 -2
- package/dist/{chunk-JWMYVQAM.js → chunk-ES5IHQ6M.js} +2 -2
- package/dist/{chunk-HJEEAO4O.js → chunk-G2NSSQES.js} +2 -2
- package/dist/{chunk-QO2KODU6.js → chunk-GD3QOBMB.js} +2 -2
- package/dist/{chunk-62QM5MKY.js → chunk-IIXLB5E7.js} +118 -62
- package/dist/chunk-IIXLB5E7.js.map +1 -0
- package/dist/{chunk-RKNJBZ55.js → chunk-JBPKEARU.js} +4 -4
- package/dist/{chunk-Q3FWRDCP.js → chunk-JNIJBXVK.js} +2 -2
- package/dist/{chunk-EILX7SQR.js → chunk-JVGUY2AU.js} +27 -16
- package/dist/chunk-JVGUY2AU.js.map +1 -0
- package/dist/{chunk-N7EVMKP6.js → chunk-KNRG6ZGJ.js} +11 -11
- package/dist/{chunk-GEUDRENF.js → chunk-MMTG3SCJ.js} +2 -2
- package/dist/{chunk-WZFAPHIK.js → chunk-MU7ZHSZE.js} +2 -2
- package/dist/{chunk-W4FBGYGK.js → chunk-NRV4Y3PM.js} +1 -1
- package/dist/{chunk-TCZWBJBO.js → chunk-OUW4PAY4.js} +199 -256
- package/dist/chunk-OUW4PAY4.js.map +1 -0
- package/dist/{chunk-275ENJDK.js → chunk-P2BLHUL2.js} +2 -2
- package/dist/{chunk-LRGSLV7M.js → chunk-PYHOAXTI.js} +4 -4
- package/dist/{chunk-V5TSUGRB.js → chunk-QCKQEBIY.js} +17 -9
- package/dist/chunk-QCKQEBIY.js.map +1 -0
- package/dist/{chunk-EZKKHVFY.js → chunk-QE63OHLB.js} +2 -2
- package/dist/{chunk-ONHRRJZM.js → chunk-QJAQNXWI.js} +6 -6
- package/dist/{chunk-KHRKEELC.js → chunk-ROUL7RZU.js} +395 -69
- package/dist/chunk-ROUL7RZU.js.map +1 -0
- package/dist/{chunk-AT3TDN6O.js → chunk-RT4TSR2C.js} +8953 -8645
- package/dist/chunk-RT4TSR2C.js.map +1 -0
- package/dist/{chunk-6NZ7U4R4.js → chunk-SCOT5DTA.js} +1 -1
- package/dist/chunk-SCOT5DTA.js.map +1 -0
- package/dist/{chunk-LI4ZOFHW.js → chunk-SVZGA2MK.js} +2 -2
- package/dist/chunk-SYOIVK7K.js +63 -0
- package/dist/chunk-SYOIVK7K.js.map +1 -0
- package/dist/{chunk-5RUE3GHQ.js → chunk-TWCOYET2.js} +17 -1
- package/dist/chunk-TWCOYET2.js.map +1 -0
- package/dist/{chunk-5IXPWEQB.js → chunk-WS32QRLO.js} +113 -48
- package/dist/chunk-WS32QRLO.js.map +1 -0
- package/dist/{chunk-53WDAG7X.js → chunk-WWZ35GWW.js} +5 -5
- package/dist/{chunk-4F6AANKS.js → chunk-XWPFZX6S.js} +507 -143
- package/dist/chunk-XWPFZX6S.js.map +1 -0
- package/dist/{chunk-SB4OKS6C.js → chunk-ZN4UZWMT.js} +2 -2
- package/dist/{chunk-7M6APKJL.js → chunk-ZYU7ZFLT.js} +2 -2
- package/dist/{cli-DPEhq0Cp.d.ts → cli-BrwT9YMD.d.ts} +5 -5
- package/dist/cli.d.ts +14 -11
- package/dist/cli.js +86 -84
- package/dist/compounding/engine.d.ts +2 -2
- package/dist/compounding/engine.js +11 -11
- package/dist/compounding/preference-consolidator.d.ts +1 -1
- package/dist/compression-optimizer.d.ts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +4 -4
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +11 -11
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +12 -12
- package/dist/consolidation-provenance-check.d.ts +2 -2
- package/dist/consolidation-undo.d.ts +2 -2
- package/dist/contradiction/index.d.ts +2 -2
- package/dist/contradiction/index.js +1 -1
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/chunker.d.ts +1 -1
- package/dist/conversation-index/faiss-adapter.d.ts +1 -1
- package/dist/conversation-index/indexer.d.ts +1 -1
- package/dist/conversation-index/search.d.ts +1 -1
- package/dist/day-summary.d.ts +1 -1
- package/dist/delinearize.d.ts +1 -1
- package/dist/direct-answer-wiring.d.ts +1 -1
- package/dist/direct-answer.d.ts +1 -1
- package/dist/embedding-fallback.d.ts +1 -1
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +2 -2
- package/dist/entity-retrieval.js +11 -11
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +9 -7
- package/dist/explicit-capture.js +1 -1
- package/dist/extraction-error-classification.d.ts +22 -0
- package/dist/extraction-error-classification.js +11 -0
- package/dist/extraction-error-classification.js.map +1 -0
- package/dist/extraction-faithfulness.d.ts +1 -1
- package/dist/extraction-judge-telemetry.d.ts +1 -1
- package/dist/extraction-judge-training.d.ts +1 -1
- package/dist/extraction-judge.d.ts +1 -1
- package/dist/extraction.d.ts +3 -17
- package/dist/extraction.js +5 -3
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/{first-start-migration-LEXL3XYL.js → first-start-migration-BKNGOFED.js} +4 -4
- package/dist/graph-dashboard-diff.d.ts +1 -1
- package/dist/graph-dashboard-key.d.ts +1 -1
- package/dist/graph-dashboard-parser.d.ts +1 -1
- package/dist/graph-edge-reinforcement.d.ts +1 -1
- package/dist/graph-snapshot.d.ts +1 -1
- package/dist/graph.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/importers/index.d.ts +1 -1
- package/dist/in-flight-reads.d.ts +1 -1
- package/dist/index.d.ts +713 -923
- package/dist/index.js +249 -212
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/engine.js +4 -4
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/index.js +13 -13
- package/dist/lcm/tools.d.ts +1 -1
- package/dist/lifecycle.d.ts +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/local-llm.d.ts +1 -1
- package/dist/local-model-endpoint.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +12 -12
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +11 -11
- package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-projection.js +13 -13
- package/dist/maintenance-C98njYb8.d.ts +366 -0
- package/dist/mcp-memory-inspector-app.d.ts +12 -9
- package/dist/mcp-read-only-tools.js +1 -1
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +2 -2
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +3 -3
- package/dist/namespaces/migrate.js +19 -19
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +7 -7
- package/dist/namespaces/storage.d.ts +3 -3
- package/dist/namespaces/storage.js +11 -11
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/offline-sync-impression-drain.d.ts +1 -1
- package/dist/offline-sync-impression-drain.js +1 -1
- package/dist/operator-toolkit.d.ts +2 -2
- package/dist/operator-toolkit.js +28 -28
- package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
- package/dist/orchestration/maintenance.d.ts +6 -223
- package/dist/orchestration/maintenance.js +19 -19
- package/dist/{orchestrator-DB93S48I.d.ts → orchestrator-C9ZVppNh.d.ts} +12 -481
- package/dist/orchestrator.d.ts +10 -8
- package/dist/orchestrator.js +122 -119
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/{pipeline-DmGc-H66.d.ts → pipeline-id_-sqYm.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/proactive-contention.d.ts +1 -1
- package/dist/provenance.d.ts +1 -1
- package/dist/{qmd-cJT0crkF.d.ts → qmd-R6XaQOZK.d.ts} +1 -1
- package/dist/qmd-preflight.d.ts +2 -2
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +2 -2
- package/dist/qmd.js +4 -4
- package/dist/recall-concurrency-config.d.ts +1 -1
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-memory-map.d.ts +1 -1
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-state.d.ts +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-timings.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +1 -1
- package/dist/recall-xray.js +2 -2
- package/dist/replay/normalizers/chatgpt.d.ts +1 -1
- package/dist/replay/normalizers/claude.d.ts +1 -1
- package/dist/replay/normalizers/openclaw.d.ts +1 -1
- package/dist/replay/normalizers/shared.d.ts +1 -1
- package/dist/replay/runner.d.ts +1 -1
- package/dist/replay/types.d.ts +1 -1
- package/dist/resolution-3K27T4VO.js +1 -1
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +6 -6
- package/dist/retrieval-agents.d.ts +2 -2
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/routing/engine.d.ts +1 -1
- package/dist/routing/store.d.ts +1 -1
- package/dist/salvage-envelope.d.ts +1 -1
- package/dist/salvage-envelope.js +1 -1
- package/dist/schemas.d.ts +76 -76
- package/dist/{scope-profiles-KG2nODX7.d.ts → scope-profiles-EhyuAKkd.d.ts} +1 -1
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +6 -6
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +12 -12
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-BaZlg0D8.d.ts → semantic-consolidation-B2xo26UQ.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +13 -13
- package/dist/semantic-rule-promotion.js +11 -11
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +12 -12
- package/dist/service-DgFWlZ-r.d.ts +835 -0
- package/dist/session-observer-bands.d.ts +1 -1
- package/dist/session-observer-state.d.ts +1 -1
- package/dist/shared-context/manager.d.ts +9 -9
- package/dist/signal.d.ts +1 -1
- package/dist/{storage-BKhHHnRo.d.ts → storage-XGawwqXE.d.ts} +131 -2
- package/dist/storage.d.ts +2 -2
- package/dist/storage.js +10 -10
- package/dist/summarizer.d.ts +1 -1
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/temporal-supersession.d.ts +2 -2
- package/dist/temporal-timeline-recall.d.ts +1 -1
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/tier-migration.d.ts +2 -2
- package/dist/tier-routing.d.ts +1 -1
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/import-sqlite.js +2 -2
- package/dist/transfer/types.d.ts +66 -66
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-GBQZuT7l.d.ts → types-Bbs0qz6b.d.ts} +2 -3
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +12 -12
- package/dist/write-envelope.d.ts +1 -1
- package/dist/write-envelope.js +1 -1
- package/package.json +2 -2
- package/src/access-admin-ops-surface.ts +47 -0
- package/src/access-boundary.ts +4 -0
- package/src/access-http.test.ts +63 -0
- package/src/access-http.ts +27 -37
- package/src/access-mcp-admin-tools.ts +171 -0
- package/src/access-mcp-output-schemas.ts +16 -0
- package/src/access-mcp.ts +10 -262
- package/src/access-operations-batch.ts +11 -5
- package/src/access-service.ts +59 -46
- package/src/access-surface-catalog.ts +7 -0
- package/src/access-wearables-meetings-surface.ts +139 -0
- package/src/activity/digest.ts +1 -1
- package/src/activity/runner.test.ts +37 -0
- package/src/activity/runner.ts +12 -0
- package/src/activity/scheduler.test.ts +1 -0
- package/src/activity/sync-registration.ts +13 -0
- package/src/cli/meetings-commands.ts +70 -0
- package/src/cli.ts +7 -6
- package/src/extraction-error-classification.ts +52 -0
- package/src/extraction.ts +2 -50
- package/src/mcp-read-only-tools.ts +2 -0
- package/src/meetings/build-memory.test.ts +364 -0
- package/src/meetings/build-scheduler.test.ts +55 -0
- package/src/meetings/build-scheduler.ts +96 -0
- package/src/meetings/day-source.test.ts +275 -0
- package/src/meetings/day-source.ts +352 -0
- package/src/meetings/http-glue.ts +126 -0
- package/src/meetings/index.ts +5 -4
- package/src/meetings/manual-sync-flush.test.ts +72 -0
- package/src/meetings/mcp-tools.ts +65 -0
- package/src/meetings/memory-gen.test.ts +498 -0
- package/src/meetings/memory-gen.ts +549 -0
- package/src/meetings/memory-generator.ts +5 -0
- package/src/meetings/namespace-isolation.test.ts +159 -0
- package/src/meetings/service.test.ts +195 -0
- package/src/meetings/service.ts +157 -0
- package/src/meetings/summary-extractor.test.ts +287 -0
- package/src/meetings/summary-extractor.ts +264 -0
- package/src/orchestration/maintenance.ts +8 -0
- package/src/orchestration/orchestrator-init.ts +6 -1
- package/src/orchestration/workspace-ops.ts +172 -8
- package/src/orchestrator.ts +12 -13
- package/src/storage.ts +21 -0
- package/src/testing/subjects/meetings-namespace-harness.ts +159 -0
- package/src/testing/subjects/meetings-namespace.test.ts +93 -0
- package/src/types.ts +1 -2
- package/src/wearables/cli.ts +2 -1
- package/src/wearables/index.ts +1 -0
- package/src/wearables/mcp-tools.ts +143 -0
- package/src/wearables/registry.test.ts +11 -0
- package/src/wearables/registry.ts +13 -0
- package/src/wearables/service.test.ts +62 -1
- package/src/wearables/service.ts +30 -2
- package/src/wearables/transcript-search-namespace-isolation.test.ts +98 -0
- package/dist/chunk-4F6AANKS.js.map +0 -1
- package/dist/chunk-5IXPWEQB.js.map +0 -1
- package/dist/chunk-5RUE3GHQ.js.map +0 -1
- package/dist/chunk-62QM5MKY.js.map +0 -1
- package/dist/chunk-6NZ7U4R4.js.map +0 -1
- package/dist/chunk-AT3TDN6O.js.map +0 -1
- package/dist/chunk-EILX7SQR.js.map +0 -1
- package/dist/chunk-IC2TCZJ2.js.map +0 -1
- package/dist/chunk-KHRKEELC.js.map +0 -1
- package/dist/chunk-MONWCSVL.js.map +0 -1
- package/dist/chunk-SQEDDWAM.js.map +0 -1
- package/dist/chunk-TCZWBJBO.js.map +0 -1
- package/dist/chunk-V5TSUGRB.js.map +0 -1
- /package/dist/{auto-sync-UPTUVE4X.js.map → auto-sync-5OE5QOZB.js.map} +0 -0
- /package/dist/{chunk-Z54EM5YZ.js.map → chunk-2PHX3I5C.js.map} +0 -0
- /package/dist/{chunk-JFDEYXF7.js.map → chunk-3NAHZQU3.js.map} +0 -0
- /package/dist/{chunk-MJYYXODM.js.map → chunk-3UOSVTFR.js.map} +0 -0
- /package/dist/{chunk-HPOY2PHQ.js.map → chunk-3ZW6ZQO6.js.map} +0 -0
- /package/dist/{chunk-UV72DEZD.js.map → chunk-4B77XSG5.js.map} +0 -0
- /package/dist/{chunk-LMHDFOVV.js.map → chunk-5CPI2QWG.js.map} +0 -0
- /package/dist/{chunk-3ZUY2VQF.js.map → chunk-5FZQ74K5.js.map} +0 -0
- /package/dist/{chunk-B7C3TF5H.js.map → chunk-6TWXQ4E2.js.map} +0 -0
- /package/dist/{chunk-JN3IUA2Q.js.map → chunk-7I7AYIUQ.js.map} +0 -0
- /package/dist/{chunk-TVVEYCNW.js.map → chunk-7K5Q6COX.js.map} +0 -0
- /package/dist/{chunk-5JQLAQUZ.js.map → chunk-ATEAL5EI.js.map} +0 -0
- /package/dist/{chunk-4PYLBXX6.js.map → chunk-AYAROCWD.js.map} +0 -0
- /package/dist/{chunk-EXU5IQ3S.js.map → chunk-CUUY5CC4.js.map} +0 -0
- /package/dist/{chunk-X5QS5C2O.js.map → chunk-E3ZMFFQZ.js.map} +0 -0
- /package/dist/{chunk-JWMYVQAM.js.map → chunk-ES5IHQ6M.js.map} +0 -0
- /package/dist/{chunk-HJEEAO4O.js.map → chunk-G2NSSQES.js.map} +0 -0
- /package/dist/{chunk-QO2KODU6.js.map → chunk-GD3QOBMB.js.map} +0 -0
- /package/dist/{chunk-RKNJBZ55.js.map → chunk-JBPKEARU.js.map} +0 -0
- /package/dist/{chunk-Q3FWRDCP.js.map → chunk-JNIJBXVK.js.map} +0 -0
- /package/dist/{chunk-N7EVMKP6.js.map → chunk-KNRG6ZGJ.js.map} +0 -0
- /package/dist/{chunk-GEUDRENF.js.map → chunk-MMTG3SCJ.js.map} +0 -0
- /package/dist/{chunk-WZFAPHIK.js.map → chunk-MU7ZHSZE.js.map} +0 -0
- /package/dist/{chunk-W4FBGYGK.js.map → chunk-NRV4Y3PM.js.map} +0 -0
- /package/dist/{chunk-275ENJDK.js.map → chunk-P2BLHUL2.js.map} +0 -0
- /package/dist/{chunk-LRGSLV7M.js.map → chunk-PYHOAXTI.js.map} +0 -0
- /package/dist/{chunk-EZKKHVFY.js.map → chunk-QE63OHLB.js.map} +0 -0
- /package/dist/{chunk-ONHRRJZM.js.map → chunk-QJAQNXWI.js.map} +0 -0
- /package/dist/{chunk-LI4ZOFHW.js.map → chunk-SVZGA2MK.js.map} +0 -0
- /package/dist/{chunk-53WDAG7X.js.map → chunk-WWZ35GWW.js.map} +0 -0
- /package/dist/{chunk-SB4OKS6C.js.map → chunk-ZN4UZWMT.js.map} +0 -0
- /package/dist/{chunk-7M6APKJL.js.map → chunk-ZYU7ZFLT.js.map} +0 -0
- /package/dist/{first-start-migration-LEXL3XYL.js.map → first-start-migration-BKNGOFED.js.map} +0 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wearables MCP tool definitions (issue #1900 / #2123) — the five
|
|
3
|
+
* `engram.wearables_*` / `engram.transcript_*` tool-def objects, extracted from
|
|
4
|
+
* access-mcp.ts so the surface file stays under its structural ceiling. Spread
|
|
5
|
+
* back into `this.tools` (`...WEARABLES_MCP_TOOLS`); tools/list is verified at
|
|
6
|
+
* runtime. MCP_MIGRATED_OPERATIONS + callTool dispatch stay inline in
|
|
7
|
+
* access-mcp.ts. Each schema carries `namespace` + `sessionKey` so the MCP
|
|
8
|
+
* scope-override injects the caller namespace (caller-derived symmetry, #2123).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { McpTool } from "../access-mcp.js";
|
|
12
|
+
|
|
13
|
+
export const WEARABLES_MCP_TOOLS: McpTool[] = [
|
|
14
|
+
{
|
|
15
|
+
name: "engram.wearables_status",
|
|
16
|
+
description:
|
|
17
|
+
"Status of wearable transcript sources (Limitless / Bee / Omi): configured sources, connector availability, last sync, stored transcript days.",
|
|
18
|
+
inputSchema: {
|
|
19
|
+
type: "object",
|
|
20
|
+
properties: {
|
|
21
|
+
namespace: { type: "string", description: "Caller namespace to scope this operation to (issue #2123)." },
|
|
22
|
+
sessionKey: { type: "string", description: "Session key for principal/namespace resolution." },
|
|
23
|
+
},
|
|
24
|
+
additionalProperties: false,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: "engram.wearables_sync",
|
|
29
|
+
description:
|
|
30
|
+
"Pull, clean, and store wearable transcripts for one source or all enabled sources; optionally creates trust-gated memories per the source's memoryMode.",
|
|
31
|
+
inputSchema: {
|
|
32
|
+
type: "object",
|
|
33
|
+
properties: {
|
|
34
|
+
namespace: { type: "string", description: "Caller namespace to scope this operation to (issue #2123)." },
|
|
35
|
+
sessionKey: { type: "string", description: "Session key for principal/namespace resolution." },
|
|
36
|
+
source: {
|
|
37
|
+
type: "string",
|
|
38
|
+
description: "Source id (e.g. limitless, bee, omi). Omit to sync every enabled source.",
|
|
39
|
+
},
|
|
40
|
+
date: {
|
|
41
|
+
type: "string",
|
|
42
|
+
description: "Sync exactly this day (YYYY-MM-DD). Overrides days.",
|
|
43
|
+
},
|
|
44
|
+
days: {
|
|
45
|
+
type: "integer",
|
|
46
|
+
minimum: 1,
|
|
47
|
+
maximum: 90,
|
|
48
|
+
description: "Lookback window in days ending today (default 2).",
|
|
49
|
+
},
|
|
50
|
+
forceMemories: {
|
|
51
|
+
type: "boolean",
|
|
52
|
+
description: "Re-run memory extraction even for unchanged days.",
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
additionalProperties: false,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: "engram.transcript_day",
|
|
60
|
+
description:
|
|
61
|
+
"Return the full stored wearable transcript(s) for a day, across all sources or one source, with cross-source overlap hints.",
|
|
62
|
+
inputSchema: {
|
|
63
|
+
type: "object",
|
|
64
|
+
properties: {
|
|
65
|
+
namespace: { type: "string", description: "Caller namespace to scope this operation to (issue #2123)." },
|
|
66
|
+
sessionKey: { type: "string", description: "Session key for principal/namespace resolution." },
|
|
67
|
+
date: {
|
|
68
|
+
type: "string",
|
|
69
|
+
description: "Day to read (YYYY-MM-DD). Required.",
|
|
70
|
+
},
|
|
71
|
+
source: {
|
|
72
|
+
type: "string",
|
|
73
|
+
description: "Optional source id to scope to (e.g. limitless).",
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
required: ["date"],
|
|
77
|
+
additionalProperties: false,
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: "engram.transcript_search",
|
|
82
|
+
description:
|
|
83
|
+
"Search stored wearable transcripts. Results carry source + date so callers can pull the full day via engram.transcript_day.",
|
|
84
|
+
inputSchema: {
|
|
85
|
+
type: "object",
|
|
86
|
+
properties: {
|
|
87
|
+
namespace: { type: "string", description: "Caller namespace to scope this operation to (issue #2123)." },
|
|
88
|
+
sessionKey: { type: "string", description: "Session key for principal/namespace resolution." },
|
|
89
|
+
query: {
|
|
90
|
+
type: "string",
|
|
91
|
+
description: "Search query. Required; non-empty.",
|
|
92
|
+
},
|
|
93
|
+
source: {
|
|
94
|
+
type: "string",
|
|
95
|
+
description: "Optional source id filter.",
|
|
96
|
+
},
|
|
97
|
+
from: {
|
|
98
|
+
type: "string",
|
|
99
|
+
description: "Optional inclusive start date (YYYY-MM-DD).",
|
|
100
|
+
},
|
|
101
|
+
to: {
|
|
102
|
+
type: "string",
|
|
103
|
+
description: "Optional inclusive end date (YYYY-MM-DD).",
|
|
104
|
+
},
|
|
105
|
+
limit: {
|
|
106
|
+
type: "integer",
|
|
107
|
+
minimum: 1,
|
|
108
|
+
maximum: 50,
|
|
109
|
+
description: "Maximum results (default 10).",
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
required: ["query"],
|
|
113
|
+
additionalProperties: false,
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
name: "engram.transcript_memories",
|
|
118
|
+
description:
|
|
119
|
+
"List memories created from wearable transcripts, filterable by source and/or day. Includes pending_review candidates awaiting approval.",
|
|
120
|
+
inputSchema: {
|
|
121
|
+
type: "object",
|
|
122
|
+
properties: {
|
|
123
|
+
namespace: { type: "string", description: "Caller namespace to scope this operation to (issue #2123)." },
|
|
124
|
+
sessionKey: { type: "string", description: "Session key for principal/namespace resolution." },
|
|
125
|
+
source: {
|
|
126
|
+
type: "string",
|
|
127
|
+
description: "Optional source id filter (e.g. limitless).",
|
|
128
|
+
},
|
|
129
|
+
date: {
|
|
130
|
+
type: "string",
|
|
131
|
+
description: "Optional transcript day filter (YYYY-MM-DD).",
|
|
132
|
+
},
|
|
133
|
+
limit: {
|
|
134
|
+
type: "integer",
|
|
135
|
+
minimum: 1,
|
|
136
|
+
maximum: 200,
|
|
137
|
+
description: "Maximum results (default 50).",
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
additionalProperties: false,
|
|
141
|
+
},
|
|
142
|
+
}
|
|
143
|
+
];
|
|
@@ -2,6 +2,7 @@ import assert from "node:assert/strict";
|
|
|
2
2
|
import { afterEach, test } from "node:test";
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
|
+
builtInConnectorPackageSpecifier,
|
|
5
6
|
clearWearableConnectors,
|
|
6
7
|
ensureBuiltInWearableConnectors,
|
|
7
8
|
getWearableConnector,
|
|
@@ -60,3 +61,13 @@ test("ensureBuiltInWearableConnectors tolerates absent optional packages", async
|
|
|
60
61
|
await ensureBuiltInWearableConnectors();
|
|
61
62
|
assert.ok(Array.isArray(listWearableConnectors()));
|
|
62
63
|
});
|
|
64
|
+
|
|
65
|
+
test("builtInConnectorPackageSpecifier maps a source to its real optional package (AC9 install hint)", () => {
|
|
66
|
+
// desktop ships in @remnic/capture-audio, NOT the nonexistent
|
|
67
|
+
// @remnic/connector-desktop — the missing-package hint must be installable.
|
|
68
|
+
assert.equal(builtInConnectorPackageSpecifier("desktop"), "@remnic/capture-audio");
|
|
69
|
+
assert.equal(builtInConnectorPackageSpecifier("limitless"), "@remnic/connector-limitless");
|
|
70
|
+
assert.equal(builtInConnectorPackageSpecifier("bee"), "@remnic/connector-bee");
|
|
71
|
+
// An unknown id keeps the connector-<id> convention.
|
|
72
|
+
assert.equal(builtInConnectorPackageSpecifier("acme"), "@remnic/connector-acme");
|
|
73
|
+
});
|
|
@@ -86,8 +86,21 @@ const BUILT_IN_CONNECTOR_PACKAGES: Array<{ id: string; suffix: string }> = [
|
|
|
86
86
|
{ id: "omi", suffix: "connector-omi" },
|
|
87
87
|
{ id: "fireflies", suffix: "connector-fireflies" },
|
|
88
88
|
{ id: "granola", suffix: "connector-granola" },
|
|
89
|
+
{ id: "desktop", suffix: "capture-audio" },
|
|
89
90
|
];
|
|
90
91
|
|
|
92
|
+
/**
|
|
93
|
+
* npm specifier of the optional package that provides a source's connector.
|
|
94
|
+
* Built-in sources map to their real package (e.g. `desktop` ->
|
|
95
|
+
* `@remnic/capture-audio`, not the nonexistent `@remnic/connector-desktop`);
|
|
96
|
+
* unknown ids fall back to the `connector-<id>` convention. Used by
|
|
97
|
+
* missing-connector install hints so they name the exact install command.
|
|
98
|
+
*/
|
|
99
|
+
export function builtInConnectorPackageSpecifier(id: string): string {
|
|
100
|
+
const entry = BUILT_IN_CONNECTOR_PACKAGES.find((e) => e.id === id);
|
|
101
|
+
return `@remnic/${entry ? entry.suffix : `connector-${id}`}`;
|
|
102
|
+
}
|
|
103
|
+
|
|
91
104
|
const loadFailuresWarned = new Set<string>();
|
|
92
105
|
|
|
93
106
|
export async function ensureBuiltInWearableConnectors(): Promise<void> {
|
|
@@ -31,7 +31,15 @@ import {
|
|
|
31
31
|
} from "./service.js";
|
|
32
32
|
import { sealedWriteToLegacyArgs } from "../write-envelope.js";
|
|
33
33
|
import { defaultWearablesConfig, defaultWearableSourceSettings } from "./config.js";
|
|
34
|
-
import
|
|
34
|
+
import {
|
|
35
|
+
clearWearableConnectors,
|
|
36
|
+
registerWearableConnector,
|
|
37
|
+
} from "./registry.js";
|
|
38
|
+
import type {
|
|
39
|
+
WearableConversation,
|
|
40
|
+
WearableSourceConnector,
|
|
41
|
+
WearablesConfig,
|
|
42
|
+
} from "./types.js";
|
|
35
43
|
|
|
36
44
|
function makeStorage(memoryDir: string): WearableStorageIo & {
|
|
37
45
|
files: Map<string, string>;
|
|
@@ -1621,3 +1629,56 @@ test("searchTranscripts scan decodes segment text so snippets show the original
|
|
|
1621
1629
|
rmSync(dir, { recursive: true, force: true });
|
|
1622
1630
|
}
|
|
1623
1631
|
});
|
|
1632
|
+
|
|
1633
|
+
function syncOnlyConnector(): WearableSourceConnector {
|
|
1634
|
+
return {
|
|
1635
|
+
id: "testsource",
|
|
1636
|
+
displayName: "Test Source",
|
|
1637
|
+
async verifyAuth() {
|
|
1638
|
+
return { ok: true };
|
|
1639
|
+
},
|
|
1640
|
+
async fetchConversations() {
|
|
1641
|
+
return { conversations: [], nextCursor: null };
|
|
1642
|
+
},
|
|
1643
|
+
};
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
test("sync fires onDaysSynced with the synced days so a MANUAL wearables sync triggers the meeting tail-step (issue #1900)", async () => {
|
|
1647
|
+
const dir = mkdtempSync(path.join(tmpdir(), "wearables-on-days-synced-"));
|
|
1648
|
+
try {
|
|
1649
|
+
clearWearableConnectors();
|
|
1650
|
+
registerWearableConnector({
|
|
1651
|
+
id: "testsource",
|
|
1652
|
+
displayName: "Test Source",
|
|
1653
|
+
factory: () => syncOnlyConnector(),
|
|
1654
|
+
});
|
|
1655
|
+
const storage = makeStorage(dir);
|
|
1656
|
+
const synced: string[][] = [];
|
|
1657
|
+
const service = new WearablesService({
|
|
1658
|
+
config: {
|
|
1659
|
+
...defaultWearablesConfig(),
|
|
1660
|
+
enabled: true,
|
|
1661
|
+
timezone: "UTC",
|
|
1662
|
+
sources: { testsource: { ...defaultWearableSourceSettings(), enabled: true } },
|
|
1663
|
+
},
|
|
1664
|
+
getStorage: async () => storage,
|
|
1665
|
+
extract: null,
|
|
1666
|
+
searchBackend: null,
|
|
1667
|
+
// Stands in for the workspace-ops wiring that calls the meetings service's
|
|
1668
|
+
// debounced requestBuild — the manual HTTP/MCP/CLI sync path reaches this
|
|
1669
|
+
// same shared service, so the tail-step must fire here, not only in the
|
|
1670
|
+
// auto-sync adapter.
|
|
1671
|
+
onDaysSynced: (days) => {
|
|
1672
|
+
synced.push([...days]);
|
|
1673
|
+
},
|
|
1674
|
+
});
|
|
1675
|
+
const summaries = await service.sync({ source: "testsource", days: 1 });
|
|
1676
|
+
const expected = [...new Set(summaries.flatMap((summary) => summary.days))].sort();
|
|
1677
|
+
assert.ok(expected.length > 0, "the sync touched at least one day");
|
|
1678
|
+
assert.equal(synced.length, 1, "the shared sync path fires the meeting tail-step exactly once");
|
|
1679
|
+
assert.deepEqual([...synced[0]!].sort(), expected, "the hook receives the union of synced days");
|
|
1680
|
+
} finally {
|
|
1681
|
+
clearWearableConnectors();
|
|
1682
|
+
rmSync(dir, { recursive: true, force: true });
|
|
1683
|
+
}
|
|
1684
|
+
});
|
package/src/wearables/service.ts
CHANGED
|
@@ -41,6 +41,7 @@ import {
|
|
|
41
41
|
type WearableSyncOptions,
|
|
42
42
|
} from "./pipeline.js";
|
|
43
43
|
import {
|
|
44
|
+
builtInConnectorPackageSpecifier,
|
|
44
45
|
ensureBuiltInWearableConnectors,
|
|
45
46
|
getWearableConnector,
|
|
46
47
|
listWearableConnectors,
|
|
@@ -132,6 +133,15 @@ export interface WearablesServiceDeps {
|
|
|
132
133
|
searchBackend: WearableSearchBackend | null;
|
|
133
134
|
/** Fired after transcript writes so the search index refreshes. */
|
|
134
135
|
reindexSearch?: () => Promise<void>;
|
|
136
|
+
/**
|
|
137
|
+
* Meeting tail-step (issue #1900): fired once after a sync with the union of
|
|
138
|
+
* days it touched, so a dependent subsystem (meeting building) can rebuild the
|
|
139
|
+
* affected day(s). Wired for EVERY sync path — auto-sync AND manual
|
|
140
|
+
* HTTP/MCP/CLI backfill — because they all share this one service. Optional;
|
|
141
|
+
* omitted by hosts that do not build meetings. The hook self-gates and never
|
|
142
|
+
* fails the sync.
|
|
143
|
+
*/
|
|
144
|
+
onDaysSynced?: (days: readonly string[]) => void | Promise<void>;
|
|
135
145
|
}
|
|
136
146
|
|
|
137
147
|
export interface WearableTranscriptSearchResult {
|
|
@@ -326,7 +336,7 @@ export class WearablesService {
|
|
|
326
336
|
if (!registration) {
|
|
327
337
|
throw new WearablesInputError(
|
|
328
338
|
`wearable source '${sourceId}' is enabled but its connector package is not installed.\n` +
|
|
329
|
-
`Install it alongside Remnic:\n npm install
|
|
339
|
+
`Install it alongside Remnic:\n npm install ${builtInConnectorPackageSpecifier(sourceId)}`,
|
|
330
340
|
);
|
|
331
341
|
}
|
|
332
342
|
const connector = registration.factory({
|
|
@@ -398,6 +408,24 @@ export class WearablesService {
|
|
|
398
408
|
);
|
|
399
409
|
summaries.push(summary);
|
|
400
410
|
}
|
|
411
|
+
// Tail step (issue #1900): a wearable sync changed a day's audio, so fan out
|
|
412
|
+
// the affected days to the injected build hook (wired to the meetings
|
|
413
|
+
// service's debounced rebuild). Fires for every sync path — auto-sync and
|
|
414
|
+
// manual HTTP/MCP/CLI backfill alike — since they all share this service.
|
|
415
|
+
// The hook self-gates on meetings.enabled and coalesces; a failure here
|
|
416
|
+
// never fails the sync that called us.
|
|
417
|
+
const syncedDays = [...new Set(summaries.flatMap((summary) => summary.days))];
|
|
418
|
+
if (syncedDays.length > 0 && this.deps.onDaysSynced) {
|
|
419
|
+
try {
|
|
420
|
+
await this.deps.onDaysSynced(syncedDays);
|
|
421
|
+
} catch (err) {
|
|
422
|
+
log.warn(
|
|
423
|
+
`wearables: post-sync meeting build hook failed (non-fatal): ${
|
|
424
|
+
err instanceof Error ? err.message : String(err)
|
|
425
|
+
}`,
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
401
429
|
return summaries;
|
|
402
430
|
}
|
|
403
431
|
|
|
@@ -414,7 +442,7 @@ export class WearablesService {
|
|
|
414
442
|
if (!registration) {
|
|
415
443
|
return {
|
|
416
444
|
ok: false,
|
|
417
|
-
detail: `connector package
|
|
445
|
+
detail: `connector package ${builtInConnectorPackageSpecifier(sourceId)} is not installed`,
|
|
418
446
|
};
|
|
419
447
|
}
|
|
420
448
|
const connector = registration.factory({
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wearable transcript SEARCH namespace isolation (issue #2123, P1 gap).
|
|
3
|
+
*
|
|
4
|
+
* getWearablesService(namespace) reads transcript FILES from the caller's
|
|
5
|
+
* namespace storage, but the injected `searchBackend.search` used to call the
|
|
6
|
+
* ROOT qmd collection unconditionally. In a namespace-enabled deployment that
|
|
7
|
+
* let a non-default caller's transcript_search surface root/other-namespace
|
|
8
|
+
* transcripts — a data-isolation breach that the file-scoping alone did not
|
|
9
|
+
* close (the indexed path returns hits using the index snippet even when the
|
|
10
|
+
* caller-namespace file read is null).
|
|
11
|
+
*
|
|
12
|
+
* The fix scopes the indexed search to the CALLER namespace's collection. This
|
|
13
|
+
* two-principal test drives a fake collection-partitioned qmd backend:
|
|
14
|
+
* 1. principal A (non-default nsA) sees ONLY nsA's transcript;
|
|
15
|
+
* 2. principal B (non-default nsB) sees ONLY nsB's transcript — a transcript
|
|
16
|
+
* that exists only under the default/root namespace is NOT returned to B;
|
|
17
|
+
* 3. the default/machine-owner caller still sees the default transcript.
|
|
18
|
+
*
|
|
19
|
+
* Before the fix every caller searched the root collection (collection
|
|
20
|
+
* undefined), so B received the default transcript and this fails.
|
|
21
|
+
*/
|
|
22
|
+
import assert from "node:assert/strict";
|
|
23
|
+
import test from "node:test";
|
|
24
|
+
|
|
25
|
+
import { namespaceCollectionName } from "../namespaces/search.js";
|
|
26
|
+
import type { SearchBackend, SearchResult } from "../search/port.js";
|
|
27
|
+
import { buildMeetingsNamespaceHarness } from "../testing/subjects/meetings-namespace-harness.js";
|
|
28
|
+
|
|
29
|
+
const SOURCE = "faketest";
|
|
30
|
+
const DATE_A = "2026-04-01";
|
|
31
|
+
const DATE_B = "2026-04-02";
|
|
32
|
+
const DATE_DEFAULT = "2026-04-03";
|
|
33
|
+
|
|
34
|
+
const transcriptFile = (body: string): string =>
|
|
35
|
+
`---\nkind: wearable-transcript\n---\n\n${body}\n`;
|
|
36
|
+
|
|
37
|
+
const dates = (results: ReadonlyArray<{ date: string }>): string[] =>
|
|
38
|
+
results.map((r) => r.date).sort();
|
|
39
|
+
|
|
40
|
+
test("transcript search is scoped to the caller namespace: A sees only A, B never sees the default transcript, the default caller still sees default (#2123)", async () => {
|
|
41
|
+
const h = await buildMeetingsNamespaceHarness();
|
|
42
|
+
try {
|
|
43
|
+
// Physical transcripts under each namespace root.
|
|
44
|
+
await (await h.storageForNs("nsA")).writeWearableDayTranscript(SOURCE, DATE_A, transcriptFile("alpha standup notes"));
|
|
45
|
+
await (await h.storageForNs("nsB")).writeWearableDayTranscript(SOURCE, DATE_B, transcriptFile("bravo standup notes"));
|
|
46
|
+
await (await h.storageForNs("default")).writeWearableDayTranscript(SOURCE, DATE_DEFAULT, transcriptFile("delta standup notes"));
|
|
47
|
+
|
|
48
|
+
const base = h.orchestrator.config.qmdCollection;
|
|
49
|
+
const collFor = (ns: string, legacy: boolean): string =>
|
|
50
|
+
namespaceCollectionName(base, ns, { defaultNamespace: "default", useLegacyDefaultCollection: legacy });
|
|
51
|
+
const hit = (date: string, snippet: string): SearchResult =>
|
|
52
|
+
({ path: `wearables/${SOURCE}/${date}.md`, score: 0.9, snippet } as unknown as SearchResult);
|
|
53
|
+
|
|
54
|
+
// Collection-partitioned index. The default hit is ALSO registered under
|
|
55
|
+
// the root key (collection === undefined) so a non-scoped (pre-fix) search
|
|
56
|
+
// returns the default transcript — that is exactly the breach under test.
|
|
57
|
+
const index: Record<string, SearchResult[]> = {
|
|
58
|
+
"\u0000root": [hit(DATE_DEFAULT, "delta standup notes")],
|
|
59
|
+
[base]: [hit(DATE_DEFAULT, "delta standup notes")],
|
|
60
|
+
[collFor("default", false)]: [hit(DATE_DEFAULT, "delta standup notes")],
|
|
61
|
+
[collFor("nsA", false)]: [hit(DATE_A, "alpha standup notes")],
|
|
62
|
+
[collFor("nsB", false)]: [hit(DATE_B, "bravo standup notes")],
|
|
63
|
+
};
|
|
64
|
+
const searchedCollections: Array<string | undefined> = [];
|
|
65
|
+
h.orchestrator.qmd = {
|
|
66
|
+
isAvailable: () => true,
|
|
67
|
+
search: async (_query: string, collection?: string, maxResults?: number) => {
|
|
68
|
+
searchedCollections.push(collection);
|
|
69
|
+
return (index[collection ?? "\u0000root"] ?? []).slice(0, maxResults);
|
|
70
|
+
},
|
|
71
|
+
} as unknown as SearchBackend;
|
|
72
|
+
|
|
73
|
+
const search = (namespace: string, authenticatedPrincipal: string) =>
|
|
74
|
+
h.service.wearablesTranscriptSearch({ query: "standup", namespace, authenticatedPrincipal });
|
|
75
|
+
|
|
76
|
+
const aRes = await search("nsA", "pA");
|
|
77
|
+
assert.deepEqual(dates(aRes), [DATE_A], "principal A sees only nsA's transcript");
|
|
78
|
+
|
|
79
|
+
const bRes = await search("nsB", "pB");
|
|
80
|
+
assert.deepEqual(dates(bRes), [DATE_B], "principal B sees only nsB's transcript");
|
|
81
|
+
assert.ok(
|
|
82
|
+
!bRes.some((r) => r.date === DATE_DEFAULT),
|
|
83
|
+
"the default/root transcript is NOT leaked to a non-default caller",
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const dRes = await search("default", "op");
|
|
87
|
+
assert.deepEqual(dates(dRes), [DATE_DEFAULT], "the default/machine-owner caller still sees default transcripts");
|
|
88
|
+
|
|
89
|
+
// The indexed search was scoped per caller: no query ran against the root
|
|
90
|
+
// collection (undefined) — that is the pre-fix breach.
|
|
91
|
+
assert.ok(
|
|
92
|
+
!searchedCollections.includes(undefined),
|
|
93
|
+
"no transcript search targeted the unscoped root collection",
|
|
94
|
+
);
|
|
95
|
+
} finally {
|
|
96
|
+
await h.cleanup();
|
|
97
|
+
}
|
|
98
|
+
});
|