@remnic/core 9.4.1 → 9.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/access-admin-ops-surface.d.ts +5 -5
- package/dist/access-admin-ops-surface.js +26 -26
- package/dist/access-boundary.d.ts +26 -7
- package/dist/access-boundary.js +31 -27
- package/dist/access-cli.js +79 -77
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +51 -5
- package/dist/access-http.js +38 -36
- package/dist/access-identity-continuity-surface.d.ts +4 -4
- package/dist/access-identity-continuity-surface.js +26 -26
- package/dist/access-lcm-surface.d.ts +5 -5
- package/dist/access-lcm-surface.js +26 -26
- package/dist/access-mcp.d.ts +15 -5
- package/dist/access-mcp.js +35 -33
- package/dist/access-observe-write-surface.d.ts +5 -5
- package/dist/access-observe-write-surface.js +26 -26
- package/dist/access-operations-batch.js +31 -30
- package/dist/access-operations.d.ts +7 -7
- package/dist/access-operations.js +33 -32
- package/dist/access-recall-surface.d.ts +5 -5
- package/dist/access-recall-surface.js +26 -26
- package/dist/access-schema.js +4 -4
- package/dist/{access-service-m-2VO_Ig.d.ts → access-service-DZX0sYAv.d.ts} +3 -3
- package/dist/access-service.d.ts +5 -5
- package/dist/access-service.js +26 -26
- package/dist/access-surface-catalog.d.ts +5 -5
- package/dist/access-surface-catalog.js +1 -0
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/access-token-capabilities.d.ts +174 -0
- package/dist/access-token-capabilities.js +33 -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 +1 -1
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/{auto-sync-HMHQHUAG.js → auto-sync-G6IU7L6C.js} +3 -3
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +4 -4
- package/dist/briefing.d.ts +1 -1
- package/dist/briefing.js +7 -7
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer.d.ts +1 -1
- package/dist/calibration.d.ts +1 -1
- package/dist/capabilities.d.ts +1 -1
- package/dist/{capsule-crypto-CZJSLEFG.js → capsule-crypto-RAARDY3M.js} +2 -2
- package/dist/capsule-crypto-RAARDY3M.js.map +1 -0
- package/dist/{catalog-BxWokdC2.d.ts → catalog-DoH2b0OR.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-behavior.js +5 -5
- package/dist/causal-chain.js +3 -3
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +11 -11
- package/dist/causal-retrieval.js +3 -3
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-7QWMTOIF.js → chunk-2B7DP7AP.js} +31 -31
- package/dist/{chunk-4BFRBP45.js → chunk-2JFDHI2K.js} +2 -2
- package/dist/{chunk-OHDJ34CC.js → chunk-2SFEFR5I.js} +2 -2
- package/dist/{chunk-E2SPGGUI.js → chunk-4OKLXWDZ.js} +13 -6
- package/dist/chunk-4OKLXWDZ.js.map +1 -0
- package/dist/{chunk-ILFJ7AVS.js → chunk-4WNLSSHL.js} +35 -21
- package/dist/chunk-4WNLSSHL.js.map +1 -0
- package/dist/{chunk-YDSWRD33.js → chunk-5K5VEDFY.js} +4 -4
- package/dist/{chunk-CZAZX7JP.js → chunk-7BAJAXGB.js} +4 -4
- package/dist/{chunk-CXLNZXG5.js → chunk-7XGSIUP5.js} +1 -1
- package/dist/{chunk-ZPOROUTX.js → chunk-AOYJVCFN.js} +5 -5
- package/dist/{chunk-IC6QX5TC.js → chunk-BGMSRN6I.js} +5 -5
- package/dist/{chunk-5QZDMSSN.js → chunk-CXEL3Y22.js} +70 -70
- package/dist/{chunk-M5QKGHCR.js → chunk-CYWCKFCL.js} +5 -5
- package/dist/{chunk-2U2A5HF4.js → chunk-D2XYYU5Q.js} +5 -5
- package/dist/chunk-D7FOKIY5.js +173 -0
- package/dist/chunk-D7FOKIY5.js.map +1 -0
- package/dist/{chunk-DGYCWCQ7.js → chunk-DZSAXE3T.js} +2 -2
- package/dist/{chunk-2BFLDH5F.js → chunk-EEIROWEG.js} +2 -2
- package/dist/{chunk-6ZIETXZ2.js → chunk-H5PFR5ZT.js} +2 -2
- package/dist/{chunk-2FOD2YY3.js → chunk-I74ZEBMA.js} +236 -103
- package/dist/chunk-I74ZEBMA.js.map +1 -0
- package/dist/chunk-IC2TCZJ2.js +54 -0
- package/dist/chunk-IC2TCZJ2.js.map +1 -0
- package/dist/{chunk-66FLU5BT.js → chunk-II6WHCCW.js} +6 -6
- package/dist/{chunk-YPEMNNNY.js → chunk-ITWTKT2R.js} +6 -6
- package/dist/{chunk-AKUCU7CI.js → chunk-JI5AVXYO.js} +5 -5
- package/dist/{chunk-27FLVMDC.js → chunk-KMF67QDQ.js} +7 -7
- package/dist/{chunk-FLVL4L3L.js → chunk-KTULX4YO.js} +4 -4
- package/dist/{chunk-FZGGZAAU.js → chunk-L2QJQSHL.js} +146 -2
- package/dist/chunk-L2QJQSHL.js.map +1 -0
- package/dist/{chunk-4P4626RY.js → chunk-L4UZBJNM.js} +4 -4
- package/dist/{chunk-JLR3JSTL.js → chunk-L6V3WJ55.js} +3 -3
- package/dist/{chunk-6BISDEN6.js → chunk-LNHJ32NK.js} +14 -14
- package/dist/{chunk-437S3G37.js → chunk-LNQUAJNC.js} +1 -1
- package/dist/{chunk-LOR6ZM5R.js → chunk-MFDJ63U5.js} +2 -2
- package/dist/{chunk-HRCACVHL.js → chunk-NFTABV56.js} +2 -2
- package/dist/{chunk-OUMTBFSQ.js → chunk-NKCPUHCI.js} +5 -5
- package/dist/{chunk-KCJ5H6XQ.js → chunk-ODSYJXDU.js} +2 -2
- package/dist/{chunk-2QSZNTDO.js → chunk-RKNJBZ55.js} +4 -4
- package/dist/{chunk-NG7YBCJO.js → chunk-SNBEVJBX.js} +4 -4
- package/dist/{chunk-CZAA5N5S.js → chunk-SNNIUDRS.js} +2 -2
- package/dist/{chunk-P6SYWE4G.js → chunk-STCCFQU5.js} +9 -9
- package/dist/{chunk-X4A62ET7.js → chunk-TI7IHDBQ.js} +17 -17
- package/dist/{chunk-BGTAL46Y.js → chunk-TV7C3HCB.js} +2 -2
- package/dist/{chunk-EPGWWCZF.js → chunk-UBGAOYBP.js} +6 -6
- package/dist/{chunk-M7GGMGMZ.js → chunk-UDCDGP6A.js} +15 -15
- package/dist/{chunk-2MR3MFQB.js → chunk-UPSAT4PY.js} +2 -2
- package/dist/{chunk-CGS7UKWM.js → chunk-VCW74PNH.js} +2 -2
- package/dist/{chunk-DR6PEJU3.js → chunk-VWEWK2BM.js} +44 -59
- package/dist/chunk-VWEWK2BM.js.map +1 -0
- package/dist/{chunk-CLX5VDNY.js → chunk-Y4RKAQZ7.js} +4 -4
- package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
- package/dist/{cli-EiBBOt3r.d.ts → cli-1dghPCO2.d.ts} +3 -3
- package/dist/cli.d.ts +6 -6
- package/dist/cli.js +57 -55
- package/dist/compounding/engine.d.ts +1 -1
- package/dist/compounding/engine.js +7 -7
- 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 +1 -1
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +7 -7
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +11 -9
- package/dist/consolidation-provenance-check.d.ts +1 -1
- package/dist/consolidation-undo.d.ts +1 -1
- package/dist/contradiction/index.d.ts +1 -1
- package/dist/contradiction/index.js +4 -4
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/backend.js +2 -2
- 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/dashboard-runtime.js +2 -2
- 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 +1 -1
- package/dist/entity-retrieval.js +7 -7
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +4 -4
- 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 +1 -1
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/{first-start-migration-DY6YCRC2.js → first-start-migration-VBJQL6OI.js} +5 -5
- 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/identity-continuity.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/index.d.ts +13 -10
- package/dist/index.js +115 -93
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/engine.js +2 -2
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/index.js +2 -2
- 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 +8 -8
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +7 -7
- package/dist/maintenance/rebuild-memory-projection.js +9 -9
- package/dist/mcp-memory-inspector-app.d.ts +5 -5
- package/dist/mcp-read-only-tools.d.ts +16 -0
- package/dist/mcp-read-only-tools.js +8 -0
- package/dist/mcp-read-only-tools.js.map +1 -0
- 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 +1 -1
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +2 -2
- package/dist/namespaces/migrate.js +17 -17
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +9 -9
- package/dist/namespaces/storage.d.ts +2 -2
- package/dist/namespaces/storage.js +7 -7
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +1 -1
- package/dist/operator-toolkit.js +22 -22
- package/dist/orchestration/compression-guideline-coordinator.d.ts +1 -1
- package/dist/orchestration/maintenance.d.ts +2 -2
- package/dist/orchestration/maintenance.js +9 -9
- package/dist/{orchestrator-B2Y28Z9t.d.ts → orchestrator-Dh3WSW_O.d.ts} +3 -3
- package/dist/orchestrator.d.ts +4 -4
- package/dist/orchestrator.js +81 -79
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/provenance.d.ts +1 -1
- package/dist/{qmd-Db9mOkzB.d.ts → qmd-DoUVxqND.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/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.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-renderer.d.ts +1 -1
- package/dist/recall-xray.d.ts +1 -1
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +2 -2
- 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/schemas.d.ts +22 -22
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +8 -8
- 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/lancedb-backend.js +2 -2
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.js +2 -2
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/orama-backend.js +2 -2
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-BDVIbLRw.d.ts → semantic-consolidation-Dof1865o.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +9 -9
- package/dist/semantic-rule-promotion.js +7 -7
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +8 -8
- 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 +1 -1
- package/dist/signal.d.ts +1 -1
- package/dist/storage.d.ts +1 -1
- package/dist/storage.js +6 -6
- package/dist/summarizer.d.ts +1 -1
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/temporal-supersession.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 +1 -1
- package/dist/tier-routing.d.ts +1 -1
- package/dist/{tier-stats-TG6GUZ6N.js → tier-stats-5XF4UBRQ.js} +4 -4
- package/dist/tokens.d.ts +17 -2
- package/dist/tokens.js +3 -1
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/backup.js +2 -2
- package/dist/transfer/capsule-export.js +3 -3
- package/dist/transfer/capsule-import.js +3 -3
- package/dist/transfer/types.d.ts +12 -12
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-ljkd82rn.d.ts → types-C7HUgOuA.d.ts} +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +8 -8
- package/package.json +2 -2
- package/src/access-boundary.test.ts +62 -0
- package/src/access-boundary.ts +165 -126
- package/src/access-http.test.ts +781 -0
- package/src/access-http.ts +334 -108
- package/src/access-mcp.test.ts +264 -0
- package/src/access-mcp.ts +45 -70
- package/src/access-operations-batch.ts +35 -12
- package/src/access-surface-catalog.test.ts +22 -14
- package/src/access-surface-catalog.ts +6 -3
- package/src/access-token-capabilities.test.ts +844 -0
- package/src/access-token-capabilities.ts +391 -0
- package/src/chat/chat-mcp.test.ts +232 -0
- package/src/chat/chat-session.ts +34 -0
- package/src/index.ts +14 -0
- package/src/mcp-read-only-tools.ts +61 -0
- package/src/tokens.ts +32 -3
- package/dist/chunk-2FOD2YY3.js.map +0 -1
- package/dist/chunk-DR6PEJU3.js.map +0 -1
- package/dist/chunk-E2SPGGUI.js.map +0 -1
- package/dist/chunk-FZGGZAAU.js.map +0 -1
- package/dist/chunk-ILFJ7AVS.js.map +0 -1
- /package/dist/{capsule-crypto-CZJSLEFG.js.map → access-token-capabilities.js.map} +0 -0
- /package/dist/{auto-sync-HMHQHUAG.js.map → auto-sync-G6IU7L6C.js.map} +0 -0
- /package/dist/{chunk-7QWMTOIF.js.map → chunk-2B7DP7AP.js.map} +0 -0
- /package/dist/{chunk-4BFRBP45.js.map → chunk-2JFDHI2K.js.map} +0 -0
- /package/dist/{chunk-OHDJ34CC.js.map → chunk-2SFEFR5I.js.map} +0 -0
- /package/dist/{chunk-YDSWRD33.js.map → chunk-5K5VEDFY.js.map} +0 -0
- /package/dist/{chunk-CZAZX7JP.js.map → chunk-7BAJAXGB.js.map} +0 -0
- /package/dist/{chunk-CXLNZXG5.js.map → chunk-7XGSIUP5.js.map} +0 -0
- /package/dist/{chunk-ZPOROUTX.js.map → chunk-AOYJVCFN.js.map} +0 -0
- /package/dist/{chunk-IC6QX5TC.js.map → chunk-BGMSRN6I.js.map} +0 -0
- /package/dist/{chunk-5QZDMSSN.js.map → chunk-CXEL3Y22.js.map} +0 -0
- /package/dist/{chunk-M5QKGHCR.js.map → chunk-CYWCKFCL.js.map} +0 -0
- /package/dist/{chunk-2U2A5HF4.js.map → chunk-D2XYYU5Q.js.map} +0 -0
- /package/dist/{chunk-DGYCWCQ7.js.map → chunk-DZSAXE3T.js.map} +0 -0
- /package/dist/{chunk-2BFLDH5F.js.map → chunk-EEIROWEG.js.map} +0 -0
- /package/dist/{chunk-6ZIETXZ2.js.map → chunk-H5PFR5ZT.js.map} +0 -0
- /package/dist/{chunk-66FLU5BT.js.map → chunk-II6WHCCW.js.map} +0 -0
- /package/dist/{chunk-YPEMNNNY.js.map → chunk-ITWTKT2R.js.map} +0 -0
- /package/dist/{chunk-AKUCU7CI.js.map → chunk-JI5AVXYO.js.map} +0 -0
- /package/dist/{chunk-27FLVMDC.js.map → chunk-KMF67QDQ.js.map} +0 -0
- /package/dist/{chunk-FLVL4L3L.js.map → chunk-KTULX4YO.js.map} +0 -0
- /package/dist/{chunk-4P4626RY.js.map → chunk-L4UZBJNM.js.map} +0 -0
- /package/dist/{chunk-JLR3JSTL.js.map → chunk-L6V3WJ55.js.map} +0 -0
- /package/dist/{chunk-6BISDEN6.js.map → chunk-LNHJ32NK.js.map} +0 -0
- /package/dist/{chunk-437S3G37.js.map → chunk-LNQUAJNC.js.map} +0 -0
- /package/dist/{chunk-LOR6ZM5R.js.map → chunk-MFDJ63U5.js.map} +0 -0
- /package/dist/{chunk-HRCACVHL.js.map → chunk-NFTABV56.js.map} +0 -0
- /package/dist/{chunk-OUMTBFSQ.js.map → chunk-NKCPUHCI.js.map} +0 -0
- /package/dist/{chunk-KCJ5H6XQ.js.map → chunk-ODSYJXDU.js.map} +0 -0
- /package/dist/{chunk-2QSZNTDO.js.map → chunk-RKNJBZ55.js.map} +0 -0
- /package/dist/{chunk-NG7YBCJO.js.map → chunk-SNBEVJBX.js.map} +0 -0
- /package/dist/{chunk-CZAA5N5S.js.map → chunk-SNNIUDRS.js.map} +0 -0
- /package/dist/{chunk-P6SYWE4G.js.map → chunk-STCCFQU5.js.map} +0 -0
- /package/dist/{chunk-X4A62ET7.js.map → chunk-TI7IHDBQ.js.map} +0 -0
- /package/dist/{chunk-BGTAL46Y.js.map → chunk-TV7C3HCB.js.map} +0 -0
- /package/dist/{chunk-EPGWWCZF.js.map → chunk-UBGAOYBP.js.map} +0 -0
- /package/dist/{chunk-M7GGMGMZ.js.map → chunk-UDCDGP6A.js.map} +0 -0
- /package/dist/{chunk-2MR3MFQB.js.map → chunk-UPSAT4PY.js.map} +0 -0
- /package/dist/{chunk-CGS7UKWM.js.map → chunk-VCW74PNH.js.map} +0 -0
- /package/dist/{chunk-CLX5VDNY.js.map → chunk-Y4RKAQZ7.js.map} +0 -0
- /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
- /package/dist/{first-start-migration-DY6YCRC2.js.map → first-start-migration-VBJQL6OI.js.map} +0 -0
- /package/dist/{tier-stats-TG6GUZ6N.js.map → tier-stats-5XF4UBRQ.js.map} +0 -0
package/src/access-mcp.test.ts
CHANGED
|
@@ -13,6 +13,7 @@ import path from "node:path";
|
|
|
13
13
|
import test from "node:test";
|
|
14
14
|
|
|
15
15
|
import { EngramMcpServer } from "./access-mcp.js";
|
|
16
|
+
import { tokenCapabilityStore } from "./access-token-capabilities.js";
|
|
16
17
|
import { EngramAccessInputError, type EngramAccessService } from "./access-service.js";
|
|
17
18
|
import { parseConfig } from "./config.js";
|
|
18
19
|
import { readPair, writePair } from "./contradiction/contradiction-review.js";
|
|
@@ -979,3 +980,266 @@ test("emitLegacyTools=false still allows calling tools under BOTH names (adverti
|
|
|
979
980
|
"legacy engram.recall call still works (callability preserved)",
|
|
980
981
|
);
|
|
981
982
|
});
|
|
983
|
+
|
|
984
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
985
|
+
// Issue #1850 round 5 (finding 3): tools/list must reflect the token's ops scope
|
|
986
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
987
|
+
|
|
988
|
+
test("tools/list: deny-all (ops:[]) token sees NO tools (issue #1850 finding 3)", async () => {
|
|
989
|
+
const server = new EngramMcpServer(makeMockService(), { emitLegacyTools: false });
|
|
990
|
+
const names = await tokenCapabilityStore.run({ version: 1, ops: [] }, async () =>
|
|
991
|
+
listToolNames(await server.handleRequest(TOOLS_LIST_REQUEST)),
|
|
992
|
+
);
|
|
993
|
+
assert.deepEqual(names, [], "a deny-all token must enumerate zero tools");
|
|
994
|
+
});
|
|
995
|
+
|
|
996
|
+
test("tools/list: ops-scoped token sees ONLY its permitted tools (issue #1850 finding 3)", async () => {
|
|
997
|
+
const server = new EngramMcpServer(makeMockService(), { emitLegacyTools: false });
|
|
998
|
+
const names = await tokenCapabilityStore.run({ version: 1, ops: ["recall", "memory_get"] }, async () =>
|
|
999
|
+
listToolNames(await server.handleRequest(TOOLS_LIST_REQUEST)),
|
|
1000
|
+
);
|
|
1001
|
+
assert.ok(names.includes("remnic.recall"), "permitted recall tool advertised");
|
|
1002
|
+
assert.ok(names.includes("remnic.memory_get"), "permitted memory_get tool advertised");
|
|
1003
|
+
assert.ok(!names.includes("remnic.memory_store"), "non-permitted tool must NOT be advertised");
|
|
1004
|
+
assert.ok(!names.includes("remnic.observe"), "non-permitted tool must NOT be advertised");
|
|
1005
|
+
assert.equal(names.length, 2, "exactly the two permitted tools advertised");
|
|
1006
|
+
});
|
|
1007
|
+
|
|
1008
|
+
test("tools/list: unrestricted token (ops axis absent) sees the FULL surface (unchanged)", async () => {
|
|
1009
|
+
const server = new EngramMcpServer(makeMockService(), { emitLegacyTools: false });
|
|
1010
|
+
// No capability context at all (stdio / direct call) ⇒ full surface.
|
|
1011
|
+
const noContext = listToolNames(await server.handleRequest(TOOLS_LIST_REQUEST));
|
|
1012
|
+
// Explicit-unrestricted record (version present, no ops axis) ⇒ same surface.
|
|
1013
|
+
const explicitUnrestricted = await tokenCapabilityStore.run({ version: 1 }, async () =>
|
|
1014
|
+
listToolNames(await server.handleRequest(TOOLS_LIST_REQUEST)),
|
|
1015
|
+
);
|
|
1016
|
+
assert.deepEqual(explicitUnrestricted, noContext, "unrestricted record sees the same surface as legacy/no-context");
|
|
1017
|
+
assert.ok(noContext.length > 10, "sanity: the full tool surface is non-trivial");
|
|
1018
|
+
});
|
|
1019
|
+
|
|
1020
|
+
// ===========================================================================
|
|
1021
|
+
// Issue #1850 round 9 — MCP review_resolve namespace allow-list gate.
|
|
1022
|
+
// Mirror of the HTTP review/resolve namespace gate (access-http.test.ts).
|
|
1023
|
+
// review_resolve selects its target BY pairId, so the pair's namespace comes
|
|
1024
|
+
// from the record — NOT a request param the MCP-over-HTTP tools/call gate
|
|
1025
|
+
// (toolAcceptsNamespace) already enforces, because this tool's schema carries
|
|
1026
|
+
// no `namespace` property. A namespace-scoped bearer must NOT mutate a pair in
|
|
1027
|
+
// a namespace outside its allow-list. Both canonical (remnic.*) and legacy
|
|
1028
|
+
// (engram.*) tool-name aliases route through the SAME handler/gate.
|
|
1029
|
+
// ===========================================================================
|
|
1030
|
+
|
|
1031
|
+
test("MCP review_resolve: namespace-scoped token cannot mutate a pair in a disallowed namespace (issue #1850 round 9)", async () => {
|
|
1032
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-mcp-review-resolve-scoped-"));
|
|
1033
|
+
const allowedPair = writePair(dir, {
|
|
1034
|
+
namespace: "ns_a",
|
|
1035
|
+
memoryIds: ["a-1", "a-2"],
|
|
1036
|
+
verdict: "contradicts",
|
|
1037
|
+
rationale: "pair in the allowed namespace",
|
|
1038
|
+
confidence: 0.9,
|
|
1039
|
+
detectedAt: new Date().toISOString(),
|
|
1040
|
+
});
|
|
1041
|
+
const deniedPair = writePair(dir, {
|
|
1042
|
+
namespace: "ns_b",
|
|
1043
|
+
memoryIds: ["b-1", "b-2"],
|
|
1044
|
+
verdict: "contradicts",
|
|
1045
|
+
rationale: "pair in a denied namespace",
|
|
1046
|
+
confidence: 0.9,
|
|
1047
|
+
detectedAt: new Date().toISOString(),
|
|
1048
|
+
});
|
|
1049
|
+
const storage = { dir } as unknown as StorageManager;
|
|
1050
|
+
const service = {
|
|
1051
|
+
...makeMockService(),
|
|
1052
|
+
configRef: parseConfig({
|
|
1053
|
+
memoryDir: dir,
|
|
1054
|
+
namespacesEnabled: true,
|
|
1055
|
+
defaultNamespace: "default",
|
|
1056
|
+
}),
|
|
1057
|
+
memoryDir: dir,
|
|
1058
|
+
storageRef: storage,
|
|
1059
|
+
getWritableStorageForNamespace: async (namespace: string | undefined) => ({
|
|
1060
|
+
namespace: namespace ?? "default",
|
|
1061
|
+
storage,
|
|
1062
|
+
}),
|
|
1063
|
+
} as unknown as EngramAccessService;
|
|
1064
|
+
const server = new EngramMcpServer(service, { principal: "writer" });
|
|
1065
|
+
const readOutcome = (response: unknown): { isError: boolean; text: string } => {
|
|
1066
|
+
if (typeof response !== "object" || response === null || !("result" in response)) {
|
|
1067
|
+
return { isError: false, text: "" };
|
|
1068
|
+
}
|
|
1069
|
+
const result = response.result;
|
|
1070
|
+
if (typeof result !== "object" || result === null) return { isError: false, text: "" };
|
|
1071
|
+
const isError = "isError" in result && result.isError === true;
|
|
1072
|
+
let text = "";
|
|
1073
|
+
if ("content" in result && Array.isArray(result.content)) {
|
|
1074
|
+
const entry = result.content[0];
|
|
1075
|
+
if (entry != null && typeof entry === "object" && "text" in entry && typeof entry.text === "string") {
|
|
1076
|
+
text = entry.text;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
return { isError, text };
|
|
1080
|
+
};
|
|
1081
|
+
try {
|
|
1082
|
+
// ── scoped to ns_a: denied-namespace pair → isError (fail closed), NOT mutated ──
|
|
1083
|
+
const denied = await tokenCapabilityStore.run({ version: 1, namespaces: ["ns_a"] }, async () =>
|
|
1084
|
+
readOutcome(await server.handleRequest(makeToolRequest("engram.review_resolve", { pairId: deniedPair.pairId, verb: "both-valid" }))),
|
|
1085
|
+
);
|
|
1086
|
+
assert.equal(denied.isError, true, "scoped resolve: a pair in an unlisted namespace must be denied");
|
|
1087
|
+
assert.match(denied.text, /ns_b/, "denial message names the forbidden namespace");
|
|
1088
|
+
assert.notEqual(
|
|
1089
|
+
readPair(dir, deniedPair.pairId)?.resolution,
|
|
1090
|
+
"both-valid",
|
|
1091
|
+
"scoped resolve: the denied pair must remain unresolved (no mutation leak)",
|
|
1092
|
+
);
|
|
1093
|
+
|
|
1094
|
+
// ── scoped to ns_a: allowed-namespace pair → resolves, mutated ──
|
|
1095
|
+
const allowed = await tokenCapabilityStore.run({ version: 1, namespaces: ["ns_a"] }, async () =>
|
|
1096
|
+
readOutcome(await server.handleRequest(makeToolRequest("engram.review_resolve", { pairId: allowedPair.pairId, verb: "both-valid" }))),
|
|
1097
|
+
);
|
|
1098
|
+
assert.equal(allowed.isError, false, "scoped resolve: a pair in the allowed namespace must succeed");
|
|
1099
|
+
assert.equal(
|
|
1100
|
+
readPair(dir, allowedPair.pairId)?.resolution,
|
|
1101
|
+
"both-valid",
|
|
1102
|
+
"scoped resolve: the allowed pair is marked resolved",
|
|
1103
|
+
);
|
|
1104
|
+
|
|
1105
|
+
// ── canonical alias (remnic.review_resolve) routes through the SAME gate ──
|
|
1106
|
+
const deniedCanonical = writePair(dir, {
|
|
1107
|
+
namespace: "ns_b",
|
|
1108
|
+
memoryIds: ["b-3", "b-4"],
|
|
1109
|
+
verdict: "contradicts",
|
|
1110
|
+
rationale: "pair for canonical-alias denial",
|
|
1111
|
+
confidence: 0.9,
|
|
1112
|
+
detectedAt: new Date().toISOString(),
|
|
1113
|
+
});
|
|
1114
|
+
const deniedViaCanonical = await tokenCapabilityStore.run({ version: 1, namespaces: ["ns_a"] }, async () =>
|
|
1115
|
+
readOutcome(await server.handleRequest(makeToolRequest("remnic.review_resolve", { pairId: deniedCanonical.pairId, verb: "both-valid" }))),
|
|
1116
|
+
);
|
|
1117
|
+
assert.equal(deniedViaCanonical.isError, true, "canonical alias remnic.review_resolve must also be gated");
|
|
1118
|
+
assert.match(deniedViaCanonical.text, /ns_b/, "canonical-alias denial names the forbidden namespace");
|
|
1119
|
+
assert.notEqual(
|
|
1120
|
+
readPair(dir, deniedCanonical.pairId)?.resolution,
|
|
1121
|
+
"both-valid",
|
|
1122
|
+
"canonical-alias denied pair must remain unresolved",
|
|
1123
|
+
);
|
|
1124
|
+
|
|
1125
|
+
// ── unrestricted token (no namespaces axis): the denied-namespace pair is reachable ──
|
|
1126
|
+
const unrestrictedDenied = await tokenCapabilityStore.run({ version: 1 }, async () =>
|
|
1127
|
+
readOutcome(await server.handleRequest(makeToolRequest("engram.review_resolve", { pairId: deniedPair.pairId, verb: "both-valid" }))),
|
|
1128
|
+
);
|
|
1129
|
+
assert.equal(unrestrictedDenied.isError, false, "unrestricted token: the denied-namespace pair is reachable");
|
|
1130
|
+
assert.equal(
|
|
1131
|
+
readPair(dir, deniedPair.pairId)?.resolution,
|
|
1132
|
+
"both-valid",
|
|
1133
|
+
"unrestricted token resolves the previously-denied pair",
|
|
1134
|
+
);
|
|
1135
|
+
} finally {
|
|
1136
|
+
await rm(dir, { recursive: true, force: true });
|
|
1137
|
+
}
|
|
1138
|
+
});
|
|
1139
|
+
|
|
1140
|
+
// ===========================================================================
|
|
1141
|
+
// Issue #1850 round 10 — fleet-wide maintenance ops namespace gate.
|
|
1142
|
+
// These ops run ACROSS ALL namespaces (or a global non-namespaced layer) and
|
|
1143
|
+
// carry NO `namespace` arg, so the MCP tools/call effective-namespace
|
|
1144
|
+
// chokepoint (toolAcceptsNamespace) never fires. The `fleetWide` flag on each
|
|
1145
|
+
// op makes defineOperation's run wrapper reject a namespace-scoped token
|
|
1146
|
+
// BEFORE the handler — no side effect on denial; unrestricted/legacy allowed.
|
|
1147
|
+
// Both canonical (remnic.*) and legacy (engram.*) aliases route through the
|
|
1148
|
+
// SAME gate.
|
|
1149
|
+
// ===========================================================================
|
|
1150
|
+
|
|
1151
|
+
function readCallToolOutcome(response: unknown): { isError: boolean; text: string } {
|
|
1152
|
+
if (typeof response !== "object" || response === null || !("result" in response)) {
|
|
1153
|
+
return { isError: false, text: "" };
|
|
1154
|
+
}
|
|
1155
|
+
const result = response.result;
|
|
1156
|
+
if (typeof result !== "object" || result === null) return { isError: false, text: "" };
|
|
1157
|
+
const isError = "isError" in result && result.isError === true;
|
|
1158
|
+
let text = "";
|
|
1159
|
+
if ("content" in result && Array.isArray(result.content)) {
|
|
1160
|
+
const entry = result.content[0];
|
|
1161
|
+
if (entry != null && typeof entry === "object" && "text" in entry && typeof entry.text === "string") {
|
|
1162
|
+
text = entry.text;
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
return { isError, text };
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
const FLEET_WIDE_MAINTENANCE_TOOLS = [
|
|
1169
|
+
"graph_edge_decay_run",
|
|
1170
|
+
"memory_summarize_hourly",
|
|
1171
|
+
"conversation_index_update",
|
|
1172
|
+
"live_connectors_run",
|
|
1173
|
+
"continuity_audit_generate",
|
|
1174
|
+
"shared_context_cross_signals_run",
|
|
1175
|
+
"shared_context_curate_daily",
|
|
1176
|
+
"compounding_weekly_synthesize",
|
|
1177
|
+
"compounding_promote_candidate",
|
|
1178
|
+
"compression_guidelines_optimize",
|
|
1179
|
+
"compression_guidelines_activate",
|
|
1180
|
+
] as const;
|
|
1181
|
+
|
|
1182
|
+
test("MCP fleet-wide maintenance ops: namespace-scoped token denied for every op, no side effect (issue #1850 round 10)", async () => {
|
|
1183
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-mcp-fleetwide-scoped-"));
|
|
1184
|
+
let sideEffects = 0;
|
|
1185
|
+
// Every fleet-wide op that dispatches to a service method routes through
|
|
1186
|
+
// this tracker; graph_edge_decay_run short-circuits via graphEdgeDecayEnabled
|
|
1187
|
+
// false. Under a scoped token NONE may run — the guard throws first.
|
|
1188
|
+
const track = (): Promise<{ ok: true }> => { sideEffects += 1; return Promise.resolve({ ok: true }); };
|
|
1189
|
+
const service = {
|
|
1190
|
+
...makeMockService(),
|
|
1191
|
+
configRef: parseConfig({ memoryDir: dir, graphEdgeDecayEnabled: false }),
|
|
1192
|
+
memoryDir: dir,
|
|
1193
|
+
memorySummarizeHourly: track,
|
|
1194
|
+
conversationIndexUpdate: track,
|
|
1195
|
+
liveConnectorsRun: track,
|
|
1196
|
+
continuityAuditGenerate: track,
|
|
1197
|
+
sharedContextCrossSignalsRun: track,
|
|
1198
|
+
sharedContextCurateDaily: track,
|
|
1199
|
+
compoundingWeeklySynthesize: track,
|
|
1200
|
+
compoundingPromoteCandidate: track,
|
|
1201
|
+
compressionGuidelinesOptimize: track,
|
|
1202
|
+
compressionGuidelinesActivate: track,
|
|
1203
|
+
} as unknown as EngramAccessService;
|
|
1204
|
+
const server = new EngramMcpServer(service, { principal: "ops" });
|
|
1205
|
+
try {
|
|
1206
|
+
for (const tool of FLEET_WIDE_MAINTENANCE_TOOLS) {
|
|
1207
|
+
// Legacy alias (engra.*).
|
|
1208
|
+
const legacy = await tokenCapabilityStore.run({ version: 1, namespaces: ["ns_a"] }, async () =>
|
|
1209
|
+
readCallToolOutcome(await server.handleRequest(makeToolRequest("engram." + tool))),
|
|
1210
|
+
);
|
|
1211
|
+
assert.equal(legacy.isError, true, `engram.${tool}: a namespace-scoped token must be denied`);
|
|
1212
|
+
assert.match(legacy.text, /across all namespaces/, `engram.${tool}: denial names the fleet-wide restriction`);
|
|
1213
|
+
// Canonical alias (remnic.*) routes through the SAME gate.
|
|
1214
|
+
const canonical = await tokenCapabilityStore.run({ version: 1, namespaces: ["ns_a"] }, async () =>
|
|
1215
|
+
readCallToolOutcome(await server.handleRequest(makeToolRequest("remnic." + tool))),
|
|
1216
|
+
);
|
|
1217
|
+
assert.equal(canonical.isError, true, `remnic.${tool}: canonical alias must also be gated`);
|
|
1218
|
+
}
|
|
1219
|
+
assert.equal(sideEffects, 0, "no fleet-wide maintenance service method may run for a namespace-scoped token");
|
|
1220
|
+
} finally {
|
|
1221
|
+
await rm(dir, { recursive: true, force: true });
|
|
1222
|
+
}
|
|
1223
|
+
});
|
|
1224
|
+
|
|
1225
|
+
test("MCP graph_edge_decay_run: unrestricted and legacy tokens reach the handler (issue #1850 round 10)", async () => {
|
|
1226
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-mcp-decay-unrestricted-"));
|
|
1227
|
+
try {
|
|
1228
|
+
const service = {
|
|
1229
|
+
...makeMockService(),
|
|
1230
|
+
configRef: parseConfig({ memoryDir: dir, graphEdgeDecayEnabled: false }),
|
|
1231
|
+
memoryDir: dir,
|
|
1232
|
+
} as unknown as EngramAccessService;
|
|
1233
|
+
const server = new EngramMcpServer(service, { principal: "ops" });
|
|
1234
|
+
// Explicit-unrestricted record (version present, no namespaces axis).
|
|
1235
|
+
const unrestricted = await tokenCapabilityStore.run({ version: 1 }, async () =>
|
|
1236
|
+
readCallToolOutcome(await server.handleRequest(makeToolRequest("engram.graph_edge_decay_run"))),
|
|
1237
|
+
);
|
|
1238
|
+
assert.equal(unrestricted.isError, false, "unrestricted token reaches the handler");
|
|
1239
|
+
// Legacy / no ALS at all (cron, internal caller) — same path.
|
|
1240
|
+
const legacy = readCallToolOutcome(await server.handleRequest(makeToolRequest("remnic.graph_edge_decay_run")));
|
|
1241
|
+
assert.equal(legacy.isError, false, "legacy token (no ALS) reaches the handler");
|
|
1242
|
+
} finally {
|
|
1243
|
+
await rm(dir, { recursive: true, force: true });
|
|
1244
|
+
}
|
|
1245
|
+
});
|
package/src/access-mcp.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type { Readable, Writable } from "node:stream";
|
|
|
5
5
|
// (memory_get / memory_search / memory_store) as a side effect; callTool
|
|
6
6
|
// dispatches migrated tools through the registry (issue #1525).
|
|
7
7
|
import { type OperationName, getOperation } from "./access-boundary.js";
|
|
8
|
+
import { assertOperationAllowed, capabilityAllowsOp, enforceNamespaceAllowList, tokenCapabilityStore } from "./access-token-capabilities.js";
|
|
8
9
|
import {
|
|
9
10
|
type ActionConfidenceRequest,
|
|
10
11
|
type CapsuleExportRequest,
|
|
@@ -20,6 +21,7 @@ import { EngramAccessInputError, type EngramAccessRecallResponse, type EngramAcc
|
|
|
20
21
|
import "./access-operations.js";
|
|
21
22
|
import { validateBriefingFormat } from "./briefing.js";
|
|
22
23
|
import { processChatMessage } from "./chat/chat-factory.js";
|
|
24
|
+
import { enforceChatSessionNamespace } from "./chat/chat-session.js";
|
|
23
25
|
import { type CitationMetadata, buildCitationGuidance } from "./citations.js";
|
|
24
26
|
import { projectTagProjectId } from "./coding/coding-namespace.js";
|
|
25
27
|
import {
|
|
@@ -37,6 +39,7 @@ import type { RecallDisclosure, RecallPlanMode } from "./types.js";
|
|
|
37
39
|
import { expandTildePath } from "./utils/path.js";
|
|
38
40
|
|
|
39
41
|
import { applyToolOutputSchemas } from "./access-mcp-output-schemas.js";
|
|
42
|
+
import { MCP_READ_ONLY_TOOL_SUFFIXES } from "./mcp-read-only-tools.js";
|
|
40
43
|
type JsonRpcId = string | number | null;
|
|
41
44
|
|
|
42
45
|
type JsonRpcRequest = {
|
|
@@ -79,68 +82,6 @@ type McpResource = {
|
|
|
79
82
|
_meta?: Record<string, unknown>;
|
|
80
83
|
};
|
|
81
84
|
|
|
82
|
-
/**
|
|
83
|
-
* Conservative allowlist of canonical MCP tool suffixes that are
|
|
84
|
-
* unambiguously read-only. Tools in this set are tagged with
|
|
85
|
-
* `annotations: { readOnlyHint: true }` so ChatGPT (and other MCP
|
|
86
|
-
* clients that honor the hint) can skip per-call confirmation.
|
|
87
|
-
*
|
|
88
|
-
* The list is suffix-based so it covers both the `remnic.*` and
|
|
89
|
-
* `engram.*` naming forms. Anything not on it stays unannotated:
|
|
90
|
-
* uncertainty is resolved as "might mutate".
|
|
91
|
-
*
|
|
92
|
-
* Excluded by construction: anything that writes, runs a pipeline,
|
|
93
|
-
* flushes, applies, records, imports, or destructively deletes.
|
|
94
|
-
*/
|
|
95
|
-
const MCP_READ_ONLY_TOOL_SUFFIXES: Readonly<Record<string, true>> = {
|
|
96
|
-
recall: true,
|
|
97
|
-
recall_explain: true,
|
|
98
|
-
recall_tier_explain: true,
|
|
99
|
-
recall_xray: true,
|
|
100
|
-
briefing: true,
|
|
101
|
-
wearables_status: true,
|
|
102
|
-
transcript_day: true,
|
|
103
|
-
transcript_search: true,
|
|
104
|
-
transcript_memories: true,
|
|
105
|
-
action_confidence: true,
|
|
106
|
-
capsule_list: true,
|
|
107
|
-
procedural_stats: true,
|
|
108
|
-
memory_get: true,
|
|
109
|
-
memory_timeline: true,
|
|
110
|
-
entity_get: true,
|
|
111
|
-
review_queue_list: true,
|
|
112
|
-
lcm_search: true,
|
|
113
|
-
continuity_incident_list: true,
|
|
114
|
-
identity_anchor_get: true,
|
|
115
|
-
memory_identity: true,
|
|
116
|
-
memory_search: true,
|
|
117
|
-
memory_profile: true,
|
|
118
|
-
memory_entities_list: true,
|
|
119
|
-
memory_questions: true,
|
|
120
|
-
memory_last_recall: true,
|
|
121
|
-
memory_intent_debug: true,
|
|
122
|
-
memory_qmd_debug: true,
|
|
123
|
-
memory_graph_explain: true,
|
|
124
|
-
graph_snapshot: true,
|
|
125
|
-
review_list: true,
|
|
126
|
-
profiling_report: true,
|
|
127
|
-
peer_list: true,
|
|
128
|
-
peer_get: true,
|
|
129
|
-
peer_profile_get: true,
|
|
130
|
-
console_state: true,
|
|
131
|
-
dreams_status: true,
|
|
132
|
-
codegraph_list_projects: true,
|
|
133
|
-
codegraph_index_status: true,
|
|
134
|
-
codegraph_search_graph: true,
|
|
135
|
-
codegraph_trace_path: true,
|
|
136
|
-
codegraph_detect_changes: true,
|
|
137
|
-
codegraph_query_graph: true,
|
|
138
|
-
codegraph_get_schema: true,
|
|
139
|
-
codegraph_get_snippet: true,
|
|
140
|
-
codegraph_get_architecture: true,
|
|
141
|
-
codegraph_search_code: true,
|
|
142
|
-
};
|
|
143
|
-
|
|
144
85
|
/**
|
|
145
86
|
* MCP protocol versions this server understands, ordered newest → oldest.
|
|
146
87
|
* Exported so the HTTP transport can validate the `MCP-Protocol-Version`
|
|
@@ -2592,13 +2533,15 @@ export class EngramMcpServer {
|
|
|
2592
2533
|
};
|
|
2593
2534
|
}
|
|
2594
2535
|
if (method === "tools/list") {
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2536
|
+
// Issue #1850 round 5 (finding 3): a scoped/deny-all token must not
|
|
2537
|
+
// enumerate the full tool surface — filter advertised tools by the
|
|
2538
|
+
// token's ops allow-list via the same map callTool uses. Unrestricted
|
|
2539
|
+
// tokens (ops axis absent) see everything; unmapped tool ⇒ "" ⇒ hidden.
|
|
2540
|
+
const caps = tokenCapabilityStore.getStore();
|
|
2541
|
+
const tools = caps?.ops === undefined
|
|
2542
|
+
? this.tools
|
|
2543
|
+
: this.tools.filter((t) => capabilityAllowsOp(caps, MCP_MIGRATED_OPERATIONS[toLegacyToolName(t.name)] ?? ""));
|
|
2544
|
+
return { jsonrpc: "2.0", id, result: { tools } };
|
|
2602
2545
|
}
|
|
2603
2546
|
if (method === "resources/list") {
|
|
2604
2547
|
return {
|
|
@@ -2838,6 +2781,19 @@ export class EngramMcpServer {
|
|
|
2838
2781
|
return inputSchema?.additionalProperties === true;
|
|
2839
2782
|
}
|
|
2840
2783
|
|
|
2784
|
+
/**
|
|
2785
|
+
* Whether a tool accepts a `namespace` argument — i.e. it is a
|
|
2786
|
+
* namespace-scoped operation whose effective namespace MUST be gated by the
|
|
2787
|
+
* per-token allow-list. Exposed (public) so the HTTP MCP transport can run
|
|
2788
|
+
* the SAME effective-namespace enforcement the REST surface runs, without
|
|
2789
|
+
* duplicating the tool-schema introspection (issue #1850). Namespace-
|
|
2790
|
+
* agnostic tools (peer/wearables/etc.) return false and stay ungated,
|
|
2791
|
+
* matching the REST surface where those routes never call resolveNamespace.
|
|
2792
|
+
*/
|
|
2793
|
+
toolAcceptsNamespace(name: string): boolean {
|
|
2794
|
+
return this.toolAcceptsArgument(name, "namespace");
|
|
2795
|
+
}
|
|
2796
|
+
|
|
2841
2797
|
/**
|
|
2842
2798
|
* Determine whether oai-mem-citation guidance should be appended to recall.
|
|
2843
2799
|
* Returns true when explicitly enabled via config OR when auto-detect is
|
|
@@ -2931,10 +2887,29 @@ export class EngramMcpServer {
|
|
|
2931
2887
|
} else if (migrated.startsWith("codegraph_")) {
|
|
2932
2888
|
envelope = { ...args, tool: migrated.slice("codegraph_".length) };
|
|
2933
2889
|
} else if (migrated === "chat_message") {
|
|
2934
|
-
// memory_chat
|
|
2890
|
+
// memory_chat bypasses op.run(); gate op + resumed-session namespace like the HTTP route (#1850 r6).
|
|
2891
|
+
assertOperationAllowed(tokenCapabilityStore.getStore(), migrated);
|
|
2935
2892
|
const message = typeof args.message === "string" ? args.message : "";
|
|
2936
2893
|
if (!message) throw new EngramAccessInputError("message is required");
|
|
2937
2894
|
const chatSessionId = typeof args.chatSessionId === "string" ? args.chatSessionId : undefined;
|
|
2895
|
+
if (chatSessionId) {
|
|
2896
|
+
await enforceChatSessionNamespace(this.service, chatSessionId);
|
|
2897
|
+
} else {
|
|
2898
|
+
// NEW chat session (no chatSessionId): processChatMessage mints a fresh
|
|
2899
|
+
// session under the EFFECTIVE namespace (scope.namespace OR server
|
|
2900
|
+
// default). Unlike the HTTP chat handler (which forwards no namespace),
|
|
2901
|
+
// the MCP scope CAN carry one (Thread 17), so route it through the SAME
|
|
2902
|
+
// effective-namespace chokepoint as the HTTP new-chat path
|
|
2903
|
+
// (enforceNamespaceAllowList maps undefined → default) — a namespace-
|
|
2904
|
+
// scoped token CANNOT start a chat in a namespace outside its allow-
|
|
2905
|
+
// list, including an unconfigured/forbidden server default. Fail closed;
|
|
2906
|
+
// no-op for unrestricted/legacy tokens (issue #1850 round 8).
|
|
2907
|
+
enforceNamespaceAllowList(
|
|
2908
|
+
tokenCapabilityStore.getStore(),
|
|
2909
|
+
scope?.namespace,
|
|
2910
|
+
this.service.configRef?.defaultNamespace,
|
|
2911
|
+
);
|
|
2912
|
+
}
|
|
2938
2913
|
const chatResult = await processChatMessage({
|
|
2939
2914
|
service: this.service,
|
|
2940
2915
|
config: this.service.configRef?.chat,
|
|
@@ -16,6 +16,7 @@ import type { RemnicChatGptMemoryInspectorInput } from "./mcp-memory-inspector-a
|
|
|
16
16
|
import { defineOperation } from "./access-boundary.js";
|
|
17
17
|
import { EngramAccessForbiddenError } from "./access-errors.js";
|
|
18
18
|
import { EngramAccessInputError, type EngramAccessService } from "./access-service.js";
|
|
19
|
+
import { enforceNamespaceAllowList, tokenCapabilityStore } from "./access-token-capabilities.js";
|
|
19
20
|
import { projectTagProjectId } from "./coding/coding-namespace.js";
|
|
20
21
|
import { expandTildePath } from "./utils/path.js";
|
|
21
22
|
import { resolvePrincipal } from "./namespaces/principal.js";
|
|
@@ -25,7 +26,7 @@ import {
|
|
|
25
26
|
buildChatGptMemoryInspectorActionRequest,
|
|
26
27
|
buildChatGptMemoryInspectorResult,
|
|
27
28
|
} from "./mcp-memory-inspector-app.js";
|
|
28
|
-
import { listPairs, isDefaultReviewNamespace } from "./contradiction/contradiction-review.js";
|
|
29
|
+
import { listPairs, isDefaultReviewNamespace, readPair } from "./contradiction/contradiction-review.js";
|
|
29
30
|
import { executeResolution, isValidResolutionVerb } from "./contradiction/resolution.js";
|
|
30
31
|
import { runContradictionScan } from "./contradiction/contradiction-scan.js";
|
|
31
32
|
import { runGraphEdgeDecayMaintenanceAcrossNamespaces } from "./maintenance/graph-edge-decay.js";
|
|
@@ -166,7 +167,7 @@ defineOperation({ name: "lcm_compaction_flush", description: "Flush LCM compacti
|
|
|
166
167
|
defineOperation({ name: "lcm_compaction_record", description: "Record LCM compaction.", schema: strictSchema({ sessionKey: S.str, namespace: S.str, tokensBefore: S.num, tokensAfter: S.num }), handler: async (input, ctx) => ({ result: await ctx.service.lcmCompactionRecord({ sessionKey: optStr(input.sessionKey) ?? "", namespace: optStr(input.namespace), tokensBefore: optNum(input.tokensBefore) ?? 0, tokensAfter: optNum(input.tokensAfter) ?? 0, authenticatedPrincipal: ctx.authenticatedPrincipal }) }) });
|
|
167
168
|
|
|
168
169
|
// === CONTINUITY/IDENTITY ===
|
|
169
|
-
defineOperation({ name: "continuity_audit_generate", description: "Continuity audit.", schema: strictSchema({ period: S.str, key: S.str }), handler: async (input, ctx) => ({ result: await ctx.service.continuityAuditGenerate({ period: optStr(input.period) === "monthly" ? "monthly" : optStr(input.period) === "weekly" ? "weekly" : undefined, key: optStr(input.key) }) }) });
|
|
170
|
+
defineOperation({ name: "continuity_audit_generate", description: "Continuity audit.", fleetWide: true, schema: strictSchema({ period: S.str, key: S.str }), handler: async (input, ctx) => ({ result: await ctx.service.continuityAuditGenerate({ period: optStr(input.period) === "monthly" ? "monthly" : optStr(input.period) === "weekly" ? "weekly" : undefined, key: optStr(input.key) }) }) });
|
|
170
171
|
defineOperation({ name: "continuity_incident_open", description: "Open incident.", schema: strictSchema({ symptom: S.str, namespace: S.str, triggerWindow: S.str, suspectedCause: S.str }), handler: async (input, ctx) => ({ result: await ctx.service.continuityIncidentOpen({ symptom: optStr(input.symptom) ?? "", namespace: optStr(input.namespace), triggerWindow: optStr(input.triggerWindow), suspectedCause: optStr(input.suspectedCause), principal: ctx.authenticatedPrincipal }) }) });
|
|
171
172
|
defineOperation({ name: "continuity_incident_close", description: "Close incident.", schema: strictSchema({ id: S.str, namespace: S.str, fixApplied: S.str, verificationResult: S.str, preventiveRule: S.str }), handler: async (input, ctx) => ({ result: await ctx.service.continuityIncidentClose({ id: optStr(input.id) ?? "", namespace: optStr(input.namespace), fixApplied: optStr(input.fixApplied) ?? "", verificationResult: optStr(input.verificationResult) ?? "", preventiveRule: optStr(input.preventiveRule), principal: ctx.authenticatedPrincipal }) }) });
|
|
172
173
|
defineOperation({ name: "continuity_incident_list", description: "List incidents.", schema: strictSchema({ state: S.str, namespace: S.str, limit: S.num }), handler: async (input, ctx) => { const st = optStr(input.state); return { result: await ctx.service.continuityIncidentList({ state: st === "closed" ? "closed" : st === "all" ? "all" : st === "open" ? "open" : undefined, namespace: optStr(input.namespace), limit: optNum(input.limit), principal: ctx.authenticatedPrincipal }) }; } });
|
|
@@ -183,12 +184,12 @@ defineOperation({ name: "work_board", description: "Manage work board.", schema:
|
|
|
183
184
|
defineOperation({ name: "shared_context_write_output", description: "Write shared output.", schema: strictSchema({ agentId: S.str, title: S.str, content: S.str }), handler: async (input, ctx) => ({ result: await ctx.service.sharedContextWriteOutput({ agentId: optStr(input.agentId) ?? "", title: optStr(input.title) ?? "", content: optStr(input.content) ?? "" }) }) });
|
|
184
185
|
defineOperation({ name: "shared_feedback_record", description: "Record shared feedback.", schema: strictSchema({ agent: S.str, decision: S.str, reason: S.str, date: S.str, learning: S.str, outcome: S.str, severity: S.str, confidence: S.num, workflow: S.str, tags: S.strArr, evidenceWindowStart: S.str, evidenceWindowEnd: S.str, refs: S.strArr }), handler: async (input, ctx) => { const sv = optStr(input.severity); return { result: await ctx.service.sharedFeedbackRecord({ agent: optStr(input.agent) ?? "", decision: (optStr(input.decision) as "rejected" | "approved" | "approved_with_feedback") ?? "approved", reason: optStr(input.reason) ?? "", date: optStr(input.date), learning: optStr(input.learning), outcome: optStr(input.outcome), severity: sv === "low" || sv === "medium" || sv === "high" ? sv as "low" | "medium" | "high" : undefined, confidence: optNum(input.confidence), workflow: optStr(input.workflow), tags: optStrArr(input.tags), evidenceWindowStart: optStr(input.evidenceWindowStart), evidenceWindowEnd: optStr(input.evidenceWindowEnd), refs: optStrArr(input.refs) }) }; } });
|
|
185
186
|
defineOperation({ name: "shared_priorities_append", description: "Append priorities.", schema: strictSchema({ agentId: S.str, text: S.str }), handler: async (input, ctx) => ({ result: await ctx.service.sharedPrioritiesAppend({ agentId: optStr(input.agentId) ?? "", text: optStr(input.text) ?? "" }) }) });
|
|
186
|
-
defineOperation({ name: "shared_context_cross_signals_run", description: "Run cross signals.", schema: strictSchema({ date: S.str }), handler: async (input, ctx) => ({ result: await ctx.service.sharedContextCrossSignalsRun({ date: optStr(input.date) }) }) });
|
|
187
|
-
defineOperation({ name: "shared_context_curate_daily", description: "Curate daily.", schema: strictSchema({ date: S.str }), handler: async (input, ctx) => ({ result: await ctx.service.sharedContextCurateDaily({ date: optStr(input.date) }) }) });
|
|
188
|
-
defineOperation({ name: "compounding_weekly_synthesize", description: "Weekly synthesize.", schema: strictSchema({ weekId: S.str }), handler: async (input, ctx) => ({ result: await ctx.service.compoundingWeeklySynthesize({ weekId: optStr(input.weekId) }) }) });
|
|
189
|
-
defineOperation({ name: "compounding_promote_candidate", description: "Promote candidate.", schema: strictSchema({ weekId: S.str, candidateId: S.str, dryRun: S.bool }), handler: async (input, ctx) => ({ result: await ctx.service.compoundingPromoteCandidate({ weekId: optStr(input.weekId) ?? "", candidateId: optStr(input.candidateId) ?? "", dryRun: input.dryRun === true }) }) });
|
|
190
|
-
defineOperation({ name: "compression_guidelines_optimize", description: "Optimize guidelines.", schema: strictSchema({ dryRun: S.bool, eventLimit: S.num }), handler: async (input, ctx) => ({ result: await ctx.service.compressionGuidelinesOptimize({ dryRun: input.dryRun === true, eventLimit: optNum(input.eventLimit) }) }) });
|
|
191
|
-
defineOperation({ name: "compression_guidelines_activate", description: "Activate guidelines.", schema: strictSchema({ expectedContentHash: S.str, expectedGuidelineVersion: S.num }), handler: async (input, ctx) => ({ result: await ctx.service.compressionGuidelinesActivate({ expectedContentHash: optStr(input.expectedContentHash), expectedGuidelineVersion: optNum(input.expectedGuidelineVersion) }) }) });
|
|
187
|
+
defineOperation({ name: "shared_context_cross_signals_run", description: "Run cross signals.", fleetWide: true, schema: strictSchema({ date: S.str }), handler: async (input, ctx) => ({ result: await ctx.service.sharedContextCrossSignalsRun({ date: optStr(input.date) }) }) });
|
|
188
|
+
defineOperation({ name: "shared_context_curate_daily", description: "Curate daily.", fleetWide: true, schema: strictSchema({ date: S.str }), handler: async (input, ctx) => ({ result: await ctx.service.sharedContextCurateDaily({ date: optStr(input.date) }) }) });
|
|
189
|
+
defineOperation({ name: "compounding_weekly_synthesize", description: "Weekly synthesize.", fleetWide: true, schema: strictSchema({ weekId: S.str }), handler: async (input, ctx) => ({ result: await ctx.service.compoundingWeeklySynthesize({ weekId: optStr(input.weekId) }) }) });
|
|
190
|
+
defineOperation({ name: "compounding_promote_candidate", description: "Promote candidate.", fleetWide: true, schema: strictSchema({ weekId: S.str, candidateId: S.str, dryRun: S.bool }), handler: async (input, ctx) => ({ result: await ctx.service.compoundingPromoteCandidate({ weekId: optStr(input.weekId) ?? "", candidateId: optStr(input.candidateId) ?? "", dryRun: input.dryRun === true }) }) });
|
|
191
|
+
defineOperation({ name: "compression_guidelines_optimize", description: "Optimize guidelines.", fleetWide: true, schema: strictSchema({ dryRun: S.bool, eventLimit: S.num }), handler: async (input, ctx) => ({ result: await ctx.service.compressionGuidelinesOptimize({ dryRun: input.dryRun === true, eventLimit: optNum(input.eventLimit) }) }) });
|
|
192
|
+
defineOperation({ name: "compression_guidelines_activate", description: "Activate guidelines.", fleetWide: true, schema: strictSchema({ expectedContentHash: S.str, expectedGuidelineVersion: S.num }), handler: async (input, ctx) => ({ result: await ctx.service.compressionGuidelinesActivate({ expectedContentHash: optStr(input.expectedContentHash), expectedGuidelineVersion: optNum(input.expectedGuidelineVersion) }) }) });
|
|
192
193
|
|
|
193
194
|
// === MEMORY DEBUG/GRAPH/FEEDBACK ===
|
|
194
195
|
defineOperation({ name: "memory_profile", description: "Memory profile.", schema: strictSchema({ namespace: S.str }), handler: async (input, ctx) => ({ result: await ctx.service.memoryProfile(optStr(input.namespace), ctx.authenticatedPrincipal) }) });
|
|
@@ -225,17 +226,38 @@ defineOperation({ name: "review_resolve", description: "Resolve pair.", schema:
|
|
|
225
226
|
if (!pid) throw new EngramAccessInputError("pairId is required");
|
|
226
227
|
if (!vb) throw new EngramAccessInputError("verb is required");
|
|
227
228
|
if (!isValidResolutionVerb(vb)) throw new EngramAccessInputError("Invalid verb: " + vb);
|
|
229
|
+
// Per-token namespace enforcement (issue #1850 round 9): review_resolve
|
|
230
|
+
// selects its target BY pairId, so the affected namespace comes from the
|
|
231
|
+
// record — NOT a request param that the MCP-over-HTTP tools/call gate
|
|
232
|
+
// (toolAcceptsNamespace) already enforces (this tool's schema carries no
|
|
233
|
+
// `namespace` property). A namespace-scoped bearer must not mutate a
|
|
234
|
+
// contradiction pair in a namespace outside its allow-list. Load the pair
|
|
235
|
+
// to learn its namespace, enforce the token's scope via the SAME
|
|
236
|
+
// effective-namespace chokepoint the HTTP review/resolve route uses
|
|
237
|
+
// (enforceNamespaceAllowList maps undefined → default, so a scoped token
|
|
238
|
+
// whose allow-list INCLUDES the default can resolve a legacy pair), and
|
|
239
|
+
// fail closed BEFORE dispatching the (mutating) resolution. A missing pair
|
|
240
|
+
// falls through to executeResolution's existing not-found result. No-op for
|
|
241
|
+
// unrestricted/legacy tokens. Mirrors access-http.ts review/resolve exactly.
|
|
242
|
+
const targetPair = readPair(ctx.service.memoryDir, pid);
|
|
243
|
+
if (targetPair) {
|
|
244
|
+
enforceNamespaceAllowList(
|
|
245
|
+
tokenCapabilityStore.getStore(),
|
|
246
|
+
targetPair.namespace,
|
|
247
|
+
ctx.service.configRef?.defaultNamespace,
|
|
248
|
+
);
|
|
249
|
+
}
|
|
228
250
|
return { result: await executeResolution(ctx.service.memoryDir, ctx.service.storageRef, pid, vb, { mergedMemoryId: optStr(input.mergedMemoryId), mergedContent: optStr(input.mergedContent), storageForNamespace: async (namespace) => { const r = await ctx.service.getWritableStorageForNamespace(namespace, ctx.authenticatedPrincipal); return r.storage; }, onMergedMemoryWritten: () => {} }) };
|
|
229
251
|
},
|
|
230
252
|
});
|
|
231
253
|
defineOperation({ name: "contradiction_scan_run", description: "Run scan.", schema: strictSchema({ namespace: S.str }), handler: async (input, ctx) => ({ result: await runContradictionScan({ storage: ctx.service.storageRef, config: ctx.service.configRef, memoryDir: ctx.service.memoryDir, embeddingLookupFactory: ctx.service.embeddingLookupFactoryRef, storageForNamespace: (ns) => ctx.service.getWritableStorageForNamespace(ns ?? undefined, ctx.authenticatedPrincipal), localLlm: ctx.service.localLlmRef, fallbackLlm: ctx.service.fallbackLlmRef, namespace: optStr(input.namespace) }) }) });
|
|
232
|
-
defineOperation({ name: "graph_edge_decay_run", description: "Run edge decay.", schema: strictSchema({ dryRun: S.bool }), handler: async (input, ctx) => { const cfg = ctx.service.configRef; if (!cfg.graphEdgeDecayEnabled) return { result: { ranAt: new Date().toISOString(), disabled: true, reason: "graphEdgeDecayEnabled is false" } }; return { result: { results: await runGraphEdgeDecayMaintenanceAcrossNamespaces(ctx.service.memoryDir, { windowMs: cfg.graphEdgeDecayWindowMs, perWindow: cfg.graphEdgeDecayPerWindow, floor: cfg.graphEdgeDecayFloor, visibilityThreshold: cfg.graphEdgeDecayVisibilityThreshold, dryRun: input.dryRun === true, namespacesEnabled: cfg.namespacesEnabled === true, defaultNamespace: cfg.defaultNamespace }) } }; } });
|
|
254
|
+
defineOperation({ name: "graph_edge_decay_run", description: "Run edge decay.", fleetWide: true, schema: strictSchema({ dryRun: S.bool }), handler: async (input, ctx) => { const cfg = ctx.service.configRef; if (!cfg.graphEdgeDecayEnabled) return { result: { ranAt: new Date().toISOString(), disabled: true, reason: "graphEdgeDecayEnabled is false" } }; return { result: { results: await runGraphEdgeDecayMaintenanceAcrossNamespaces(ctx.service.memoryDir, { windowMs: cfg.graphEdgeDecayWindowMs, perWindow: cfg.graphEdgeDecayPerWindow, floor: cfg.graphEdgeDecayFloor, visibilityThreshold: cfg.graphEdgeDecayVisibilityThreshold, dryRun: input.dryRun === true, namespacesEnabled: cfg.namespacesEnabled === true, defaultNamespace: cfg.defaultNamespace }) } }; } });
|
|
233
255
|
|
|
234
256
|
// === SUMMARIZE/PROFILING/PEERS/CONSOLE/DREAMS ===
|
|
235
|
-
defineOperation({ name: "memory_summarize_hourly", description: "Hourly summarize.", schema: strictSchema({}), handler: async (_i, ctx) => ({ result: await ctx.service.memorySummarizeHourly() }) });
|
|
236
|
-
defineOperation({ name: "conversation_index_update", description: "Update conv index.", schema: strictSchema({ sessionKey: S.str, hours: S.num, embed: S.bool }), handler: async (input, ctx) => { if (input.sessionKey !== undefined && typeof input.sessionKey !== "string") throw new EngramAccessInputError("sessionKey must be a string when provided"); return { result: await ctx.service.conversationIndexUpdate({ sessionKey: optStr(input.sessionKey), hours: optNum(input.hours), embed: optBool(input.embed) }) }; } });
|
|
257
|
+
defineOperation({ name: "memory_summarize_hourly", description: "Hourly summarize.", fleetWide: true, schema: strictSchema({}), handler: async (_i, ctx) => ({ result: await ctx.service.memorySummarizeHourly() }) });
|
|
258
|
+
defineOperation({ name: "conversation_index_update", description: "Update conv index.", fleetWide: true, schema: strictSchema({ sessionKey: S.str, hours: S.num, embed: S.bool }), handler: async (input, ctx) => { if (input.sessionKey !== undefined && typeof input.sessionKey !== "string") throw new EngramAccessInputError("sessionKey must be a string when provided"); return { result: await ctx.service.conversationIndexUpdate({ sessionKey: optStr(input.sessionKey), hours: optNum(input.hours), embed: optBool(input.embed) }) }; } });
|
|
237
259
|
defineOperation({ name: "profiling_report", description: "Profiling report.", schema: strictSchema({ format: S.str, limit: S.num }), handler: async (input, ctx) => { if (input.format !== undefined && typeof input.format !== "string") throw new EngramAccessInputError("format must be a string when provided"); if (input.limit !== undefined && typeof input.limit !== "number") throw new EngramAccessInputError("limit must be a number when provided"); return { result: await ctx.service.profilingReport({ format: optStr(input.format), limit: optNum(input.limit) }) }; } });
|
|
238
|
-
defineOperation({ name: "live_connectors_run", description: "Run connectors.", schema: strictSchema({ force: S.bool }), handler: async (input, ctx) => ({ result: await ctx.service.liveConnectorsRun({ authenticatedPrincipal: ctx.authenticatedPrincipal, force: input.force === true }, ctx.authenticatedPrincipal) }) });
|
|
260
|
+
defineOperation({ name: "live_connectors_run", description: "Run connectors.", fleetWide: true, schema: strictSchema({ force: S.bool }), handler: async (input, ctx) => ({ result: await ctx.service.liveConnectorsRun({ authenticatedPrincipal: ctx.authenticatedPrincipal, force: input.force === true }, ctx.authenticatedPrincipal) }) });
|
|
239
261
|
defineOperation({ name: "peer_list", description: "List peers.", schema: strictSchema({}), handler: async (_i, ctx) => ({ result: await ctx.service.peerList() }) });
|
|
240
262
|
defineOperation({ name: "peer_get", description: "Get peer.", schema: strictSchema({ id: S.str }), handler: async (input, ctx) => { const id = defStr(input.id, ""); if (!id) throw new EngramAccessInputError("peer_get: id is required"); return { result: await ctx.service.peerGet(id) }; } });
|
|
241
263
|
defineOperation({ name: "peer_set", description: "Set peer.", schema: strictSchema({ id: S.str, kind: S.str, displayName: S.str, notes: S.str }), handler: async (input, ctx) => { const id = defStr(input.id, ""); if (!id) throw new EngramAccessInputError("peer_set: id is required"); if (input.kind !== undefined && typeof input.kind !== "string") throw new EngramAccessInputError("peer_set: kind must be a string when provided"); if (input.displayName !== undefined && typeof input.displayName !== "string") throw new EngramAccessInputError("peer_set: displayName must be a string when provided"); if (input.notes !== undefined && typeof input.notes !== "string") throw new EngramAccessInputError("peer_set: notes must be a string when provided"); return { result: await ctx.service.peerSet({ id, kind: optStr(input.kind), displayName: optStr(input.displayName), notes: optStr(input.notes) }) }; } });
|
|
@@ -287,3 +309,4 @@ defineOperation({ name: "offline_sync_snapshot_stream", description: "SSE stream
|
|
|
287
309
|
defineOperation({ name: "graph_events", description: "SSE graph events.", schema: strictSchema({}), handler: async (_i, _ctx) => ({ result: { stream: "sse" } }) });
|
|
288
310
|
defineOperation({ name: "chat_message", description: "Chat message.", schema: strictSchema({ message: S.str, chatSessionId: S.str }), handler: async (_i, _ctx) => ({ result: { ok: true } }) });
|
|
289
311
|
defineOperation({ name: "chat_events", description: "SSE chat events.", schema: strictSchema({}), handler: async (_i, _ctx) => ({ result: { stream: "sse" } }) });
|
|
312
|
+
defineOperation({ name: "adapters_status", description: "Adapter registry metadata (issue #1850 round 5). Marker op: the HTTP transport builds the response from its own adapterRegistry, but the op still must be registered so it appears in listRegisteredOperations and enforceTokenOp can gate it for scoped tokens.", schema: strictSchema({}), handler: async (_i, _ctx) => ({ result: { ok: true } }) });
|