chainlesschain 0.163.2 → 0.163.4
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/package.json +3 -2
- package/scripts/command-lifecycle-report.mjs +330 -38
- package/src/assets/web-panel/assets/{AIOps-DnGsmsqJ.js → AIOps-DB5X7qqV.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CrO6fcQ7.js → ActionButton-DxHRtKLk.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DsBdOaP2.js → Analytics-DIH5QrxT.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DmQslKUB.js → AppLayout-uu0oxVz7.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-BvyrT_QQ.js → Artifacts-BNSMiW9Y.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-prndoLiC.js → Audit-DcAzB4_x.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-DOTFyA55.js → BackgroundAgents-ClSsvjIc.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-9zOnPp_8.js → Backup-BMciY0js.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-C4PC6sAG.js → BaseInput-Hn3b57Sh.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-BBAF-W9v.js → Chat-CoSlC53V.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CWhvvloO.js → ChatBubbleRenderer-CFevJ3So.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-BI9iculd.js → Checkbox-B4L4Eu4w.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-3DP9BCKb.js → Codegen-C77FgRxF.js} +1 -1
- package/src/assets/web-panel/assets/{Col-df-2TnJX.js → Col-BrLtJLH3.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CHs8gG_A.js → Community-Be7pXXhA.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-CDfF6q7V.js → Compact-DuGPecjo.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CthrDnO7.js → Compliance-CzS66mjP.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-HjIqsWJw.js → Cowork-CEhjCoyK.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-BKc196fb.js → Cron-D7ir8Vja.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CJnjdc8W.js → Crosschain-BcXmuLxf.js} +1 -1
- package/src/assets/web-panel/assets/{DID-BHUy-8Q2.js → DID-Cto1dtBy.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-QDB7sKeY.js → Dashboard-B7KjgwOX.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DStcVK11.js → Dropdown-COMqxijg.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BwSUskMJ.js → EmailListRenderer-BZrya-nf.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DgF_kurT.js → FamilyGuardDashboard-AmVeMq0J.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-k8wvv-wN.js → Federation-kZU8c-27.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-C11qoq2r.js → FormItemContext-sOV22v2-.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BIIpr9kg.js → GenericCardRenderer-BUuLtGCz.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BlA1exTe.js → Git-K-ZxsLsH.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CYa1ZYM4.js → Governance-D3OEnawI.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-6_kKVIt6.js → Inference-Bll0gRmP.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-CB4AwxYy.js → KnowledgeGraph-DBXwjr53.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-xf7nHFAe.js → Logs-CEzPwEfP.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-Bf3DEqP6.js → MarkdownRenderer-CLmCbHx6.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-aPg8e4Jt.js → Marketplace-BYyRyOPz.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-C-TNlVUf.js → McpTools-DVu8w_rM.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-DMTPIpGa.js → Memory-tenuZ_hO.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BxyvveRq.js → MobileBridge-Bxgy4ozS.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DyPCrAyQ.js → MobileProjects-Dgx1D6sc.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BdhqNXp6.js → Mtc-CRfJ8r8j.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-Cz-HFxzW.js → MtcAudit-BBJq4Aiz.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-CIUaFNsx.js → Multisig-B3ii9lai.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CWe6-J17.js → NLProgramming-FIi-Cubv.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-vYAKeviU.js → Notes-DIq8MPf1.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-DQL9-2d7.js → NotificationSettings-BFOD9eGd.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DnXj1jBn.js → OrderTableRenderer--41u7vre.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-B3spU8AN.js → Organization-B_0AWztW.js} +2 -2
- package/src/assets/web-panel/assets/{Overflow-DgEwo7vm.js → Overflow-B6I7TuXv.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-hujMRH8X.js → P2P-Cdf6qens.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-C_qhdg9h.js → PdhVaultBrowser-B_0FcQJY.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-vp7LMcSf.js → Permissions-6nFBjsQp.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-Dxr5Hgnq.js → PersonalDataHub-nQYV7xpn.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-DEPZqqH4.js → Pipeline-CBVod5jm.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DTpDiKPe.js → Privacy-D52jW1Nt.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-jDJsRWmF.js → ProjectInit-Bdx3BYhf.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-Dhor5RWH.js → ProjectSettings-b7xr4DUa.js} +2 -2
- package/src/assets/web-panel/assets/Projects-DhfifCKx.js +1 -0
- package/src/assets/web-panel/assets/Providers-Dy_PgDMr.js +1 -0
- package/src/assets/web-panel/assets/{QrScannerModal-CjIw-wIb.js → QrScannerModal-FQKSmc3e.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DX6jcqoi.js → QuickAsk-CSTrhzcF.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DopXkhar.js → Recommend-CxMABOUh.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-BLvqJE9c.js → RemoteSession-Cv2T8yRa.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-DhRj2Me7.js → Reputation-CE1k4Vvu.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DQ53vuPq.js → Row-BNgNcAV_.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BslvwiBD.js → RssFeed-5ZiBZ3ph.js} +3 -3
- package/src/assets/web-panel/assets/{Search-DJKBDNKZ.js → Search-mDOIF1UV.js} +1 -1
- package/src/assets/web-panel/assets/{Security-COhpxHER.js → Security-CtuCTC-e.js} +3 -3
- package/src/assets/web-panel/assets/{Services-dbulD6cI.js → Services-DxFO2Zg7.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-ciIVNfhC.js → Skeleton-CKmKkH9y.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-AiRTkTCk.js → Skills-Bmzl9qkk.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DDMcWYBc.js → Sla-9RqaWHOC.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BPxWbpXO.js → SpeechSettings-CGdzFIYw.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BoEOXCyg.js → SyncSettings-CvNuCeBT.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-B_sLdcnw.js +1 -0
- package/src/assets/web-panel/assets/{Templates-UowY8Ixe.js → Templates-D9_YijdK.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DauSLQXN.js → Tenant-Cuc7BUSP.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DBj7Jneq.js → Terminal-6VYRnJgd.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-UMrPwoZC.js → TimelineRenderer-GtK8xd8Y.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-4ea96-bn.js → Tokens-BZ94Lt5W.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger--ISCqt4b.js → Trigger-DEcZgDaX.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-D4GVimRJ.js → Trust-CC3z9THe.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-Ci-nXRQc.js → UkeySign-Cvtw8cV3.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-Cjk7mKPw.js → VideoEditing-CL4e6Bn3.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BgOLOO3Z.js → Wallet-ycEemP27.js} +2 -2
- package/src/assets/web-panel/assets/{WebAuthn-CCX0K29i.js → WebAuthn-DgZ4X_aw.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-Ch3zgIsE.js → WorkflowEditor-D0qMhSv7.js} +1 -1
- package/src/assets/web-panel/assets/{chat-DKOU_2Vb.js → chat-DsAg01Zn.js} +1 -1
- package/src/assets/web-panel/assets/{colors-6OVo4u3C.js → colors-B0oqAhrQ.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BH78Hlsq.js → compact-item-CmX0Rabz.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CFRpSbbC.js → createContext-Be4cn1Ub.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-CP2qzG6D.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DNQhgcVi.js → hasIn-D5v12kVq.js} +1 -1
- package/src/assets/web-panel/assets/{index-BkN3iTTp.js → index-0eWLkQKT.js} +1 -1
- package/src/assets/web-panel/assets/{index-CkNEMANR.js → index-301ogenv.js} +1 -1
- package/src/assets/web-panel/assets/{index-D3RtTT4K.js → index-5LGY0JbG.js} +1 -1
- package/src/assets/web-panel/assets/{index-dDkoL4Pe.js → index-7VKDn-t1.js} +1 -1
- package/src/assets/web-panel/assets/{index-BHa4WyTZ.js → index-8WvYGnON.js} +1 -1
- package/src/assets/web-panel/assets/{index-CaYqY35Z.js → index-B1YGjOWC.js} +1 -1
- package/src/assets/web-panel/assets/{index-bKm3TUDp.js → index-B3mUHuVc.js} +1 -1
- package/src/assets/web-panel/assets/{index--rq90rL9.js → index-BA4oulaP.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaDgdJYj.js → index-BBREnn1V.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_Z-YoxX.js → index-BBvyHguy.js} +1 -1
- package/src/assets/web-panel/assets/{index-CkqHgG-b.js → index-BKmsS2jj.js} +1 -1
- package/src/assets/web-panel/assets/{index-CrcLHN2F.js → index-BRIqLy1m.js} +1 -1
- package/src/assets/web-panel/assets/{index-BaVE6E8y.js → index-BXGSbelg.js} +3 -3
- package/src/assets/web-panel/assets/{index-BYrnm5Ob.js → index-BaE0Ui07.js} +1 -1
- package/src/assets/web-panel/assets/{index-BDSR7ecX.js → index-BoAIAZ5C.js} +1 -1
- package/src/assets/web-panel/assets/{index-CNuCHHQT.js → index-BqltWojQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Eag8e_mA.js → index-CGiIyTZw.js} +1 -1
- package/src/assets/web-panel/assets/index-CKB0vbJU.js +1 -0
- package/src/assets/web-panel/assets/{index-BepBTpa8.js → index-CZ2wUEgr.js} +1 -1
- package/src/assets/web-panel/assets/{index-HNGGVF6o.js → index-CZpfzcuy.js} +1 -1
- package/src/assets/web-panel/assets/{index-AuBhLqOm.js → index-Ckrk3pIV.js} +1 -1
- package/src/assets/web-panel/assets/{index-7TC3S8SN.js → index-CqoCZ5vR.js} +1 -1
- package/src/assets/web-panel/assets/{index-CFPJ8yzF.js → index-CyWBir7N.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bb6kDrUx.js → index-CyyGTMKd.js} +1 -1
- package/src/assets/web-panel/assets/{index-DKN2noIF.js → index-D0BSkxYQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Du0rnksC.js → index-D5YVopyr.js} +1 -1
- package/src/assets/web-panel/assets/{index-BxRy5LPR.js → index-DKUBj36_.js} +1 -1
- package/src/assets/web-panel/assets/{index-sm7W8AXy.js → index-DM724NgU.js} +1 -1
- package/src/assets/web-panel/assets/{index-BujsOZfc.js → index-DQRsQen0.js} +1 -1
- package/src/assets/web-panel/assets/index-DgoXmwqB.js +1 -0
- package/src/assets/web-panel/assets/{index-Y9MJv28e.js → index-DikJ0Qqe.js} +1 -1
- package/src/assets/web-panel/assets/{index-caye7AOE.js → index-Dn2dSdXx.js} +1 -1
- package/src/assets/web-panel/assets/{index-cdf7fd7d.js → index-DyUaFWEk.js} +1 -1
- package/src/assets/web-panel/assets/{index-BnnXQot_.js → index-Hfe_dEGx.js} +1 -1
- package/src/assets/web-panel/assets/{index-DvHGtNnF.js → index-_JjRLSD0.js} +1 -1
- package/src/assets/web-panel/assets/{index-nbfHl1oV.js → index-frSojpHj.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cu3L4r5l.js → index-jK3ax6Z6.js} +1 -1
- package/src/assets/web-panel/assets/{index-D84id2Y4.js → index-qMuZ-NRR.js} +1 -1
- package/src/assets/web-panel/assets/{index-hPY0fFrd.js → index-q_fQ94SE.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BZ9w6jPL.js → initDefaultProps-D4VdhJ9_.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BnwUiOho.js → motion-CZJA0MQW.js} +1 -1
- package/src/assets/web-panel/assets/{move-ByUKJnNm.js → move-BqEs7Sb1.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-V7yK1KEl.js → mtc-parser-BpHEtsu1.js} +1 -1
- package/src/assets/web-panel/assets/{omit-BEXBBt4j.js → omit-BW94tY9W.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-qDm_46Gi.js → pickAttrs-BnBjPWP9.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BIbhEo_0.js → placementArrow-uUkjQ_hu.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-NbPbDgA_.js → responsiveObserve-B-klUqXK.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BnUWglZ0.js → slide-CvY1cNAs.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BX8_wZI5.js → statusUtils-Ix5sEDT2.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BV4OycQX.js → styleChecker-C8qcXOne.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-Od_H5llY.js → useFlexGapSupport-KNF6Kj8f.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BWI-PyiX.js → useFs-DGJr345n.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BqMuhG3g.js → usePersonalDataHub-BboN99rI.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-DNd23z6f.js → vnode-Bgt8Vgte.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-Cjaxnm7l.js → zoom-BhJtErgt.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +2 -2
- package/src/commands/agenda.js +6 -5
- package/src/commands/agent.js +237 -75
- package/src/commands/agents.js +6 -0
- package/src/commands/artifacts.js +98 -0
- package/src/commands/background-session.js +11 -1
- package/src/commands/mcp.js +218 -31
- package/src/commands/review.js +221 -22
- package/src/commands/session-mcp-recovery.js +5 -5
- package/src/data/changelog.json +27 -1
- package/src/gateways/ws/ws-agent-handler.js +492 -14
- package/src/harness/jsonl-session-store.js +39 -1
- package/src/harness/mcp-client.js +414 -71
- package/src/harness/prompt-compressor.js +24 -0
- package/src/harness/provider-backed-compaction.js +205 -0
- package/src/harness/worktree-isolator.js +26 -3
- package/src/lib/agent-worktree.js +41 -2
- package/src/lib/app-preview.js +3 -0
- package/src/lib/background-agent-supervisor.js +790 -186
- package/src/lib/background-command-argv.js +318 -0
- package/src/lib/background-launch-profile.js +1 -0
- package/src/lib/background-phase-reporter.js +22 -2
- package/src/lib/background-worktree-policy.js +109 -0
- package/src/lib/command-lifecycle-report.js +1340 -145
- package/src/lib/cowork-mcp-tools.js +51 -6
- package/src/lib/cowork-task-runner.js +1 -0
- package/src/lib/delivery-coordinator.js +30 -5
- package/src/lib/delivery-production-adapter.js +1777 -0
- package/src/lib/delivery-production-runner.js +240 -0
- package/src/lib/durable-security-store.js +29 -17
- package/src/lib/execution-trace/trace-context.cjs +179 -0
- package/src/lib/execution-trace/trace-context.js +8 -175
- package/src/lib/mcp-call-ledger-store.js +58 -6
- package/src/lib/mcp-headers-helper.js +76 -8
- package/src/lib/mcp-host-recovery-runtime.js +2 -0
- package/src/lib/mcp-ledger-recovery-admission.js +39 -3
- package/src/lib/mcp-recovery-adjudication.js +256 -19
- package/src/lib/mcp-sandbox-policy.js +184 -0
- package/src/lib/mcp-stdio-capsule-builder-worker.cjs +495 -0
- package/src/lib/mcp-stdio-executable-identity.js +33 -2
- package/src/lib/mcp-stdio-execution-authority.js +163 -0
- package/src/lib/mcp-stdio-immutable-vfs-resolver.cjs +830 -0
- package/src/lib/mcp-stdio-package-materialization.js +721 -333
- package/src/lib/mcp-stdio-workspace-authority.js +252 -0
- package/src/lib/observability/index.js +2 -0
- package/src/lib/observability/otlp-exporter.js +2 -2
- package/src/lib/packer/pack-update-applier.js +8 -1
- package/src/lib/packer/pkg-config-generator.js +34 -0
- package/src/lib/plugin-runtime/sandbox-policy.js +42 -2
- package/src/lib/process-execution-broker/index.js +213 -109
- package/src/lib/process-execution-broker/platform-sandbox.js +1024 -169
- package/src/lib/process-tree-termination.js +17 -1
- package/src/lib/scheduler-kernel/contract.js +315 -0
- package/src/lib/scheduler-kernel/store.js +1345 -0
- package/src/lib/session-host-lease.js +403 -30
- package/src/lib/session-persistence-failure.js +4 -1
- package/src/lib/skill-mcp.js +65 -4
- package/src/lib/sub-agent-context.js +8 -0
- package/src/lib/web-fetch.js +4 -4
- package/src/repl/agent-repl.js +285 -38
- package/src/runtime/agent-core.js +1044 -90
- package/src/runtime/agent-runtime.js +61 -8
- package/src/runtime/headless-runner.js +260 -166
- package/src/runtime/headless-stream.js +254 -25
- package/src/runtime/mcp-config.js +235 -28
- package/src/workers/background-agent-worker.js +492 -71
- package/src/assets/web-panel/assets/Projects-08xUDZGt.js +0 -1
- package/src/assets/web-panel/assets/Providers-BGs47s1a.js +0 -1
- package/src/assets/web-panel/assets/Tasks-CEYFJwmr.js +0 -1
- package/src/assets/web-panel/assets/devWarning-DEMblAIm.js +0 -1
- package/src/assets/web-panel/assets/index-BTvq-36D.js +0 -1
- package/src/assets/web-panel/assets/index-hUpvk6Jl.js +0 -1
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { webcrypto } = require("node:crypto");
|
|
4
|
+
const path = require("node:path");
|
|
5
|
+
const vm = require("node:vm");
|
|
6
|
+
const { parentPort, workerData } = require("node:worker_threads");
|
|
7
|
+
|
|
8
|
+
const WORKER_SCHEMA = "chainlesschain.mcp-stdio-capsule-builder-worker/v1";
|
|
9
|
+
const NONCE = /^[a-f0-9]{64}$/;
|
|
10
|
+
const MAX_OUTPUT_BYTES = 32 * 1024 * 1024;
|
|
11
|
+
const MAX_METAFILE_BYTES = 16 * 1024 * 1024;
|
|
12
|
+
const MAX_AUDIT_BYTES = 16 * 1024 * 1024;
|
|
13
|
+
const MAX_VFS_FILES = 10_001;
|
|
14
|
+
const MAX_VFS_TOTAL_BYTES = 64 * 1024 * 1024 + 64 * 1024;
|
|
15
|
+
const MAX_VFS_FILE_BYTES = 16 * 1024 * 1024;
|
|
16
|
+
const activeTimers = new Map();
|
|
17
|
+
let nextTimerId = 1;
|
|
18
|
+
let terminalSent = false;
|
|
19
|
+
|
|
20
|
+
function setTimerBridge(callback, delay, args) {
|
|
21
|
+
const id = nextTimerId++;
|
|
22
|
+
const timer = setTimeout(
|
|
23
|
+
() => {
|
|
24
|
+
activeTimers.delete(id);
|
|
25
|
+
callback(...args);
|
|
26
|
+
},
|
|
27
|
+
Math.max(0, Number(delay) || 0),
|
|
28
|
+
);
|
|
29
|
+
activeTimers.set(id, timer);
|
|
30
|
+
return id;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function clearTimerBridge(id) {
|
|
34
|
+
const timer = activeTimers.get(id);
|
|
35
|
+
if (timer) clearTimeout(timer);
|
|
36
|
+
activeTimers.delete(id);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function encodeBridge(value) {
|
|
40
|
+
return Array.from(new TextEncoder().encode(String(value)));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function decodeBridge(bytes) {
|
|
44
|
+
return new TextDecoder("utf-8").decode(Uint8Array.from(bytes));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function randomFillBridge(view) {
|
|
48
|
+
webcrypto.getRandomValues(view);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function sendTerminal(message, transferList = []) {
|
|
52
|
+
if (terminalSent) {
|
|
53
|
+
throw new Error("MCP capsule builder Worker emitted two terminal messages");
|
|
54
|
+
}
|
|
55
|
+
terminalSent = true;
|
|
56
|
+
parentPort.postMessage(message, transferList);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function loadPinnedCommonJs(source, filename) {
|
|
60
|
+
if (typeof source !== "string" || source.length === 0) {
|
|
61
|
+
throw new TypeError(`Pinned CommonJS source is empty: ${filename}`);
|
|
62
|
+
}
|
|
63
|
+
const loaded = { exports: {} };
|
|
64
|
+
const factory = vm.runInThisContext(
|
|
65
|
+
`(function(exports,require,module,__filename,__dirname){${source}\n})`,
|
|
66
|
+
{ filename },
|
|
67
|
+
);
|
|
68
|
+
factory(loaded.exports, require, loaded, filename, path.dirname(filename));
|
|
69
|
+
return loaded.exports;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function assertHardenedBrowserContext(context) {
|
|
73
|
+
const probe = new vm.Script(
|
|
74
|
+
`(() => {
|
|
75
|
+
const hidden = [
|
|
76
|
+
"process", "require", "Buffer", "fetch", "Worker", "Blob", "URL", "location"
|
|
77
|
+
];
|
|
78
|
+
const visibility = Object.fromEntries(
|
|
79
|
+
hidden.map((name) => [name, typeof globalThis[name]])
|
|
80
|
+
);
|
|
81
|
+
const probes = {
|
|
82
|
+
TextEncoder: () => TextEncoder.constructor("return typeof process")(),
|
|
83
|
+
TextDecoder: () => TextDecoder.constructor("return typeof process")(),
|
|
84
|
+
setTimeout: () => setTimeout.constructor("return typeof process")(),
|
|
85
|
+
clearTimeout: () => clearTimeout.constructor("return typeof process")(),
|
|
86
|
+
WebAssembly: () => WebAssembly.instantiate.constructor("return typeof process")(),
|
|
87
|
+
wasmModule: () => __chainlessWasmModule.constructor.constructor("return typeof process")(),
|
|
88
|
+
crypto: () => crypto.getRandomValues.constructor("return typeof process")(),
|
|
89
|
+
cryptoError: () => {
|
|
90
|
+
try {
|
|
91
|
+
crypto.getRandomValues(new Uint8Array(65_537));
|
|
92
|
+
} catch (error) {
|
|
93
|
+
return error.constructor.constructor("return typeof process")();
|
|
94
|
+
}
|
|
95
|
+
throw new Error("expected crypto.getRandomValues to reject an oversized view");
|
|
96
|
+
},
|
|
97
|
+
timerError: () => {
|
|
98
|
+
try {
|
|
99
|
+
setTimeout(() => {}, Symbol("invalid-delay"));
|
|
100
|
+
} catch (error) {
|
|
101
|
+
return error.constructor.constructor("return typeof process")();
|
|
102
|
+
}
|
|
103
|
+
throw new Error("expected setTimeout to reject a symbol delay");
|
|
104
|
+
},
|
|
105
|
+
performance: () => performance.now.constructor("return typeof process")(),
|
|
106
|
+
console: () => console.log.constructor("return typeof process")(),
|
|
107
|
+
contextFunction: () => Function("return typeof process")(),
|
|
108
|
+
};
|
|
109
|
+
const escapes = {};
|
|
110
|
+
for (const [name, attempt] of Object.entries(probes)) {
|
|
111
|
+
try {
|
|
112
|
+
escapes[name] = { blocked: false, result: attempt() };
|
|
113
|
+
} catch (error) {
|
|
114
|
+
escapes[name] = { blocked: true, result: error && error.name };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return { visibility, escapes };
|
|
118
|
+
})()`,
|
|
119
|
+
{ filename: "/chainlesschain/browser-context-security-probe.js" },
|
|
120
|
+
).runInContext(context, { timeout: 1_000 });
|
|
121
|
+
if (
|
|
122
|
+
Object.values(probe.visibility).some((value) => value !== "undefined") ||
|
|
123
|
+
Object.values(probe.escapes).some(
|
|
124
|
+
(result) => result.blocked !== true || result.result !== "EvalError",
|
|
125
|
+
)
|
|
126
|
+
) {
|
|
127
|
+
throw new Error("Pinned esbuild-wasm browser context is not isolated");
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async function loadPinnedBrowserApi(source, filename, wasmBytes) {
|
|
132
|
+
// esbuild-wasm's browser host intentionally installs its own process/fs/path
|
|
133
|
+
// shims. Node 22 exposes some of those names as globals, so forwarding the
|
|
134
|
+
// Worker global would silently select the host filesystem instead of the
|
|
135
|
+
// in-memory service transport. Host bridge functions only enter lexical
|
|
136
|
+
// closures created in this realm. They are never properties of globalThis.
|
|
137
|
+
if (!(wasmBytes instanceof Uint8Array) || wasmBytes.byteLength === 0) {
|
|
138
|
+
throw new TypeError("Pinned esbuild-wasm bytes are invalid");
|
|
139
|
+
}
|
|
140
|
+
const sandbox = Object.create(null);
|
|
141
|
+
sandbox.__chainlessWasmBytesHost = wasmBytes;
|
|
142
|
+
const context = vm.createContext(sandbox, {
|
|
143
|
+
codeGeneration: { strings: false, wasm: true },
|
|
144
|
+
name: "chainlesschain-esbuild-wasm",
|
|
145
|
+
});
|
|
146
|
+
new vm.Script(
|
|
147
|
+
`"use strict";
|
|
148
|
+
Object.defineProperties(globalThis, {
|
|
149
|
+
self: { value: globalThis },
|
|
150
|
+
module: { value: { exports: {} } },
|
|
151
|
+
});
|
|
152
|
+
Object.defineProperty(globalThis, "exports", {
|
|
153
|
+
value: globalThis.module.exports,
|
|
154
|
+
});`,
|
|
155
|
+
{ filename: "/chainlesschain/browser-context-bootstrap.js" },
|
|
156
|
+
).runInContext(context, { timeout: 1_000 });
|
|
157
|
+
const installGlobals = vm.compileFunction(
|
|
158
|
+
`class ChainlessTextEncoder {
|
|
159
|
+
encode(value = "") {
|
|
160
|
+
try {
|
|
161
|
+
return Uint8Array.from(encodeBridge(String(value)));
|
|
162
|
+
} catch {
|
|
163
|
+
throw new Error("TextEncoder bridge failed");
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
class ChainlessTextDecoder {
|
|
168
|
+
decode(input = new Uint8Array()) {
|
|
169
|
+
let view;
|
|
170
|
+
if (ArrayBuffer.isView(input)) {
|
|
171
|
+
view = new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
|
|
172
|
+
} else if (input instanceof ArrayBuffer) {
|
|
173
|
+
view = new Uint8Array(input);
|
|
174
|
+
} else {
|
|
175
|
+
throw new TypeError("Expected an ArrayBuffer view");
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
return decodeBridge(Array.from(view));
|
|
179
|
+
} catch {
|
|
180
|
+
throw new Error("TextDecoder bridge failed");
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function safeSetTimeout(callback, delay, ...args) {
|
|
185
|
+
if (typeof callback !== "function") {
|
|
186
|
+
throw new TypeError("callback must be a function");
|
|
187
|
+
}
|
|
188
|
+
try {
|
|
189
|
+
return setTimerBridge(callback, delay, args);
|
|
190
|
+
} catch {
|
|
191
|
+
throw new Error("setTimeout bridge failed");
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
function safeClearTimeout(id) {
|
|
195
|
+
try {
|
|
196
|
+
clearTimerBridge(id);
|
|
197
|
+
} catch {
|
|
198
|
+
throw new Error("clearTimeout bridge failed");
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
const safeCrypto = Object.freeze({
|
|
202
|
+
getRandomValues(view) {
|
|
203
|
+
if (!ArrayBuffer.isView(view)) {
|
|
204
|
+
throw new TypeError("Expected an integer typed array");
|
|
205
|
+
}
|
|
206
|
+
try {
|
|
207
|
+
randomFillBridge(view);
|
|
208
|
+
} catch {
|
|
209
|
+
throw new Error("crypto.getRandomValues bridge failed");
|
|
210
|
+
}
|
|
211
|
+
return view;
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
const safePerformance = Object.freeze({ now() { return Date.now(); } });
|
|
215
|
+
Object.defineProperties(globalThis, {
|
|
216
|
+
TextEncoder: { value: ChainlessTextEncoder },
|
|
217
|
+
TextDecoder: { value: ChainlessTextDecoder },
|
|
218
|
+
setTimeout: { value: safeSetTimeout },
|
|
219
|
+
clearTimeout: { value: safeClearTimeout },
|
|
220
|
+
crypto: { value: safeCrypto },
|
|
221
|
+
performance: { value: safePerformance },
|
|
222
|
+
});`,
|
|
223
|
+
[
|
|
224
|
+
"encodeBridge",
|
|
225
|
+
"decodeBridge",
|
|
226
|
+
"setTimerBridge",
|
|
227
|
+
"clearTimerBridge",
|
|
228
|
+
"randomFillBridge",
|
|
229
|
+
],
|
|
230
|
+
{
|
|
231
|
+
filename: "/chainlesschain/browser-context-primitives.js",
|
|
232
|
+
parsingContext: context,
|
|
233
|
+
},
|
|
234
|
+
);
|
|
235
|
+
installGlobals(
|
|
236
|
+
encodeBridge,
|
|
237
|
+
decodeBridge,
|
|
238
|
+
setTimerBridge,
|
|
239
|
+
clearTimerBridge,
|
|
240
|
+
randomFillBridge,
|
|
241
|
+
);
|
|
242
|
+
await new vm.Script(
|
|
243
|
+
`(async () => {
|
|
244
|
+
const localBytes = Uint8Array.from(__chainlessWasmBytesHost);
|
|
245
|
+
delete globalThis.__chainlessWasmBytesHost;
|
|
246
|
+
globalThis.__chainlessWasmModule = await WebAssembly.compile(localBytes);
|
|
247
|
+
})()`,
|
|
248
|
+
{ filename: "/chainlesschain/compile-pinned-wasm.js" },
|
|
249
|
+
).runInContext(context, { timeout: 1_000 });
|
|
250
|
+
assertHardenedBrowserContext(context);
|
|
251
|
+
const script = new vm.Script(
|
|
252
|
+
`(function(exports,module){${source}\n})(exports,module);`,
|
|
253
|
+
{ filename },
|
|
254
|
+
);
|
|
255
|
+
script.runInContext(context, { timeout: 5_000 });
|
|
256
|
+
assertHardenedBrowserContext(context);
|
|
257
|
+
return Object.freeze({
|
|
258
|
+
api: context.module.exports,
|
|
259
|
+
RegExp: vm.runInContext("RegExp", context),
|
|
260
|
+
Uint8Array: vm.runInContext("Uint8Array", context),
|
|
261
|
+
wasmModule: vm.runInContext("__chainlessWasmModule", context),
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function adaptPluginToBrowserRealm(plugin, browserRealm) {
|
|
266
|
+
if (
|
|
267
|
+
!plugin ||
|
|
268
|
+
typeof plugin.name !== "string" ||
|
|
269
|
+
typeof plugin.setup !== "function" ||
|
|
270
|
+
typeof browserRealm?.RegExp !== "function" ||
|
|
271
|
+
typeof browserRealm?.Uint8Array !== "function"
|
|
272
|
+
) {
|
|
273
|
+
throw new TypeError("MCP capsule immutable VFS plugin is invalid");
|
|
274
|
+
}
|
|
275
|
+
const cloneFilter = (options) => {
|
|
276
|
+
if (
|
|
277
|
+
!options ||
|
|
278
|
+
typeof options !== "object" ||
|
|
279
|
+
!(options.filter instanceof RegExp)
|
|
280
|
+
) {
|
|
281
|
+
throw new TypeError("MCP capsule immutable VFS filter is invalid");
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
...options,
|
|
285
|
+
filter: new browserRealm.RegExp(
|
|
286
|
+
options.filter.source,
|
|
287
|
+
options.filter.flags,
|
|
288
|
+
),
|
|
289
|
+
};
|
|
290
|
+
};
|
|
291
|
+
const cloneContents = (result) => {
|
|
292
|
+
if (
|
|
293
|
+
!result ||
|
|
294
|
+
typeof result !== "object" ||
|
|
295
|
+
result.contents === undefined
|
|
296
|
+
) {
|
|
297
|
+
return result;
|
|
298
|
+
}
|
|
299
|
+
if (!(result.contents instanceof Uint8Array)) {
|
|
300
|
+
throw new TypeError("MCP capsule immutable VFS contents are invalid");
|
|
301
|
+
}
|
|
302
|
+
const contents = new browserRealm.Uint8Array(result.contents.byteLength);
|
|
303
|
+
contents.set(result.contents);
|
|
304
|
+
return { ...result, contents };
|
|
305
|
+
};
|
|
306
|
+
return Object.freeze({
|
|
307
|
+
name: plugin.name,
|
|
308
|
+
setup(build) {
|
|
309
|
+
const bridge = Object.create(null);
|
|
310
|
+
bridge.onResolve = (options, callback) =>
|
|
311
|
+
build.onResolve(cloneFilter(options), callback);
|
|
312
|
+
bridge.onLoad = (options, callback) =>
|
|
313
|
+
build.onLoad(cloneFilter(options), async (args) =>
|
|
314
|
+
cloneContents(await callback(args)),
|
|
315
|
+
);
|
|
316
|
+
return plugin.setup(Object.freeze(bridge));
|
|
317
|
+
},
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function assertWorkerInput(input) {
|
|
322
|
+
if (
|
|
323
|
+
!input ||
|
|
324
|
+
input.schema !== WORKER_SCHEMA ||
|
|
325
|
+
!NONCE.test(input.nonce) ||
|
|
326
|
+
typeof input.browserApiSource !== "string" ||
|
|
327
|
+
typeof input.resolverSource !== "string" ||
|
|
328
|
+
!(input.wasmBytes instanceof Uint8Array) ||
|
|
329
|
+
!Array.isArray(input.files) ||
|
|
330
|
+
typeof input.entryPath !== "string" ||
|
|
331
|
+
typeof input.banner !== "string" ||
|
|
332
|
+
!Number.isSafeInteger(input.fileCount) ||
|
|
333
|
+
input.fileCount < 1 ||
|
|
334
|
+
input.fileCount > MAX_VFS_FILES ||
|
|
335
|
+
!Number.isSafeInteger(input.totalBytes) ||
|
|
336
|
+
input.totalBytes < 1 ||
|
|
337
|
+
input.totalBytes > MAX_VFS_TOTAL_BYTES ||
|
|
338
|
+
!Number.isSafeInteger(input.maxOutputBytes) ||
|
|
339
|
+
input.maxOutputBytes < 1 ||
|
|
340
|
+
input.maxOutputBytes > MAX_OUTPUT_BYTES ||
|
|
341
|
+
!Number.isSafeInteger(input.maxMetafileBytes) ||
|
|
342
|
+
input.maxMetafileBytes < 1 ||
|
|
343
|
+
input.maxMetafileBytes > MAX_METAFILE_BYTES
|
|
344
|
+
) {
|
|
345
|
+
throw new TypeError("MCP capsule builder Worker input is invalid");
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function serializeError(error) {
|
|
350
|
+
return {
|
|
351
|
+
name: typeof error?.name === "string" ? error.name : "Error",
|
|
352
|
+
code: typeof error?.code === "string" ? error.code : null,
|
|
353
|
+
message: String(error?.message || error || "Unknown builder failure").slice(
|
|
354
|
+
0,
|
|
355
|
+
8_000,
|
|
356
|
+
),
|
|
357
|
+
stack:
|
|
358
|
+
typeof error?.stack === "string" ? error.stack.slice(0, 32_000) : null,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
async function main() {
|
|
363
|
+
assertWorkerInput(workerData);
|
|
364
|
+
const { ImmutableVfsResolver } = loadPinnedCommonJs(
|
|
365
|
+
workerData.resolverSource,
|
|
366
|
+
"/chainlesschain/immutable-vfs-resolver.cjs",
|
|
367
|
+
);
|
|
368
|
+
if (typeof ImmutableVfsResolver !== "function") {
|
|
369
|
+
throw new TypeError("Pinned immutable VFS resolver export is invalid");
|
|
370
|
+
}
|
|
371
|
+
const browserRealm = await loadPinnedBrowserApi(
|
|
372
|
+
workerData.browserApiSource,
|
|
373
|
+
"/chainlesschain/esbuild-wasm-browser.js",
|
|
374
|
+
workerData.wasmBytes,
|
|
375
|
+
);
|
|
376
|
+
workerData.wasmBytes = null;
|
|
377
|
+
const esbuild = browserRealm.api;
|
|
378
|
+
if (
|
|
379
|
+
esbuild?.version !== workerData.builderVersion ||
|
|
380
|
+
typeof esbuild.initialize !== "function" ||
|
|
381
|
+
typeof esbuild.build !== "function" ||
|
|
382
|
+
typeof esbuild.stop !== "function"
|
|
383
|
+
) {
|
|
384
|
+
throw new TypeError("Pinned esbuild-wasm browser API is invalid");
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
const files = new Map();
|
|
388
|
+
let totalBytes = 0;
|
|
389
|
+
for (const record of workerData.files) {
|
|
390
|
+
if (
|
|
391
|
+
!Array.isArray(record) ||
|
|
392
|
+
record.length !== 2 ||
|
|
393
|
+
typeof record[0] !== "string" ||
|
|
394
|
+
!(record[1] instanceof Uint8Array) ||
|
|
395
|
+
record[1].byteLength > MAX_VFS_FILE_BYTES ||
|
|
396
|
+
files.has(record[0])
|
|
397
|
+
) {
|
|
398
|
+
throw new TypeError("MCP capsule immutable VFS record is invalid");
|
|
399
|
+
}
|
|
400
|
+
files.set(record[0], record[1]);
|
|
401
|
+
totalBytes += record[1].byteLength;
|
|
402
|
+
}
|
|
403
|
+
if (
|
|
404
|
+
files.size !== workerData.fileCount ||
|
|
405
|
+
totalBytes !== workerData.totalBytes
|
|
406
|
+
) {
|
|
407
|
+
throw new TypeError("MCP capsule immutable VFS budget changed in transit");
|
|
408
|
+
}
|
|
409
|
+
const resolver = new ImmutableVfsResolver(files, {
|
|
410
|
+
root: workerData.vfsRoot,
|
|
411
|
+
});
|
|
412
|
+
// Drop the structured-clone container before the WASM build. The resolver
|
|
413
|
+
// owns private copies and no callback outside this Worker can mutate them.
|
|
414
|
+
files.clear();
|
|
415
|
+
workerData.files.length = 0;
|
|
416
|
+
|
|
417
|
+
await esbuild.initialize({
|
|
418
|
+
wasmModule: browserRealm.wasmModule,
|
|
419
|
+
worker: false,
|
|
420
|
+
});
|
|
421
|
+
let terminal;
|
|
422
|
+
try {
|
|
423
|
+
const result = await esbuild.build({
|
|
424
|
+
absWorkingDir: "/",
|
|
425
|
+
banner: { js: workerData.banner },
|
|
426
|
+
bundle: true,
|
|
427
|
+
charset: "utf8",
|
|
428
|
+
entryPoints: [workerData.entryPath],
|
|
429
|
+
format: "cjs",
|
|
430
|
+
legalComments: "none",
|
|
431
|
+
logLevel: "silent",
|
|
432
|
+
metafile: true,
|
|
433
|
+
outfile: "/chainlesschain-output/server.cjs",
|
|
434
|
+
packages: "bundle",
|
|
435
|
+
platform: "node",
|
|
436
|
+
plugins: [
|
|
437
|
+
adaptPluginToBrowserRealm(
|
|
438
|
+
resolver.createEsbuildPlugin(workerData.entryPath),
|
|
439
|
+
browserRealm,
|
|
440
|
+
),
|
|
441
|
+
],
|
|
442
|
+
supported: { "dynamic-import": false },
|
|
443
|
+
target: "node22",
|
|
444
|
+
treeShaking: false,
|
|
445
|
+
write: false,
|
|
446
|
+
});
|
|
447
|
+
if (
|
|
448
|
+
!result ||
|
|
449
|
+
!Array.isArray(result.outputFiles) ||
|
|
450
|
+
result.outputFiles.length !== 1 ||
|
|
451
|
+
!(result.outputFiles[0]?.contents instanceof browserRealm.Uint8Array) ||
|
|
452
|
+
result.outputFiles[0].contents.byteLength > workerData.maxOutputBytes ||
|
|
453
|
+
!result.metafile ||
|
|
454
|
+
typeof result.metafile !== "object" ||
|
|
455
|
+
!Array.isArray(result.warnings)
|
|
456
|
+
) {
|
|
457
|
+
throw new Error("MCP capsule esbuild-wasm output is invalid");
|
|
458
|
+
}
|
|
459
|
+
const metafileBytes = Buffer.byteLength(JSON.stringify(result.metafile));
|
|
460
|
+
if (metafileBytes > workerData.maxMetafileBytes) {
|
|
461
|
+
throw new Error("MCP capsule esbuild-wasm metafile exceeds its limit");
|
|
462
|
+
}
|
|
463
|
+
const browserOutput = result.outputFiles[0].contents;
|
|
464
|
+
const output = new Uint8Array(browserOutput.byteLength);
|
|
465
|
+
output.set(browserOutput);
|
|
466
|
+
const audit = resolver.audit();
|
|
467
|
+
if (Buffer.byteLength(JSON.stringify(audit)) > MAX_AUDIT_BYTES) {
|
|
468
|
+
throw new Error("MCP capsule immutable VFS audit exceeds its limit");
|
|
469
|
+
}
|
|
470
|
+
terminal = {
|
|
471
|
+
ok: true,
|
|
472
|
+
nonce: workerData.nonce,
|
|
473
|
+
output,
|
|
474
|
+
metafile: result.metafile,
|
|
475
|
+
warnings: result.warnings,
|
|
476
|
+
audit,
|
|
477
|
+
};
|
|
478
|
+
} finally {
|
|
479
|
+
await esbuild.stop();
|
|
480
|
+
}
|
|
481
|
+
sendTerminal(terminal, [terminal.output.buffer]);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
main()
|
|
485
|
+
.catch((error) => {
|
|
486
|
+
sendTerminal({
|
|
487
|
+
ok: false,
|
|
488
|
+
nonce: workerData?.nonce,
|
|
489
|
+
error: serializeError(error),
|
|
490
|
+
});
|
|
491
|
+
})
|
|
492
|
+
.finally(() => {
|
|
493
|
+
for (const timer of activeTimers.values()) clearTimeout(timer);
|
|
494
|
+
activeTimers.clear();
|
|
495
|
+
});
|
|
@@ -48,6 +48,12 @@ export const MCP_STDIO_RUNTIME_KIND_INVALID_CODE =
|
|
|
48
48
|
export const MCP_STDIO_CAPSULE_SANDBOX_CONTRACT_KIND =
|
|
49
49
|
"strict-mcp-node-capsule";
|
|
50
50
|
export const MCP_STDIO_CAPSULE_CODE_SNAPSHOT_BOUNDARY = "code-snapshot";
|
|
51
|
+
export const MCP_STDIO_CAPSULE_REQUIRED_BOUNDARIES = Object.freeze([
|
|
52
|
+
MCP_STDIO_CAPSULE_CODE_SNAPSHOT_BOUNDARY,
|
|
53
|
+
"filesystem",
|
|
54
|
+
"network",
|
|
55
|
+
"process-tree",
|
|
56
|
+
]);
|
|
51
57
|
|
|
52
58
|
const STORE_LABEL = "MCP stdio executable identity";
|
|
53
59
|
const WITNESS_LABEL = "MCP stdio executable identity anti-rollback witness";
|
|
@@ -783,6 +789,28 @@ function identityDigest(identity) {
|
|
|
783
789
|
return sha256(JSON.stringify(comparableIdentity(identity)));
|
|
784
790
|
}
|
|
785
791
|
|
|
792
|
+
export function nanosecondsToSafeMilliseconds(value) {
|
|
793
|
+
const nanoseconds = BigInt(value);
|
|
794
|
+
const maximumSafeNanoseconds = BigInt(Number.MAX_SAFE_INTEGER) * 1_000_000n;
|
|
795
|
+
if (
|
|
796
|
+
nanoseconds > maximumSafeNanoseconds ||
|
|
797
|
+
nanoseconds < -maximumSafeNanoseconds
|
|
798
|
+
) {
|
|
799
|
+
throw new RangeError(
|
|
800
|
+
"MCP capsule file timestamp exceeds safe milliseconds",
|
|
801
|
+
);
|
|
802
|
+
}
|
|
803
|
+
const wholeMilliseconds = nanoseconds / 1_000_000n;
|
|
804
|
+
const remainderNanoseconds = nanoseconds % 1_000_000n;
|
|
805
|
+
const numericWholeMilliseconds = Number(wholeMilliseconds);
|
|
806
|
+
if (!Number.isSafeInteger(numericWholeMilliseconds)) {
|
|
807
|
+
throw new RangeError(
|
|
808
|
+
"MCP capsule file timestamp exceeds safe milliseconds",
|
|
809
|
+
);
|
|
810
|
+
}
|
|
811
|
+
return numericWholeMilliseconds + Number(remainderNanoseconds) / 1_000_000;
|
|
812
|
+
}
|
|
813
|
+
|
|
786
814
|
function capsuleSandboxFileIdentity(identity, requestedPath) {
|
|
787
815
|
return Object.freeze({
|
|
788
816
|
...(requestedPath ? { requestedPath } : {}),
|
|
@@ -791,7 +819,7 @@ function capsuleSandboxFileIdentity(identity, requestedPath) {
|
|
|
791
819
|
bytes: identity.bytes,
|
|
792
820
|
dev: identity.dev,
|
|
793
821
|
ino: identity.ino,
|
|
794
|
-
mtimeMs:
|
|
822
|
+
mtimeMs: nanosecondsToSafeMilliseconds(identity.mtimeNs),
|
|
795
823
|
mode: identity.mode,
|
|
796
824
|
});
|
|
797
825
|
}
|
|
@@ -859,6 +887,7 @@ function issueCapsuleSandboxExecutionContract({
|
|
|
859
887
|
args: Object.freeze([...attestation.launchArgs]),
|
|
860
888
|
cwd: capsuleRoot.realPath,
|
|
861
889
|
identityDigest: attestation.identityDigest,
|
|
890
|
+
requiredBoundaries: MCP_STDIO_CAPSULE_REQUIRED_BOUNDARIES,
|
|
862
891
|
}),
|
|
863
892
|
);
|
|
864
893
|
return contract;
|
|
@@ -886,7 +915,9 @@ export function consumeMcpStdioCapsuleSandboxExecutionContract(
|
|
|
886
915
|
provenance.shell === false &&
|
|
887
916
|
provenance.sync === false &&
|
|
888
917
|
provenance.identityDigest === issued.identityDigest &&
|
|
889
|
-
requiredBoundaries.
|
|
918
|
+
issued.requiredBoundaries.every((boundary) =>
|
|
919
|
+
requiredBoundaries.includes(boundary),
|
|
920
|
+
) &&
|
|
890
921
|
args.length === issued.args.length &&
|
|
891
922
|
args.every((value, index) => value === issued.args[index])
|
|
892
923
|
);
|