chainlesschain 0.162.193 → 0.162.198
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -6
- package/completions/_cc +2 -2
- package/completions/cc.bash +2 -2
- package/completions/cc.fish +2 -2
- package/completions/cc.ps1 +2 -2
- package/package.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-DBLkaTje.js → AIOps-CSN-D2xb.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-BAy-Qebo.js → ActionButton-CBSMlGzv.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-Dfb1Mlau.js → Analytics-3yr3Nt2t.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-BbFkN8m0.js → AppLayout-1b-o3lMH.js} +4 -4
- package/src/assets/web-panel/assets/{Artifacts-kM4-cEEH.js → Artifacts-Dr8rJi17.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-BSQfYWf3.js → Audit-2V689HC2.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-CWDbI_fG.js → BackgroundAgents-DIxkNrD_.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BxLPbq_Q.js → Backup-Pg6BcwrE.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-DuIbdrp6.js → BaseInput-CLUpqyfH.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-NEmjGahU.js → Chat-qVS8rD4G.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-DfJEo-5_.js → ChatBubbleRenderer-ti49X12Q.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-CaoeG3Ns.js → Checkbox-Bs9AaEay.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BFf_g3xY.js → Codegen-Dvc1mq8q.js} +1 -1
- package/src/assets/web-panel/assets/{Col-CNOd8mdQ.js → Col-C4_biO7A.js} +1 -1
- package/src/assets/web-panel/assets/{Community-BhpDqz-i.js → Community-al25XQUV.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-CQ42T7Z6.js → Compact-D-ZDB8M1.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-DI5PcLMN.js → Compliance-6lIfDz1W.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-wYYZe0wR.js → Cowork-DdI48XMJ.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-Dlq03DD_.js → Cron-DF5HZd2g.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BzqS8PP3.js → Crosschain-DuxeSvt3.js} +1 -1
- package/src/assets/web-panel/assets/{DID-It55Yem7.js → DID-B9yHkUTd.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-9HkH6oxn.js → Dashboard-Z5EuI3IM.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-00e2YWRB.js → Dropdown-vuRfO3dY.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-By-ugRDL.js → EmailListRenderer-QFLCc1uL.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-C396yu5m.js → FamilyGuardDashboard-BZ7EXkFJ.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BME5sbZY.js → Federation-DycIEg2s.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-B4TEZCr-.js → FormItemContext-Ba0H_7yG.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-_9CX9ieY.js → GenericCardRenderer--JgSTK-C.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BrS6WVSr.js → Git-DEvTbldE.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-BMdCWnKF.js → Governance-BJIljy18.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-Bcp3vzcA.js → Inference-CVyW3G3q.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DlLuqGY5.js → KnowledgeGraph-v8-borge.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-D-W_6x09.js → Logs-BCdS7gGo.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-DElGPxCZ.js → MarkdownRenderer-CU-JB2Ns.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-Dzn2guvI.js → Marketplace-AN6tGA2B.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-uPict-KL.js → McpTools-DGViXASN.js} +6 -6
- package/src/assets/web-panel/assets/{Memory-BCw43kOb.js → Memory-Bpvmx9X4.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DmV8Wv7F.js → MobileBridge-CTP-DOTC.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-C-HaCmSM.js → MobileProjects-C8qfktxn.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-C6jxJ34Y.js → Mtc-ndYr0M1s.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-Za8ExwhQ.js → MtcAudit-Ci0-YK7W.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-KKDbuEgb.js → Multisig-BehSTFW7.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Dj97zbCk.js → NLProgramming-B91_YBLv.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-DBXvMraU.js → Notes-BQlJ0-gq.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-DOxITLYl.js → NotificationSettings-CDgYMjYK.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-7DVjZwMM.js → OrderTableRenderer-BJkSlKeH.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-D1i73mjb.js → Organization-B-b3cWCp.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-kW6Q3rvg.js → Overflow-CILUL4nL.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-C-v_8p2v.js → P2P-BTCFBkF0.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-tUbbY64W.js → PdhVaultBrowser-BAR6AUx5.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-DkHxEZ58.js → Permissions-RRf6HbWJ.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-DWuMPGrK.js → PersonalDataHub-BGTMiICa.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-30IYXWWm.js → Pipeline-945qY9YF.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DZNQ4RrH.js → Privacy-DPZwI6lJ.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-De2MCElf.js → ProjectInit-BPH2NRKc.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-5uHk9wsC.js → ProjectSettings-BZCRNCvb.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-XjDfrFLb.js → Projects-BTI__tBt.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-Bgwj6gcE.js → Providers-DDCf_nIw.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-gKql9umv.js → QrScannerModal-N6rbqt1r.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BWvmwkh7.js → QuickAsk-DrwjPS7M.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Uok4hZPd.js → Recommend-Cog9Wd99.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DLJzTk9a.js → RemoteSession-DC9pynjM.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-ZVwIPMSO.js → Reputation-D4th4gKS.js} +1 -1
- package/src/assets/web-panel/assets/{Row-CN04HxWR.js → Row-ogiWR6v9.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BdSrEG4g.js → RssFeed-uYlk-2Oj.js} +3 -3
- package/src/assets/web-panel/assets/{Search-5PwVd0IR.js → Search-DYzzwvtM.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DdBo4zjN.js → Security-Da7YOyX6.js} +4 -4
- package/src/assets/web-panel/assets/{Services-D3letU7M.js → Services-CLI1VM1X.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton--Jb83f1v.js → Skeleton-DK77dzDC.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-Bg-CulHX.js → Skills-C_z7Lmhl.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-7QOa7S-X.js → Sla-D6413Q8L.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-DQwppjRw.js → SpeechSettings-C07ydbj2.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-dNPQGL-s.js → SyncSettings-DGOm2W22.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-Ggs-Z48q.js → Tasks-Cr_PVyLM.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-78TYHgRO.js → Templates-BhL2mZ0t.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-xHwwv9vO.js → Tenant-CPk5oyUr.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-BJXSJfm4.js → Terminal-ClhqUsqV.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-fLbjRhJw.js → TimelineRenderer-BCC7MV5a.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-oMSBSBmB.js → Tokens-DD1Jt4oO.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-CfnY_wX_.js → Trigger-BCydFvN2.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-AdyTgYKO.js → Trust-DDHT1noa.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-C5K_81dS.js → UkeySign-CWPZC7oI.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-vcGVDqki.js → VideoEditing-9Ea0nJR0.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-hhOc3hlY.js → Wallet-BjxhLxTf.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-CVloC11s.js → WebAuthn-C6uCye67.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-CYeE32R5.js → WorkflowEditor-d2g4reYo.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CNROR5bN.js → chat-frTc6ScX.js} +1 -1
- package/src/assets/web-panel/assets/{colors-Cjx-cnwU.js → colors-B5K6lG3v.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DOIfelvD.js → compact-item-Cdn46r8D.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DfA7UZ8u.js → createContext-DU1jqVQi.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-CP-jEUyw.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BMSCzcfM.js → hasIn-DdNH-aW_.js} +1 -1
- package/src/assets/web-panel/assets/{index-CAnvhwg6.js → index-32ajXmTb.js} +1 -1
- package/src/assets/web-panel/assets/{index-BEMwBBHk.js → index-7ehytj1K.js} +1 -1
- package/src/assets/web-panel/assets/{index-CVL27kXC.js → index-BC4eGkar.js} +1 -1
- package/src/assets/web-panel/assets/{index-FBc_CJBd.js → index-BVLL-mq_.js} +1 -1
- package/src/assets/web-panel/assets/{index-dCd8cSUq.js → index-BXKhhx9V.js} +1 -1
- package/src/assets/web-panel/assets/{index-BemJ2u_E.js → index-BcGwGIaR.js} +1 -1
- package/src/assets/web-panel/assets/{index-CVm1_i3t.js → index-Be4OtL-N.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cs6l7uRu.js → index-BoFak7le.js} +1 -1
- package/src/assets/web-panel/assets/{index-DPAWBrMf.js → index-BwlIxAmX.js} +1 -1
- package/src/assets/web-panel/assets/{index-DLmn0BoK.js → index-CGiwfwB9.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7gf77CJ.js → index-CHmkkdfT.js} +1 -1
- package/src/assets/web-panel/assets/{index-m2vG9gG_.js → index-CQorP1Ng.js} +1 -1
- package/src/assets/web-panel/assets/{index-ClNMrqEY.js → index-CUoNAmE8.js} +1 -1
- package/src/assets/web-panel/assets/{index-DHtpHZAQ.js → index-Cj6P9Nst.js} +1 -1
- package/src/assets/web-panel/assets/{index-C2K9SNVX.js → index-CtRPi4YC.js} +1 -1
- package/src/assets/web-panel/assets/index-CzrCHrFy.js +1 -0
- package/src/assets/web-panel/assets/{index-BolaOQxx.js → index-D1qIC4GR.js} +1 -1
- package/src/assets/web-panel/assets/{index-BM1y_9hM.js → index-D23xGYjM.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cyweh0Hy.js → index-D4l82Me1.js} +1 -1
- package/src/assets/web-panel/assets/{index-By61ojUx.js → index-D4miNkWv.js} +1 -1
- package/src/assets/web-panel/assets/{index-BbQ2eQ8H.js → index-DIVyTmZ3.js} +1 -1
- package/src/assets/web-panel/assets/{index-Icdoqmzt.js → index-DM5FmPZU.js} +1 -1
- package/src/assets/web-panel/assets/{index-DjEsxO5h.js → index-DRzBBdQ0.js} +1 -1
- package/src/assets/web-panel/assets/{index-B4iYzpkL.js → index-Dca_i7H8.js} +1 -1
- package/src/assets/web-panel/assets/{index-C3L5gdiD.js → index-DftZuyA7.js} +1 -1
- package/src/assets/web-panel/assets/{index-CdYBye8B.js → index-DtBCCkC4.js} +1 -1
- package/src/assets/web-panel/assets/{index-AWg-0M1S.js → index-HjCvXHf5.js} +1 -1
- package/src/assets/web-panel/assets/{index-CEKMcOyU.js → index-LaivuXyF.js} +1 -1
- package/src/assets/web-panel/assets/{index-BxOk9vkG.js → index-MM4Zz2OE.js} +1 -1
- package/src/assets/web-panel/assets/{index-CNC5onm4.js → index-NmEXVjzt.js} +1 -1
- package/src/assets/web-panel/assets/index-OJsGskZw.js +1 -0
- package/src/assets/web-panel/assets/{index-BUonmKSE.js → index-PjAS0sIZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5Udeb_6.js → index-VDM2KKo9.js} +1 -1
- package/src/assets/web-panel/assets/{index-5-HXgOX5.js → index-cYaWV4Mq.js} +1 -1
- package/src/assets/web-panel/assets/{index-DBpWXFed.js → index-gg3QPC3i.js} +3 -3
- package/src/assets/web-panel/assets/{index-C7xn0Nub.js → index-kVO_MDm-.js} +1 -1
- package/src/assets/web-panel/assets/{index-ti_lnTWl.js → index-mgU3Q-lN.js} +1 -1
- package/src/assets/web-panel/assets/{index-CshQbilz.js → index-t_OBzIP4.js} +1 -1
- package/src/assets/web-panel/assets/{index-mTpHoEzr.js → index-yZRuZpwK.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-Bu8k7H1Y.js → initDefaultProps-DwLTRNdo.js} +1 -1
- package/src/assets/web-panel/assets/{motion-s3iVK41k.js → motion-BchZDXnh.js} +1 -1
- package/src/assets/web-panel/assets/{move-B6B-E5Jz.js → move-e8M-zZFl.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BiYgTidA.js → mtc-parser-Ci40fQb3.js} +1 -1
- package/src/assets/web-panel/assets/{omit-pU1RdUDA.js → omit-C7110_f2.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-Cdoq_SeM.js → pickAttrs-skteMgnM.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DIuvAn2K.js → placementArrow-MGZ-lh2B.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-8w16YR2D.js → responsiveObserve-N4Sd7uy-.js} +1 -1
- package/src/assets/web-panel/assets/{slide-VZ01cZe3.js → slide-C7HDGRaa.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-lh8YMN8Z.js → statusUtils-BhRexlgy.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-CmDyreec.js → styleChecker-ChEoQkN2.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-hiJWMU5y.js → useFlexGapSupport-CDbG1s2Y.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-Thnu-Iaj.js → useFs-CUIx0tcJ.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-LBdOxjwY.js → usePersonalDataHub-bkO7L7ec.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-Cg6lFY_X.js → vnode-B_ZvABIG.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DVfsR1YO.js → zoom-D5shjpS8.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +4 -4
- package/src/command-manifest.json +214 -50
- package/src/command-surface-policy.js +115 -0
- package/src/commands/agent.js +3 -3
- package/src/commands/background-session.js +145 -0
- package/src/commands/mcp.js +125 -7
- package/src/commands/serve.js +1 -1
- package/src/commands/session-show.js +131 -0
- package/src/commands/session.js +50 -106
- package/src/commands/skill.js +87 -50
- package/src/data/changelog.json +18 -5
- package/src/gateways/ws/ws-agent-handler.js +8 -1
- package/src/harness/jsonl-session-store.js +428 -25
- package/src/harness/mcp-client.js +2652 -404
- package/src/harness/session-list-index.js +65 -7
- package/src/lazy-dispatch.js +76 -8
- package/src/lib/abort-utils.js +68 -0
- package/src/lib/agent-core.js +1 -59
- package/src/lib/chat-core.js +24 -6
- package/src/lib/cowork-mcp-tools.js +47 -2
- package/src/lib/cowork-task-runner.js +11 -3
- package/src/lib/doctor-checkup.js +9 -7
- package/src/lib/learning/skill-improver.js +21 -2
- package/src/lib/mcp-call-ledger-store.js +116 -3
- package/src/lib/mcp-call-ledger.js +59 -14
- package/src/lib/mcp-client.js +1 -0
- package/src/lib/mcp-stdio-executable-identity.js +598 -0
- package/src/lib/mcp-stdio-execution-authority.js +363 -0
- package/src/lib/mcp-tool-metadata.js +436 -0
- package/src/lib/mcp-tool-result.js +367 -0
- package/src/lib/observability/index.js +71 -0
- package/src/lib/pr-link-ledger.js +8 -27
- package/src/lib/pr-link-store.js +26 -0
- package/src/lib/process-execution-broker/index.js +14 -0
- package/src/lib/process-tree-termination.js +253 -0
- package/src/lib/public-ide-capability-manifest.js +6 -0
- package/src/lib/session-host-snapshot.js +9 -5
- package/src/lib/session-projection.js +5 -1
- package/src/lib/session-tail.js +31 -1
- package/src/lib/skill-budget.js +222 -0
- package/src/lib/skill-execution-authority.js +381 -0
- package/src/lib/skill-execution-identity.js +39 -2
- package/src/lib/skill-loader.js +322 -86
- package/src/lib/skill-mcp.js +43 -1
- package/src/repl/agent-repl.js +349 -46
- package/src/repl/bg-dashboard.js +81 -28
- package/src/repl/chat-repl.js +77 -12
- package/src/repl/prompt-interactions.js +67 -7
- package/src/repl/slash-command-registry.js +3 -4
- package/src/runtime/agent-core.js +340 -108
- package/src/runtime/agent-runtime.js +26 -3
- package/src/runtime/headless-runner.js +150 -23
- package/src/runtime/headless-stream.js +309 -59
- package/src/runtime/mcp-config.js +157 -10
- package/src/runtime/mcp-tool-search.js +0 -0
- package/src/runtime/output-backpressure.js +366 -0
- package/src/runtime/pipe-safety.js +56 -21
- package/src/assets/web-panel/assets/devWarning-ChcCBGs7.js +0 -1
- package/src/assets/web-panel/assets/index-Q2IajL54.js +0 -1
- package/src/assets/web-panel/assets/index-bRkHgOMc.js +0 -1
- package/src/lib/skill-process-broker.js +0 -85
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
import { isProxy } from "node:util/types";
|
|
2
|
+
|
|
3
|
+
// Final tools/call results cross several amplification boundaries after the
|
|
4
|
+
// transport frame is parsed: ledger hashing, stream projection, session/model
|
|
5
|
+
// serialization, and direct IDE/host consumers. Admit one strict JSON snapshot
|
|
6
|
+
// under a smaller result-specific budget before any of those consumers run.
|
|
7
|
+
|
|
8
|
+
export const MCP_TOOL_RESULT_LIMITS = Object.freeze({
|
|
9
|
+
maxBytes: 1024 * 1024,
|
|
10
|
+
maxDepth: 64,
|
|
11
|
+
maxNodes: 50_000,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const MCP_TOOL_RESULT_ERROR_CODES = new Set([
|
|
15
|
+
"CC_MCP_TOOL_RESULT_INVALID",
|
|
16
|
+
"CC_MCP_TOOL_RESULT_TOO_LARGE",
|
|
17
|
+
"CC_MCP_TOOL_RESULT_DEPTH_EXCEEDED",
|
|
18
|
+
"CC_MCP_TOOL_RESULT_NODES_EXCEEDED",
|
|
19
|
+
]);
|
|
20
|
+
|
|
21
|
+
const admittedToolResults = new WeakMap();
|
|
22
|
+
|
|
23
|
+
function tightenedLimit(configured, ceiling) {
|
|
24
|
+
if (Number.isFinite(configured) && configured > 0) {
|
|
25
|
+
return Math.min(ceiling, Math.max(1, Math.floor(configured)));
|
|
26
|
+
}
|
|
27
|
+
return ceiling;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function resolveMcpToolResultLimits(config = {}) {
|
|
31
|
+
return Object.freeze({
|
|
32
|
+
maxBytes: tightenedLimit(
|
|
33
|
+
config?.maxToolResultBytes,
|
|
34
|
+
MCP_TOOL_RESULT_LIMITS.maxBytes,
|
|
35
|
+
),
|
|
36
|
+
maxDepth: tightenedLimit(
|
|
37
|
+
config?.maxToolResultDepth,
|
|
38
|
+
MCP_TOOL_RESULT_LIMITS.maxDepth,
|
|
39
|
+
),
|
|
40
|
+
maxNodes: tightenedLimit(
|
|
41
|
+
config?.maxToolResultNodes,
|
|
42
|
+
MCP_TOOL_RESULT_LIMITS.maxNodes,
|
|
43
|
+
),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function resultError(code, message, details = {}) {
|
|
48
|
+
const error = new Error(message);
|
|
49
|
+
error.name = "McpToolResultAdmissionError";
|
|
50
|
+
error.code = code;
|
|
51
|
+
error.dispatched = true;
|
|
52
|
+
error.outcomeUnknown = true;
|
|
53
|
+
error.retryable = false;
|
|
54
|
+
if (details.limitBytes != null) error.limitBytes = details.limitBytes;
|
|
55
|
+
if (details.limitDepth != null) error.limitDepth = details.limitDepth;
|
|
56
|
+
if (details.limitNodes != null) error.limitNodes = details.limitNodes;
|
|
57
|
+
return error;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function isMcpToolResultAdmissionError(error) {
|
|
61
|
+
if (!error || typeof error !== "object") return false;
|
|
62
|
+
try {
|
|
63
|
+
if (isProxy(error)) return false;
|
|
64
|
+
const descriptor = Object.getOwnPropertyDescriptor(error, "code");
|
|
65
|
+
return Boolean(
|
|
66
|
+
descriptor &&
|
|
67
|
+
Object.hasOwn(descriptor, "value") &&
|
|
68
|
+
MCP_TOOL_RESULT_ERROR_CODES.has(descriptor.value),
|
|
69
|
+
);
|
|
70
|
+
} catch {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function denseArraySnapshot(value) {
|
|
76
|
+
if (!value || typeof value !== "object") return null;
|
|
77
|
+
try {
|
|
78
|
+
if (isProxy(value) || !Array.isArray(value)) return null;
|
|
79
|
+
const length = Object.getOwnPropertyDescriptor(value, "length")?.value;
|
|
80
|
+
if (!Number.isSafeInteger(length) || length < 0) return null;
|
|
81
|
+
const keys = Reflect.ownKeys(value);
|
|
82
|
+
if (
|
|
83
|
+
keys.length !== length + 1 ||
|
|
84
|
+
keys.some((key) => typeof key === "symbol")
|
|
85
|
+
) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
const descriptors = [];
|
|
89
|
+
for (let index = 0; index < length; index += 1) {
|
|
90
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
91
|
+
if (
|
|
92
|
+
!descriptor ||
|
|
93
|
+
!Object.hasOwn(descriptor, "value") ||
|
|
94
|
+
descriptor.enumerable !== true
|
|
95
|
+
) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
descriptors.push(descriptor);
|
|
99
|
+
}
|
|
100
|
+
return descriptors;
|
|
101
|
+
} catch {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function plainObjectSnapshot(value) {
|
|
107
|
+
if (!value || typeof value !== "object") return null;
|
|
108
|
+
try {
|
|
109
|
+
if (isProxy(value) || Array.isArray(value)) return null;
|
|
110
|
+
const prototype = Object.getPrototypeOf(value);
|
|
111
|
+
if (prototype !== Object.prototype && prototype !== null) return null;
|
|
112
|
+
const keys = Reflect.ownKeys(value);
|
|
113
|
+
if (keys.some((key) => typeof key === "symbol")) return null;
|
|
114
|
+
const descriptors = Object.create(null);
|
|
115
|
+
for (const key of keys) {
|
|
116
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
117
|
+
if (
|
|
118
|
+
!descriptor ||
|
|
119
|
+
!Object.hasOwn(descriptor, "value") ||
|
|
120
|
+
descriptor.enumerable !== true
|
|
121
|
+
) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
descriptors[key] = descriptor;
|
|
125
|
+
}
|
|
126
|
+
return { keys, descriptors };
|
|
127
|
+
} catch {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function boundedJsonStringBytes(value, available) {
|
|
133
|
+
let bytes = 2;
|
|
134
|
+
if (bytes > available) return available + 1;
|
|
135
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
136
|
+
const code = value.charCodeAt(index);
|
|
137
|
+
if (code === 0x22 || code === 0x5c) {
|
|
138
|
+
bytes += 2;
|
|
139
|
+
} else if (
|
|
140
|
+
code === 0x08 ||
|
|
141
|
+
code === 0x09 ||
|
|
142
|
+
code === 0x0a ||
|
|
143
|
+
code === 0x0c ||
|
|
144
|
+
code === 0x0d
|
|
145
|
+
) {
|
|
146
|
+
bytes += 2;
|
|
147
|
+
} else if (code <= 0x1f) {
|
|
148
|
+
bytes += 6;
|
|
149
|
+
} else if (code <= 0x7f) {
|
|
150
|
+
bytes += 1;
|
|
151
|
+
} else if (code <= 0x7ff) {
|
|
152
|
+
bytes += 2;
|
|
153
|
+
} else if (code >= 0xd800 && code <= 0xdbff) {
|
|
154
|
+
const trailing = value.charCodeAt(index + 1);
|
|
155
|
+
if (trailing >= 0xdc00 && trailing <= 0xdfff) {
|
|
156
|
+
bytes += 4;
|
|
157
|
+
index += 1;
|
|
158
|
+
} else {
|
|
159
|
+
bytes += 6;
|
|
160
|
+
}
|
|
161
|
+
} else if (code >= 0xdc00 && code <= 0xdfff) {
|
|
162
|
+
bytes += 6;
|
|
163
|
+
} else {
|
|
164
|
+
bytes += 3;
|
|
165
|
+
}
|
|
166
|
+
if (bytes > available) return available + 1;
|
|
167
|
+
}
|
|
168
|
+
return bytes;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function consumeBytes(state, bytes) {
|
|
172
|
+
if (!Number.isSafeInteger(bytes) || bytes < 0 || bytes > state.bytesLeft) {
|
|
173
|
+
state.issue = "bytes";
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
state.bytesLeft -= bytes;
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function consumeNodes(state, count = 1) {
|
|
181
|
+
if (!Number.isSafeInteger(count) || count < 0 || count > state.nodesLeft) {
|
|
182
|
+
state.issue = "nodes";
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
state.nodesLeft -= count;
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function cloneJsonValue(value, state, depth) {
|
|
190
|
+
if (!consumeNodes(state)) return undefined;
|
|
191
|
+
|
|
192
|
+
if (value === null) {
|
|
193
|
+
consumeBytes(state, 4);
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
if (typeof value === "string") {
|
|
197
|
+
consumeBytes(state, boundedJsonStringBytes(value, state.bytesLeft));
|
|
198
|
+
return value;
|
|
199
|
+
}
|
|
200
|
+
if (typeof value === "boolean") {
|
|
201
|
+
consumeBytes(state, value ? 4 : 5);
|
|
202
|
+
return value;
|
|
203
|
+
}
|
|
204
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
205
|
+
consumeBytes(state, Buffer.byteLength(JSON.stringify(value), "utf8"));
|
|
206
|
+
return value;
|
|
207
|
+
}
|
|
208
|
+
if (!value || typeof value !== "object") {
|
|
209
|
+
state.issue = "invalid";
|
|
210
|
+
return undefined;
|
|
211
|
+
}
|
|
212
|
+
if (depth > state.maxDepth) {
|
|
213
|
+
state.issue = "depth";
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
216
|
+
state.maxDepthSeen = Math.max(state.maxDepthSeen, depth);
|
|
217
|
+
try {
|
|
218
|
+
if (isProxy(value) || state.seen.has(value)) {
|
|
219
|
+
state.issue = "invalid";
|
|
220
|
+
return undefined;
|
|
221
|
+
}
|
|
222
|
+
state.seen.add(value);
|
|
223
|
+
} catch {
|
|
224
|
+
state.issue = "invalid";
|
|
225
|
+
return undefined;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (Array.isArray(value)) {
|
|
229
|
+
const descriptors = denseArraySnapshot(value);
|
|
230
|
+
if (!descriptors || !consumeBytes(state, 2)) {
|
|
231
|
+
if (!state.issue) state.issue = "invalid";
|
|
232
|
+
return undefined;
|
|
233
|
+
}
|
|
234
|
+
const clean = [];
|
|
235
|
+
for (let index = 0; index < descriptors.length; index += 1) {
|
|
236
|
+
if (index > 0 && !consumeBytes(state, 1)) return undefined;
|
|
237
|
+
const cloned = cloneJsonValue(descriptors[index].value, state, depth + 1);
|
|
238
|
+
if (state.issue) return undefined;
|
|
239
|
+
clean.push(cloned);
|
|
240
|
+
}
|
|
241
|
+
return clean;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const snapshot = plainObjectSnapshot(value);
|
|
245
|
+
if (!snapshot || !consumeBytes(state, 2)) {
|
|
246
|
+
if (!state.issue) state.issue = "invalid";
|
|
247
|
+
return undefined;
|
|
248
|
+
}
|
|
249
|
+
if (!consumeNodes(state, snapshot.keys.length)) return undefined;
|
|
250
|
+
const clean = {};
|
|
251
|
+
for (let index = 0; index < snapshot.keys.length; index += 1) {
|
|
252
|
+
const key = snapshot.keys[index];
|
|
253
|
+
if (index > 0 && !consumeBytes(state, 1)) return undefined;
|
|
254
|
+
if (
|
|
255
|
+
!consumeBytes(state, boundedJsonStringBytes(key, state.bytesLeft)) ||
|
|
256
|
+
!consumeBytes(state, 1)
|
|
257
|
+
) {
|
|
258
|
+
return undefined;
|
|
259
|
+
}
|
|
260
|
+
const cloned = cloneJsonValue(
|
|
261
|
+
snapshot.descriptors[key].value,
|
|
262
|
+
state,
|
|
263
|
+
depth + 1,
|
|
264
|
+
);
|
|
265
|
+
if (state.issue) return undefined;
|
|
266
|
+
Object.defineProperty(clean, key, {
|
|
267
|
+
value: cloned,
|
|
268
|
+
enumerable: true,
|
|
269
|
+
configurable: true,
|
|
270
|
+
writable: true,
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
return clean;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function freezeJsonSnapshot(value) {
|
|
277
|
+
const stack = [value];
|
|
278
|
+
while (stack.length > 0) {
|
|
279
|
+
const current = stack.pop();
|
|
280
|
+
if (!current || typeof current !== "object" || Object.isFrozen(current)) {
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
for (const key of Object.keys(current)) {
|
|
284
|
+
const child = current[key];
|
|
285
|
+
if (child && typeof child === "object") stack.push(child);
|
|
286
|
+
}
|
|
287
|
+
Object.freeze(current);
|
|
288
|
+
}
|
|
289
|
+
return value;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function admissionError(issue, limits) {
|
|
293
|
+
if (issue === "bytes") {
|
|
294
|
+
return resultError(
|
|
295
|
+
"CC_MCP_TOOL_RESULT_TOO_LARGE",
|
|
296
|
+
`MCP tool result exceeded the ${limits.maxBytes}-byte host budget`,
|
|
297
|
+
{ limitBytes: limits.maxBytes },
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
if (issue === "depth") {
|
|
301
|
+
return resultError(
|
|
302
|
+
"CC_MCP_TOOL_RESULT_DEPTH_EXCEEDED",
|
|
303
|
+
`MCP tool result exceeded the ${limits.maxDepth}-level host depth budget`,
|
|
304
|
+
{ limitDepth: limits.maxDepth },
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
if (issue === "nodes") {
|
|
308
|
+
return resultError(
|
|
309
|
+
"CC_MCP_TOOL_RESULT_NODES_EXCEEDED",
|
|
310
|
+
`MCP tool result exceeded the ${limits.maxNodes}-node host budget`,
|
|
311
|
+
{ limitNodes: limits.maxNodes },
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
return resultError(
|
|
315
|
+
"CC_MCP_TOOL_RESULT_INVALID",
|
|
316
|
+
"MCP server returned an invalid tool result",
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export function admitMcpToolResult(_serverName, value, config = {}) {
|
|
321
|
+
const limits = resolveMcpToolResultLimits(config);
|
|
322
|
+
if (value && typeof value === "object") {
|
|
323
|
+
const prior = admittedToolResults.get(value);
|
|
324
|
+
if (
|
|
325
|
+
prior &&
|
|
326
|
+
prior.bytes <= limits.maxBytes &&
|
|
327
|
+
prior.depth <= limits.maxDepth &&
|
|
328
|
+
prior.nodes <= limits.maxNodes
|
|
329
|
+
) {
|
|
330
|
+
return Object.freeze({
|
|
331
|
+
result: value,
|
|
332
|
+
bytes: prior.bytes,
|
|
333
|
+
depth: prior.depth,
|
|
334
|
+
nodes: prior.nodes,
|
|
335
|
+
limits,
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const state = {
|
|
341
|
+
issue: null,
|
|
342
|
+
bytesLeft: limits.maxBytes,
|
|
343
|
+
nodesLeft: limits.maxNodes,
|
|
344
|
+
maxDepth: limits.maxDepth,
|
|
345
|
+
maxDepthSeen: 0,
|
|
346
|
+
seen: new WeakSet(),
|
|
347
|
+
};
|
|
348
|
+
const result = cloneJsonValue(value, state, 1);
|
|
349
|
+
if (
|
|
350
|
+
!state.issue &&
|
|
351
|
+
(!result || typeof result !== "object" || Array.isArray(result))
|
|
352
|
+
) {
|
|
353
|
+
state.issue = "invalid";
|
|
354
|
+
}
|
|
355
|
+
if (state.issue) throw admissionError(state.issue, limits);
|
|
356
|
+
|
|
357
|
+
const bytes = limits.maxBytes - state.bytesLeft;
|
|
358
|
+
const nodes = limits.maxNodes - state.nodesLeft;
|
|
359
|
+
freezeJsonSnapshot(result);
|
|
360
|
+
const metrics = Object.freeze({
|
|
361
|
+
bytes,
|
|
362
|
+
depth: state.maxDepthSeen,
|
|
363
|
+
nodes,
|
|
364
|
+
});
|
|
365
|
+
admittedToolResults.set(result, metrics);
|
|
366
|
+
return Object.freeze({ result, ...metrics, limits });
|
|
367
|
+
}
|
|
@@ -136,6 +136,73 @@ export class ObservabilityRuntime {
|
|
|
136
136
|
]);
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
/**
|
|
140
|
+
* Export one migrated-command invocation without command arguments or any
|
|
141
|
+
* session/workspace identity. Collection remains opt-in because a disabled
|
|
142
|
+
* OTLP runtime returns before constructing or queueing the metric payload.
|
|
143
|
+
*/
|
|
144
|
+
exportCommandLifecycleInvocation(value = {}) {
|
|
145
|
+
if (!this.enabled) return false;
|
|
146
|
+
const command = normalizeLifecycleDimension(
|
|
147
|
+
value.command,
|
|
148
|
+
/^[a-z0-9][a-z0-9-]{0,63}$/,
|
|
149
|
+
"unknown",
|
|
150
|
+
);
|
|
151
|
+
const route = ["legacy", "replacement"].includes(value.route)
|
|
152
|
+
? value.route
|
|
153
|
+
: "unknown";
|
|
154
|
+
const outcome = ["completed", "error"].includes(value.outcome)
|
|
155
|
+
? value.outcome
|
|
156
|
+
: "unknown";
|
|
157
|
+
const version = normalizeLifecycleDimension(
|
|
158
|
+
value.version,
|
|
159
|
+
/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/,
|
|
160
|
+
"unknown",
|
|
161
|
+
);
|
|
162
|
+
const deprecatedSince = normalizeLifecycleDimension(
|
|
163
|
+
value.deprecatedSince,
|
|
164
|
+
/^\d+\.\d+\.\d+$/,
|
|
165
|
+
"unknown",
|
|
166
|
+
);
|
|
167
|
+
const removalNotBefore = normalizeLifecycleDimension(
|
|
168
|
+
value.removalNotBefore,
|
|
169
|
+
/^\d+\.\d+\.\d+$/,
|
|
170
|
+
"unknown",
|
|
171
|
+
);
|
|
172
|
+
const durationMs = Math.max(0, Number(value.durationMs) || 0);
|
|
173
|
+
const attributes = {
|
|
174
|
+
"command.name": command,
|
|
175
|
+
"command.route": route,
|
|
176
|
+
"command.outcome": outcome,
|
|
177
|
+
"cli.version": version,
|
|
178
|
+
"command.deprecated_since": deprecatedSince,
|
|
179
|
+
"command.removal_not_before": removalNotBefore,
|
|
180
|
+
};
|
|
181
|
+
try {
|
|
182
|
+
return this.exporter.exportMetrics([
|
|
183
|
+
{
|
|
184
|
+
name: "chainlesschain.cli.command.lifecycle.invocations",
|
|
185
|
+
type: "sum",
|
|
186
|
+
unit: "{invocation}",
|
|
187
|
+
value: 1,
|
|
188
|
+
monotonic: true,
|
|
189
|
+
attributes,
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
name: "chainlesschain.cli.command.lifecycle.duration",
|
|
193
|
+
type: "histogram",
|
|
194
|
+
unit: "ms",
|
|
195
|
+
count: 1,
|
|
196
|
+
sum: durationMs,
|
|
197
|
+
attributes,
|
|
198
|
+
},
|
|
199
|
+
]);
|
|
200
|
+
} catch {
|
|
201
|
+
// Observability is advisory and must never change the command result.
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
139
206
|
captureMetrics() {
|
|
140
207
|
if (!this.enabled) return false;
|
|
141
208
|
const metrics = collectedMetrics(this.metricsCollector);
|
|
@@ -156,6 +223,10 @@ export class ObservabilityRuntime {
|
|
|
156
223
|
}
|
|
157
224
|
}
|
|
158
225
|
|
|
226
|
+
function normalizeLifecycleDimension(value, pattern, fallback) {
|
|
227
|
+
return typeof value === "string" && pattern.test(value) ? value : fallback;
|
|
228
|
+
}
|
|
229
|
+
|
|
159
230
|
let defaultRuntime = null;
|
|
160
231
|
|
|
161
232
|
export function resolveOtlpEndpointFromArgv(argv = process.argv) {
|
|
@@ -16,10 +16,15 @@
|
|
|
16
16
|
* result or a session listing.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import {
|
|
20
|
-
import { join } from "node:path";
|
|
21
|
-
import { getHomeDir } from "./paths.js";
|
|
19
|
+
import { writeFileSync } from "node:fs";
|
|
22
20
|
import { executionBroker } from "./process-execution-broker/index.js";
|
|
21
|
+
import {
|
|
22
|
+
getPrLinks,
|
|
23
|
+
prLinkLedgerPath,
|
|
24
|
+
readPrLinkLedger,
|
|
25
|
+
} from "./pr-link-store.js";
|
|
26
|
+
|
|
27
|
+
export { getPrLinks, prLinkLedgerPath, readPrLinkLedger };
|
|
23
28
|
|
|
24
29
|
export const _deps = {
|
|
25
30
|
execFile: (...args) => executionBroker.execFile(...args),
|
|
@@ -29,21 +34,6 @@ export const _deps = {
|
|
|
29
34
|
const MAX_LINKS_PER_SESSION = 20;
|
|
30
35
|
const MAX_SESSIONS = 500;
|
|
31
36
|
|
|
32
|
-
export function prLinkLedgerPath() {
|
|
33
|
-
return join(getHomeDir(), "pr-links.json");
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function readPrLinkLedger() {
|
|
37
|
-
try {
|
|
38
|
-
const p = prLinkLedgerPath();
|
|
39
|
-
if (!existsSync(p)) return {};
|
|
40
|
-
const parsed = JSON.parse(readFileSync(p, "utf-8"));
|
|
41
|
-
return parsed && typeof parsed === "object" ? parsed : {};
|
|
42
|
-
} catch {
|
|
43
|
-
return {}; // corrupt ledger degrades to empty, never throws
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
37
|
function writeLedger(ledger) {
|
|
48
38
|
const ids = Object.keys(ledger);
|
|
49
39
|
if (ids.length > MAX_SESSIONS) {
|
|
@@ -138,15 +128,6 @@ export function recordPrLink(sessionId, ref, options = {}) {
|
|
|
138
128
|
return incoming;
|
|
139
129
|
}
|
|
140
130
|
|
|
141
|
-
/** Links for a session, newest first. */
|
|
142
|
-
export function getPrLinks(sessionId) {
|
|
143
|
-
if (!sessionId) return [];
|
|
144
|
-
const links = readPrLinkLedger()[sessionId];
|
|
145
|
-
return Array.isArray(links)
|
|
146
|
-
? [...links].sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0))
|
|
147
|
-
: [];
|
|
148
|
-
}
|
|
149
|
-
|
|
150
131
|
function ghPrForBranch(cwd, timeoutMs = 3000) {
|
|
151
132
|
const run = (file, fileArgs) =>
|
|
152
133
|
new Promise((resolve) => {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { getHomeDir } from "./paths.js";
|
|
4
|
+
|
|
5
|
+
export function prLinkLedgerPath() {
|
|
6
|
+
return join(getHomeDir(), "pr-links.json");
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function readPrLinkLedger() {
|
|
10
|
+
try {
|
|
11
|
+
const ledgerPath = prLinkLedgerPath();
|
|
12
|
+
if (!existsSync(ledgerPath)) return {};
|
|
13
|
+
const parsed = JSON.parse(readFileSync(ledgerPath, "utf-8"));
|
|
14
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
15
|
+
} catch {
|
|
16
|
+
return {};
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function getPrLinks(sessionId) {
|
|
21
|
+
if (!sessionId) return [];
|
|
22
|
+
const links = readPrLinkLedger()[sessionId];
|
|
23
|
+
return Array.isArray(links)
|
|
24
|
+
? [...links].sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0))
|
|
25
|
+
: [];
|
|
26
|
+
}
|
|
@@ -48,6 +48,7 @@ import { consumeIssuedPluginSandboxExecutionContract } from "../plugin-runtime/b
|
|
|
48
48
|
import runtimeProvenanceLedger from "../runtime-provenance-ledger.js";
|
|
49
49
|
import { credentialAgent } from "./credential-agent.js";
|
|
50
50
|
import { WorkspaceTransactionManager } from "./workspace-transaction.js";
|
|
51
|
+
import { consumeMcpStdioExecutableIdentityAuthority } from "../mcp-stdio-executable-identity.js";
|
|
51
52
|
|
|
52
53
|
const SUPPORTED_SANDBOX_BOUNDARIES = new Set(Object.values(SANDBOX_BOUNDARIES));
|
|
53
54
|
const SUPPORTED_SANDBOX_PROFILES = new Set([
|
|
@@ -2717,6 +2718,10 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
2717
2718
|
const startTime = Date.now();
|
|
2718
2719
|
const origin = options.origin || "unknown";
|
|
2719
2720
|
const requestedCwd = options.cwd || process.cwd();
|
|
2721
|
+
const mcpStdioExecutableIdentityAuthority =
|
|
2722
|
+
options.mcpStdioExecutableIdentityAuthority;
|
|
2723
|
+
const identityCommand = command;
|
|
2724
|
+
const identityArgs = [...(args || [])];
|
|
2720
2725
|
options = this._withWorkspaceTransactionBoundaries(options, requestedCwd, {
|
|
2721
2726
|
command,
|
|
2722
2727
|
args,
|
|
@@ -2764,6 +2769,7 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
2764
2769
|
sandboxRequired: [],
|
|
2765
2770
|
sandboxGuarantees: [],
|
|
2766
2771
|
sandboxBackend: null,
|
|
2772
|
+
mcpStdioExecutableIdentityDigest: null,
|
|
2767
2773
|
};
|
|
2768
2774
|
|
|
2769
2775
|
let sandboxPolicy;
|
|
@@ -2813,6 +2819,7 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
2813
2819
|
this._stripPluginControlOptions(spawnOpts);
|
|
2814
2820
|
this._stripWorkspaceTransactionOptions(spawnOpts);
|
|
2815
2821
|
this._stripAuditControlOptions(spawnOpts);
|
|
2822
|
+
delete spawnOpts.mcpStdioExecutableIdentityAuthority;
|
|
2816
2823
|
if (traceCtx) {
|
|
2817
2824
|
spawnOpts.env = { ...(spawnOpts.env || process.env) };
|
|
2818
2825
|
spawnOpts.env.TRACEPARENT = traceCtx.traceparent;
|
|
@@ -2886,6 +2893,13 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
2886
2893
|
const nativeSpawnFn = this._native?.spawn || nativeSpawn;
|
|
2887
2894
|
let proc;
|
|
2888
2895
|
try {
|
|
2896
|
+
if (mcpStdioExecutableIdentityAuthority !== undefined) {
|
|
2897
|
+
const admitted = consumeMcpStdioExecutableIdentityAuthority(
|
|
2898
|
+
mcpStdioExecutableIdentityAuthority,
|
|
2899
|
+
{ command: identityCommand, args: identityArgs },
|
|
2900
|
+
);
|
|
2901
|
+
auditEntry.mcpStdioExecutableIdentityDigest = admitted.identityDigest;
|
|
2902
|
+
}
|
|
2889
2903
|
proc = nativeSpawnFn(command, args, optsForSpawn);
|
|
2890
2904
|
this._bindWorkspaceTransactionProcess(auditEntry, proc);
|
|
2891
2905
|
} catch (spawnError) {
|