chainlesschain 0.163.8 → 0.165.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +7 -4
- package/scripts/macos-mcp-launcher-build.mjs +317 -0
- package/scripts/macos-mcp-launcher-postinstall.sh +54 -0
- package/scripts/macos-mcp-launcher-preinstall.sh +61 -0
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-CavM7W3k.js → AIOps-CYxFDrcm.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CUvZGabQ.js → ActionButton-CPBtdiU2.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DeBnWnbe.js → Analytics-Dayq7Dp7.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DbI5kxvd.js → AppLayout-6U7bPb2s.js} +4 -4
- package/src/assets/web-panel/assets/{Artifacts-D93bigKm.js → Artifacts-D2Iqg_3D.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CBNvfUZa.js → Audit-CdoOB7WV.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-CJLyh_YU.js → BackgroundAgents-DrnAVB8w.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-D_0yoehD.js → Backup-CesMi5cy.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-TJxmbObW.js → BaseInput-DaX9ptax.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CE0dto1q.js → Chat-OrwOPxDS.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CZ5-yYiD.js → ChatBubbleRenderer-CvPZFRxM.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-Ck1RVIVo.js → Checkbox-DiHbcysC.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-qpoyf6DK.js → Codegen-CbgCkaBJ.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DUyPWjIE.js → Col-Du5hgrh4.js} +1 -1
- package/src/assets/web-panel/assets/{Community-D_S1BemS.js → Community-DsPOBW-p.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BjxeK-Gc.js → Compact-BwHIFkNC.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-Dd3CEJsu.js → Compliance-BvrDQSgd.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-B4QG7-ad.js → Cowork-gwAE6arx.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-BtZnids5.js → Cron-DW-0l4uF.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CHPfCBFD.js → Crosschain-j-NsLesB.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DT8DCEOK.js → DID-CibVEBOI.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-COQab5_U.js → Dashboard-W4z9vSfe.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BY1PsQuU.js → Dropdown-DAcrkKxG.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CsuAuaq3.js → EmailListRenderer-6GXah-89.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-BqpinD-j.js → FamilyGuardDashboard-TKDCq8Ku.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-D0gkfQFv.js → Federation-BXBLlcNm.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BqgE-axK.js → FormItemContext-BoJJBkG3.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-D0hJ2KvC.js → GenericCardRenderer-okjsl46v.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CmMB0uPY.js → Git-Rvs7i6nn.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-BnVEI0Dk.js → Governance-CHSUxXXS.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-YTAMihRP.js → Inference-V3BlfxsB.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-0ax7VHop.js → KnowledgeGraph-C_NlD4aR.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-B9TRcokL.js → Logs-Nn4LNxhA.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-SVAgNnkt.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-B6CSuD_H.js → Marketplace-DEmjFcg-.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-CjMXvOVU.js → McpTools-DlopXipI.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-CXRF71U3.js → Memory-BG3ynX60.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DQgNp_oS.js → MobileBridge-DeRzWOfT.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DlPwcCbq.js → MobileProjects-Tyd3o2A0.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-6hDTRPe1.js → Mtc-BoPbOv1C.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-BlVHU1DS.js → MtcAudit-un-rTHp7.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-DP9pzEbV.js → Multisig-Ds0oveEB.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Djorh8EV.js → NLProgramming-D09JI-yY.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-oLZ-JkUg.js → Notes-DTRhiKJn.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-Cg288VH3.js → NotificationSettings-BAnnNCim.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-Yr-1fSYi.js +1 -0
- package/src/assets/web-panel/assets/{Organization-CBdo-bHs.js → Organization-S9EAolpj.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-qZdnVumx.js → Overflow-CqcLKqJ8.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-D4kNfGNQ.js → P2P-Dw0F9EcU.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-DnlMemM7.js → PdhVaultBrowser-BDRwUevN.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-DHucHFBJ.js → Permissions-D3_c3nKB.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-BovlOIPR.js → PersonalDataHub-CxdMV98x.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-Deru3CQY.js → Pipeline-CgjNQFLI.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-Bq5oTTbU.js → Privacy-BHghIIht.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-BfzxVWAz.js → ProjectInit-De6pqaKM.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CKC6XBtH.js → ProjectSettings-Bg4ZkNYQ.js} +2 -2
- package/src/assets/web-panel/assets/Projects-CP8vPvzs.js +1 -0
- package/src/assets/web-panel/assets/{Providers-C_jx4TWX.js → Providers-CUnHbNf-.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-BdIHeVGC.js → QrScannerModal-DA2f3Wts.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BwZwAcPD.js → QuickAsk-C1FeHDqp.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BNTt0L-m.js → Recommend-B5guaUMN.js} +1 -1
- package/src/assets/web-panel/assets/RemoteSession-PDADSds3.js +5 -0
- package/src/assets/web-panel/assets/{Reputation-D6VpG32B.js → Reputation-eTlRhgvK.js} +1 -1
- package/src/assets/web-panel/assets/{Row-D_74OvQQ.js → Row-D7AqSGY0.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BTr0a-BQ.js → RssFeed-JiuLm4Ja.js} +3 -3
- package/src/assets/web-panel/assets/{Search-C3MCFoNU.js → Search-CwruahW3.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CqW9aJ6s.js → Security-CdhqaR0b.js} +4 -4
- package/src/assets/web-panel/assets/{Services-Cw5GNaHF.js → Services-CU0ZIlcT.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DZps5qeY.js → Skeleton-CtduPfAb.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-C6NQ1znT.js → Skills-CROXm6AY.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DFP8G2Sh.js → Sla-DiZiABFD.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-ESt6MB6v.js → SpeechSettings-B5pLcXUw.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BHnN98aM.js → SyncSettings-DBX6J1Oe.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-NiSCaOf-.js → Tasks-BLyRJd3-.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-DsKFhW2C.js → Templates-BKa5qzmk.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CQ0E0ze5.js → Tenant-DnD3a4M6.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-D_rBu_by.js → Terminal-DEitQeTb.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-D3Vm4Po4.js → TimelineRenderer-CjHggTDq.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DNTxRH6q.js → Tokens-CsGT7sfl.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-Dgprz1ms.js → Trigger-yr4rFDrW.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-B2rUnVBD.js → Trust-CLvu1Sjp.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DEGQNc6_.js → UkeySign-B0m7yUP8.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-jlsAx3Eh.js → VideoEditing-C0VvP4lc.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-8jQih1ij.js → Wallet-kllBAG1M.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-XLeO6xIB.js → WebAuthn-C54UQNLx.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-De_dgDAG.js → WorkflowEditor-B7y8qSvU.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CI19R_Sk.js → chat-DRzTh8CJ.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DsYTOYN3.js → colors-BSMwSnCx.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-CM3-t_Qr.js → compact-item-BTg602H5.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BjxlBRZv.js → createContext-B6EGsdvp.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-Dol8jLEP.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-RDaWX_4i.js → hasIn-DDKqJ8RD.js} +1 -1
- package/src/assets/web-panel/assets/{index-nAH87mQP.js → index-323Hhxxt.js} +1 -1
- package/src/assets/web-panel/assets/{index-DIUnNOjG.js → index-BICn3Qh1.js} +1 -1
- package/src/assets/web-panel/assets/{index-DyIWssPC.js → index-BMuGd2--.js} +1 -1
- package/src/assets/web-panel/assets/{index-DX7tuWVJ.js → index-BRqt4fO-.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cd3euP_4.js → index-BVTAl5N2.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cpqm1qfU.js → index-BsR7Y2NG.js} +1 -1
- package/src/assets/web-panel/assets/{index-DcPFB8qJ.js → index-Bx044qDj.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cd9OJhHG.js → index-C1GFfuqN.js} +1 -1
- package/src/assets/web-panel/assets/index-C3QX5tOl.js +1 -0
- package/src/assets/web-panel/assets/{index-B-Z8eFUJ.js → index-C66NpWy5.js} +1 -1
- package/src/assets/web-panel/assets/{index-BlT2VAEK.js → index-CDTvsX8t.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dsij_KsN.js → index-CGNklbP6.js} +1 -1
- package/src/assets/web-panel/assets/{index-C4gkzxkw.js → index-CHfLYwcW.js} +1 -1
- package/src/assets/web-panel/assets/{index-D6sm5-Xq.js → index-CNxg61YP.js} +1 -1
- package/src/assets/web-panel/assets/{index-C0yx-jtQ.js → index-CQlHFN_g.js} +1 -1
- package/src/assets/web-panel/assets/{index-CjTrRt13.js → index-CUEU48o1.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7WBt_4T.js → index-CWGax2QW.js} +1 -1
- package/src/assets/web-panel/assets/{index-IeiL9RKc.js → index-C_JzIXUq.js} +1 -1
- package/src/assets/web-panel/assets/{index-CnHH7bnD.js → index-Cf23wVMs.js} +1 -1
- package/src/assets/web-panel/assets/{index-BKJr-TZp.js → index-CmAInUkX.js} +1 -1
- package/src/assets/web-panel/assets/{index-CiECJi-Q.js → index-CmAubjDi.js} +1 -1
- package/src/assets/web-panel/assets/{index-BCnZyIMA.js → index-Co7oM1qr.js} +1 -1
- package/src/assets/web-panel/assets/{index-Drlnwr8F.js → index-CwPUZbMI.js} +1 -1
- package/src/assets/web-panel/assets/{index-9R6BxAr0.js → index-D1naNj4U.js} +1 -1
- package/src/assets/web-panel/assets/{index-BGqqJfL0.js → index-D5CsBShd.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bi46Xu4u.js → index-DBT3YeQ9.js} +1 -1
- package/src/assets/web-panel/assets/{index-DXXtGMUJ.js → index-DLdrHhML.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0PMlbMs.js → index-Dc77VR3H.js} +1 -1
- package/src/assets/web-panel/assets/{index-D0zcy54x.js → index-Dfv2lKu3.js} +1 -1
- package/src/assets/web-panel/assets/{index-BN6UPD2E.js → index-DiW0sDkz.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dxge-xWl.js → index-DpTHIRfZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CyOGN6a5.js → index-DqFXGzzC.js} +1 -1
- package/src/assets/web-panel/assets/{index-B9O9YyWE.js → index-XFe-1twF.js} +1 -1
- package/src/assets/web-panel/assets/{index-BHNYPO0b.js → index-p2HYn89m.js} +3 -3
- package/src/assets/web-panel/assets/{index-CVQMeiwH.js → index-pqfux8vZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-pPL66J85.js → index-rjzk9z1Q.js} +1 -1
- package/src/assets/web-panel/assets/{index-DoQA0-52.js → index-th2ihDc0.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5REnKt8.js → index-u2YVld9W.js} +1 -1
- package/src/assets/web-panel/assets/index-xYybvEic.js +1 -0
- package/src/assets/web-panel/assets/{initDefaultProps-BTL88of4.js → initDefaultProps-C3Djh9fa.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BUB2pXwB.js → motion-BzqFmbSe.js} +1 -1
- package/src/assets/web-panel/assets/{move-egCkkOMm.js → move-DJo_FFaW.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DAWhZC8c.js → mtc-parser-_tlTiBvk.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CvOxe_6d.js → omit-CB2ZyxUg.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DZUSLZ5Z.js → pickAttrs-DZwIFD4u.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BERxGNMY.js → placementArrow-DxZY0dgk.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DZuDfZ9n.js → responsiveObserve-CzzGt7GL.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DO756sgI.js → slide-BaIK52yz.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BRQlIz28.js → statusUtils-3-FHu9_M.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-DCSfdybl.js → styleChecker-BkRT68fK.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-LD8dWVve.js → useFlexGapSupport-DHYwKS-s.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BX9uW2LK.js → useFs-DVVUhV8p.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BPSlPuHU.js → usePersonalDataHub-CkrFKAzQ.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-BmOILC9V.js → vnode-BuBLFz0c.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-1iKowKGg.js → zoom-kpm6LtXU.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +3 -3
- package/src/commands/cowork.js +418 -41
- package/src/commands/permissions.js +240 -16
- package/src/commands/plugin.js +1293 -56
- package/src/commands/session-location.js +276 -0
- package/src/commands/session.js +2 -0
- package/src/data/changelog.json +28 -2
- package/src/gateways/ws/action-protocol.js +316 -17
- package/src/gateways/ws/message-dispatcher.js +30 -0
- package/src/gateways/ws/remote-session-protocol.js +565 -35
- package/src/gateways/ws/ws-agent-handler.js +12 -0
- package/src/gateways/ws/ws-approval-gate.js +5 -0
- package/src/gateways/ws/ws-server.js +510 -50
- package/src/harness/jsonl-session-store.js +341 -24
- package/src/harness/mcp-client.js +8 -1
- package/src/harness/remote-session-audit.js +2 -0
- package/src/harness/remote-session-crypto.js +929 -21
- package/src/harness/remote-session-registry.js +945 -24
- package/src/harness/session-list-index.js +233 -14
- package/src/lib/agent-authority.js +6 -0
- package/src/lib/auto-mode-config.js +98 -3
- package/src/lib/background-agent-keeper-client.js +248 -0
- package/src/lib/background-agent-keeper-protocol.js +291 -0
- package/src/lib/background-agent-supervisor.js +1357 -85
- package/src/lib/background-interaction-resolver.js +12 -0
- package/src/lib/background-session-transport.js +23 -6
- package/src/lib/background-turn-bootstrap-protocol.js +190 -0
- package/src/lib/cowork-workflow.js +1188 -76
- package/src/lib/delivery-production-adapter.js +38 -2
- package/src/lib/dynamic-workflow-facade.js +1736 -0
- package/src/lib/execution-location-contract.js +551 -0
- package/src/lib/execution-location-runtime.js +130 -0
- package/src/lib/ide-context.js +94 -6
- package/src/lib/mcp-stdio-package-materialization.js +166 -14
- package/src/lib/packer/pkg-config-generator.js +2 -0
- package/src/lib/permission-authority.js +77 -0
- package/src/lib/permission-side-effect-center.js +495 -0
- package/src/lib/plugin-runtime/install.js +514 -13
- package/src/lib/plugin-runtime/marketplace-artifact-readback.js +900 -0
- package/src/lib/plugin-runtime/marketplace-catalog.js +1181 -0
- package/src/lib/plugin-runtime/marketplace-impact.js +408 -0
- package/src/lib/plugin-runtime/marketplace-remote-artifacts.js +1567 -0
- package/src/lib/plugin-security.js +60 -3
- package/src/lib/process-execution-broker/index.js +1095 -57
- package/src/lib/process-execution-broker/linux-bwrap-descriptor-launch.js +375 -0
- package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +90 -16
- package/src/lib/process-execution-broker/linux-generic-bwrap.js +159 -18
- package/src/lib/process-execution-broker/macos-mcp-launcher-contract.js +278 -0
- package/src/lib/process-execution-broker/macos-mcp-launcher-protocol.json +23 -0
- package/src/lib/process-execution-broker/macos-mcp-launcher.c +1497 -0
- package/src/lib/process-execution-broker/mcp-fd-entry-bootstrap.js +37 -0
- package/src/lib/process-execution-broker/platform-sandbox.js +2330 -279
- package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
- package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
- package/src/lib/process-execution-broker/windows-sandbox.cs +50 -4
- package/src/lib/public-ide-capability-manifest.js +3 -0
- package/src/lib/remote-approval-bridge.js +777 -34
- package/src/lib/remote-control.js +2 -0
- package/src/lib/remote-membership-authority.js +632 -0
- package/src/lib/remote-membership-coordinator.js +2973 -0
- package/src/lib/remote-membership-host-store.js +1799 -0
- package/src/lib/runtime-provenance-ledger.js +171 -46
- package/src/lib/scoped-permission-store.js +369 -0
- package/src/lib/session-anti-rollback-anchor.js +262 -5
- package/src/lib/shell-approval.js +169 -6
- package/src/lib/sub-agent-context.js +4 -0
- package/src/lib/with-file-lock.js +73 -38
- package/src/lib/workflow-definition-contract.js +149 -0
- package/src/repl/agent-repl.js +111 -36
- package/src/repl/chat-repl.js +2 -0
- package/src/repl/clipboard-image.js +735 -16
- package/src/repl/ide-status.js +1 -1
- package/src/repl/prompt-interactions.js +59 -6
- package/src/repl/remote-approval.js +29 -7
- package/src/runtime/agent-core.js +1182 -155
- package/src/runtime/headless-runner.js +52 -30
- package/src/runtime/headless-stream.js +51 -28
- package/src/workers/background-agent-keeper.js +689 -0
- package/src/workers/background-agent-worker.js +365 -13
- package/src/workers/background-turn-bootstrap.js +170 -0
- package/src/assets/web-panel/assets/MarkdownRenderer-yySN5YNM.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-Bb1O3Ofr.js +0 -1
- package/src/assets/web-panel/assets/Projects-CMolGhae.js +0 -1
- package/src/assets/web-panel/assets/RemoteSession-Biyn2-Ro.js +0 -5
- package/src/assets/web-panel/assets/devWarning-S1ld2LwU.js +0 -1
- package/src/assets/web-panel/assets/index-Drz6yq0m.js +0 -1
- package/src/assets/web-panel/assets/index-uWiUs7S_.js +0 -1
|
@@ -21,6 +21,12 @@ import crypto from "node:crypto";
|
|
|
21
21
|
import fs from "node:fs";
|
|
22
22
|
import os from "node:os";
|
|
23
23
|
import path from "node:path";
|
|
24
|
+
import {
|
|
25
|
+
buildLinuxBwrapDescriptorScrubbedLaunch,
|
|
26
|
+
LINUX_BWRAP_DESCRIPTOR_SCRUBBER_PATH,
|
|
27
|
+
linuxBwrapDescriptorScrubberPolicyBinding,
|
|
28
|
+
parseLinuxBwrapDescriptorScrubbedLaunch,
|
|
29
|
+
} from "./linux-bwrap-descriptor-launch.js";
|
|
24
30
|
|
|
25
31
|
export const LINUX_GENERIC_BWRAP_BACKEND = "linux-bwrap-workspace";
|
|
26
32
|
export const LINUX_GENERIC_CONTRACT_KIND = "strict-workspace-command";
|
|
@@ -86,6 +92,8 @@ const ENV_DENYLIST = new Set([
|
|
|
86
92
|
"LD_DEBUG",
|
|
87
93
|
"LD_LIBRARY_PATH",
|
|
88
94
|
"LD_PRELOAD",
|
|
95
|
+
"NODE_CHANNEL_FD",
|
|
96
|
+
"NODE_CHANNEL_SERIALIZATION_MODE",
|
|
89
97
|
"NODE_OPTIONS",
|
|
90
98
|
"NODE_PATH",
|
|
91
99
|
"PERL5OPT",
|
|
@@ -165,12 +173,18 @@ function assertString(value, label) {
|
|
|
165
173
|
}
|
|
166
174
|
|
|
167
175
|
function normalizeArgs(args) {
|
|
168
|
-
if (!Array.isArray(args)) {
|
|
176
|
+
if (!Array.isArray(args) || Object.getPrototypeOf(args) !== Array.prototype) {
|
|
169
177
|
throw new TypeError("args must be an array");
|
|
170
178
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
179
|
+
const normalized = [];
|
|
180
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
181
|
+
const descriptor = Object.getOwnPropertyDescriptor(args, index);
|
|
182
|
+
if (!descriptor || !("value" in descriptor)) {
|
|
183
|
+
throw new TypeError(`args[${index}] must be an own data property`);
|
|
184
|
+
}
|
|
185
|
+
normalized.push(assertString(descriptor.value, `args[${index}]`));
|
|
186
|
+
}
|
|
187
|
+
return Object.freeze(normalized);
|
|
174
188
|
}
|
|
175
189
|
|
|
176
190
|
function normalizeBoundaries(boundaries) {
|
|
@@ -209,7 +223,19 @@ function normalizeStdio(stdio) {
|
|
|
209
223
|
} else if (stdio === "ignore") {
|
|
210
224
|
entries = ["ignore", "ignore", "ignore"];
|
|
211
225
|
} else if (Array.isArray(stdio)) {
|
|
212
|
-
|
|
226
|
+
if (Object.getPrototypeOf(stdio) !== Array.prototype) {
|
|
227
|
+
throw new TypeError("stdio must use the canonical array prototype");
|
|
228
|
+
}
|
|
229
|
+
entries = [];
|
|
230
|
+
for (let index = 0; index < stdio.length; index += 1) {
|
|
231
|
+
const descriptor = Object.getOwnPropertyDescriptor(stdio, index);
|
|
232
|
+
if (!descriptor || !("value" in descriptor)) {
|
|
233
|
+
throw new TypeError(
|
|
234
|
+
`strong Linux workspace sandbox rejects sparse/accessor stdio at fd ${index}`,
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
entries.push(descriptor.value);
|
|
238
|
+
}
|
|
213
239
|
while (entries.length < 3) entries.push(undefined);
|
|
214
240
|
} else {
|
|
215
241
|
throw new TypeError(
|
|
@@ -220,9 +246,17 @@ function normalizeStdio(stdio) {
|
|
|
220
246
|
let ipcCount = 0;
|
|
221
247
|
const normalized = entries.map((entry, index) => {
|
|
222
248
|
if (entry === undefined || entry === null) {
|
|
223
|
-
|
|
249
|
+
if (index < 3) return "pipe";
|
|
250
|
+
throw new TypeError(
|
|
251
|
+
`strong Linux workspace sandbox rejects non-overwriting stdio at fd ${index}`,
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
if (entry === "pipe" || (entry === "ignore" && index < 3)) return entry;
|
|
255
|
+
if (entry === "ignore") {
|
|
256
|
+
throw new TypeError(
|
|
257
|
+
`strong Linux workspace sandbox rejects non-overwriting stdio at fd ${index}`,
|
|
258
|
+
);
|
|
224
259
|
}
|
|
225
|
-
if (entry === "pipe" || entry === "ignore") return entry;
|
|
226
260
|
if (entry === "ipc" && index >= 3) {
|
|
227
261
|
ipcCount += 1;
|
|
228
262
|
return entry;
|
|
@@ -337,6 +371,9 @@ export function issueLinuxGenericSandboxExecutionContract(
|
|
|
337
371
|
throw new TypeError("strong Linux workspace PTY cannot be synchronous");
|
|
338
372
|
}
|
|
339
373
|
const stdio = normalizeStdio(spec?.stdio);
|
|
374
|
+
if (sync && stdio.includes("ipc")) {
|
|
375
|
+
throw new TypeError("strong Linux workspace IPC cannot be synchronous");
|
|
376
|
+
}
|
|
340
377
|
const requiredBoundaries = normalizeBoundaries(spec?.requiredBoundaries);
|
|
341
378
|
if (
|
|
342
379
|
spec?.detached === true ||
|
|
@@ -611,6 +648,32 @@ function validateResourceContract(resources, issued) {
|
|
|
611
648
|
) {
|
|
612
649
|
throw new Error("bubblewrap supervisor is not root-owned and pinned");
|
|
613
650
|
}
|
|
651
|
+
if (
|
|
652
|
+
resources.descriptorScrubber?.identity?.realPath !==
|
|
653
|
+
LINUX_BWRAP_DESCRIPTOR_SCRUBBER_PATH ||
|
|
654
|
+
!validateRootOwnedIdentity(resources.descriptorScrubber?.identity, {
|
|
655
|
+
directory: false,
|
|
656
|
+
}) ||
|
|
657
|
+
(Number(resources.descriptorScrubber.identity.mode) & 0o111) === 0 ||
|
|
658
|
+
!/^[a-f0-9]{64}$/.test(resources.descriptorScrubber?.sha256 || "") ||
|
|
659
|
+
!Number.isSafeInteger(resources.descriptorScrubber?.bytes) ||
|
|
660
|
+
resources.descriptorScrubber.bytes <= 0 ||
|
|
661
|
+
!Number.isFinite(resources.descriptorScrubber?.mtimeMs) ||
|
|
662
|
+
!Number.isInteger(resources.descriptorScrubber?.probeFd) ||
|
|
663
|
+
!Number.isInteger(resources.descriptorScrubber?.finalFd)
|
|
664
|
+
) {
|
|
665
|
+
throw new Error("descriptor scrubber is not root-owned and pinned");
|
|
666
|
+
}
|
|
667
|
+
const descriptorScrubber = {
|
|
668
|
+
path: resources.descriptorScrubber.identity.realPath,
|
|
669
|
+
fileId: resources.descriptorScrubber.identity.fileId,
|
|
670
|
+
sha256: resources.descriptorScrubber.sha256,
|
|
671
|
+
bytes: resources.descriptorScrubber.bytes,
|
|
672
|
+
mtimeMs: resources.descriptorScrubber.mtimeMs,
|
|
673
|
+
mode: Number(resources.descriptorScrubber.identity.mode),
|
|
674
|
+
uid: Number(resources.descriptorScrubber.identity.uid),
|
|
675
|
+
gid: Number(resources.descriptorScrubber.identity.gid),
|
|
676
|
+
};
|
|
614
677
|
let ptyLauncher = null;
|
|
615
678
|
if (issued.pty) {
|
|
616
679
|
if (
|
|
@@ -713,6 +776,7 @@ function validateResourceContract(resources, issued) {
|
|
|
713
776
|
sha256: resources.supervisor.sha256,
|
|
714
777
|
bytes: resources.supervisor.bytes,
|
|
715
778
|
},
|
|
779
|
+
descriptorScrubber,
|
|
716
780
|
ptyLauncher,
|
|
717
781
|
system,
|
|
718
782
|
symlinks,
|
|
@@ -732,6 +796,8 @@ function sanitizedEnvironment(environment, stdio) {
|
|
|
732
796
|
if (
|
|
733
797
|
!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key) ||
|
|
734
798
|
ENV_DENYLIST.has(key) ||
|
|
799
|
+
key.startsWith("LD_") ||
|
|
800
|
+
key.startsWith("BASH_FUNC_") ||
|
|
735
801
|
value === undefined ||
|
|
736
802
|
value === null ||
|
|
737
803
|
String(value).includes("\0")
|
|
@@ -840,6 +906,11 @@ function descriptorLayout(stdio, resources, validated, workspaceRoot, phase) {
|
|
|
840
906
|
fd: resources.seccomp[`${phase}Fd`],
|
|
841
907
|
destination: null,
|
|
842
908
|
},
|
|
909
|
+
{
|
|
910
|
+
kind: "descriptorScrubber",
|
|
911
|
+
fd: resources.descriptorScrubber[`${phase}Fd`],
|
|
912
|
+
destination: null,
|
|
913
|
+
},
|
|
843
914
|
];
|
|
844
915
|
const seen = new Set();
|
|
845
916
|
for (const descriptor of descriptors) {
|
|
@@ -988,12 +1059,14 @@ function policyBinding({
|
|
|
988
1059
|
environment,
|
|
989
1060
|
requiredBoundaries,
|
|
990
1061
|
policyArgs,
|
|
1062
|
+
descriptorScrubber,
|
|
991
1063
|
}) {
|
|
992
1064
|
return {
|
|
993
1065
|
version: PLAN_VERSION,
|
|
994
1066
|
backend: LINUX_GENERIC_BWRAP_BACKEND,
|
|
995
1067
|
contractDigest: issued.contractDigest,
|
|
996
1068
|
supervisor: validated.supervisor,
|
|
1069
|
+
descriptorScrubber,
|
|
997
1070
|
workspace: {
|
|
998
1071
|
root: issued.workspaceRoot,
|
|
999
1072
|
cwd: issued.workingDirectory,
|
|
@@ -1144,6 +1217,23 @@ export function planLinuxGenericBubblewrap(
|
|
|
1144
1217
|
environment: targetEnvironment,
|
|
1145
1218
|
requiredBoundaries,
|
|
1146
1219
|
policyArgs,
|
|
1220
|
+
descriptorScrubber: linuxBwrapDescriptorScrubberPolicyBinding(
|
|
1221
|
+
validated.descriptorScrubber,
|
|
1222
|
+
{
|
|
1223
|
+
scrubberChildFd: finalDescriptors.find(
|
|
1224
|
+
(entry) => entry.kind === "descriptorScrubber",
|
|
1225
|
+
).childFd,
|
|
1226
|
+
preservedMaxFd:
|
|
1227
|
+
finalDescriptors.find((entry) => entry.kind === "descriptorScrubber")
|
|
1228
|
+
.childFd - 1,
|
|
1229
|
+
activeStdioThrough: issued.stdio.length - 1,
|
|
1230
|
+
nodeIpcChildFd:
|
|
1231
|
+
issued.stdio.indexOf("ipc") >= 3 ? issued.stdio.indexOf("ipc") : null,
|
|
1232
|
+
executableChildFd: finalDescriptors.find(
|
|
1233
|
+
(entry) => entry.kind === "supervisor",
|
|
1234
|
+
).childFd,
|
|
1235
|
+
},
|
|
1236
|
+
),
|
|
1147
1237
|
});
|
|
1148
1238
|
const policyDigest = sha256(stableJson(binding));
|
|
1149
1239
|
const probePolicyArgs = buildPolicyArgs({
|
|
@@ -1152,9 +1242,6 @@ export function planLinuxGenericBubblewrap(
|
|
|
1152
1242
|
descriptors: probeDescriptors,
|
|
1153
1243
|
environment: targetEnvironment,
|
|
1154
1244
|
});
|
|
1155
|
-
const probeCommand = `/proc/self/fd/${
|
|
1156
|
-
probeDescriptors.find((entry) => entry.kind === "supervisor").childFd
|
|
1157
|
-
}`;
|
|
1158
1245
|
const probeOptions = {
|
|
1159
1246
|
cwd: "/",
|
|
1160
1247
|
shell: false,
|
|
@@ -1162,19 +1249,31 @@ export function planLinuxGenericBubblewrap(
|
|
|
1162
1249
|
timeout: 10_000,
|
|
1163
1250
|
stdio: [
|
|
1164
1251
|
...issued.stdio.map((_, index) =>
|
|
1165
|
-
index === 1 || index === 2 ? "pipe" : "ignore",
|
|
1252
|
+
index === 1 || index === 2 || index >= 3 ? "pipe" : "ignore",
|
|
1166
1253
|
),
|
|
1167
1254
|
...probeDescriptors.map((descriptor) => descriptor.fd),
|
|
1168
1255
|
],
|
|
1169
1256
|
env: { PATH: "/usr/bin:/bin", LANG: "C", LC_ALL: "C" },
|
|
1170
1257
|
};
|
|
1258
|
+
const probeLaunch = buildLinuxBwrapDescriptorScrubbedLaunch({
|
|
1259
|
+
scrubberChildFd: probeDescriptors.find(
|
|
1260
|
+
(entry) => entry.kind === "descriptorScrubber",
|
|
1261
|
+
).childFd,
|
|
1262
|
+
preservedMaxFd:
|
|
1263
|
+
probeDescriptors.find((entry) => entry.kind === "descriptorScrubber")
|
|
1264
|
+
.childFd - 1,
|
|
1265
|
+
executableChildFd: probeDescriptors.find(
|
|
1266
|
+
(entry) => entry.kind === "supervisor",
|
|
1267
|
+
).childFd,
|
|
1268
|
+
executableArgs: probePolicyArgs,
|
|
1269
|
+
});
|
|
1171
1270
|
let probeResult;
|
|
1172
1271
|
try {
|
|
1173
1272
|
probeResult =
|
|
1174
1273
|
typeof probe === "function"
|
|
1175
1274
|
? probe({
|
|
1176
|
-
command:
|
|
1177
|
-
args:
|
|
1275
|
+
command: probeLaunch.command,
|
|
1276
|
+
args: probeLaunch.args,
|
|
1178
1277
|
options: probeOptions,
|
|
1179
1278
|
policyDigest,
|
|
1180
1279
|
contractDigest: issued.contractDigest,
|
|
@@ -1237,18 +1336,28 @@ export function planLinuxGenericBubblewrap(
|
|
|
1237
1336
|
const ptyLauncher = finalDescriptors.find(
|
|
1238
1337
|
(entry) => entry.kind === "ptyLauncher",
|
|
1239
1338
|
);
|
|
1240
|
-
const
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
: supervisorCommand;
|
|
1339
|
+
const descriptorScrubber = finalDescriptors.find(
|
|
1340
|
+
(entry) => entry.kind === "descriptorScrubber",
|
|
1341
|
+
);
|
|
1244
1342
|
const bwrapArgs = [
|
|
1245
1343
|
...policyArgs,
|
|
1246
1344
|
"--",
|
|
1247
1345
|
validated.target.resolvedCommand,
|
|
1248
1346
|
...validated.target.args,
|
|
1249
1347
|
];
|
|
1348
|
+
const scrubbedLaunch = buildLinuxBwrapDescriptorScrubbedLaunch({
|
|
1349
|
+
scrubberChildFd: descriptorScrubber.childFd,
|
|
1350
|
+
preservedMaxFd: descriptorScrubber.childFd - 1,
|
|
1351
|
+
executableChildFd: supervisor.childFd,
|
|
1352
|
+
executableArgs: bwrapArgs,
|
|
1353
|
+
});
|
|
1354
|
+
const command = issued.pty
|
|
1355
|
+
? `/proc/self/fd/${ptyLauncher.childFd}`
|
|
1356
|
+
: scrubbedLaunch.command;
|
|
1250
1357
|
const args = Object.freeze(
|
|
1251
|
-
issued.pty
|
|
1358
|
+
issued.pty
|
|
1359
|
+
? ["--ctty", scrubbedLaunch.command, ...scrubbedLaunch.args]
|
|
1360
|
+
: [...scrubbedLaunch.args],
|
|
1252
1361
|
);
|
|
1253
1362
|
const options = Object.freeze({
|
|
1254
1363
|
...passthroughSpawnOptions(spawnOptions),
|
|
@@ -1298,6 +1407,7 @@ export function planLinuxGenericBubblewrap(
|
|
|
1298
1407
|
mountTopologyAtomic: false,
|
|
1299
1408
|
contractDigest: issued.contractDigest,
|
|
1300
1409
|
policyDigest,
|
|
1410
|
+
descriptorScrubber: binding.descriptorScrubber,
|
|
1301
1411
|
mountTopologyDigest: validated.workspaceMountTopology.digest,
|
|
1302
1412
|
sourceMountSetDigest:
|
|
1303
1413
|
validated.workspaceMountTopology.sourceMountSetDigest,
|
|
@@ -1384,8 +1494,39 @@ export function planLinuxGenericBubblewrap(
|
|
|
1384
1494
|
}
|
|
1385
1495
|
|
|
1386
1496
|
export function verifyLinuxGenericBubblewrapPlan(plan) {
|
|
1497
|
+
const descriptorScrubber = plan?.runtimeProbe?.descriptorScrubber;
|
|
1498
|
+
const scrubbedLaunch = plan?.ptyPolicy
|
|
1499
|
+
? parseLinuxBwrapDescriptorScrubbedLaunch(
|
|
1500
|
+
plan.args?.[1],
|
|
1501
|
+
plan.args?.slice(2),
|
|
1502
|
+
plan.options,
|
|
1503
|
+
{ activeStdioThrough: descriptorScrubber?.activeStdioThrough },
|
|
1504
|
+
)
|
|
1505
|
+
: parseLinuxBwrapDescriptorScrubbedLaunch(
|
|
1506
|
+
plan?.command,
|
|
1507
|
+
plan?.args,
|
|
1508
|
+
plan?.options,
|
|
1509
|
+
{ activeStdioThrough: descriptorScrubber?.activeStdioThrough },
|
|
1510
|
+
);
|
|
1387
1511
|
return (
|
|
1388
1512
|
plannedPolicies.get(plan) === plan?.policyDigest &&
|
|
1513
|
+
scrubbedLaunch !== null &&
|
|
1514
|
+
descriptorScrubber?.scrubberChildFd === scrubbedLaunch.scrubberChildFd &&
|
|
1515
|
+
descriptorScrubber?.preservedMaxFd === scrubbedLaunch.preservedMaxFd &&
|
|
1516
|
+
descriptorScrubber?.activeStdioThrough ===
|
|
1517
|
+
scrubbedLaunch.activeStdioThrough &&
|
|
1518
|
+
descriptorScrubber?.nodeIpcChildFd === scrubbedLaunch.nodeIpcChildFd &&
|
|
1519
|
+
descriptorScrubber?.nodeIpcSerializationMode ===
|
|
1520
|
+
(scrubbedLaunch.nodeIpcChildFd === null ? null : "json") &&
|
|
1521
|
+
descriptorScrubber?.nodeRuntimeEnvironmentInjection ===
|
|
1522
|
+
(scrubbedLaunch.nodeIpcChildFd === null
|
|
1523
|
+
? "none"
|
|
1524
|
+
: "node-child-process-exact-ipc-v1") &&
|
|
1525
|
+
descriptorScrubber?.executableChildFd ===
|
|
1526
|
+
scrubbedLaunch.executableChildFd &&
|
|
1527
|
+
Object.isFrozen(descriptorScrubber) &&
|
|
1528
|
+
Object.isFrozen(descriptorScrubber.executableIdentity) &&
|
|
1529
|
+
Object.isFrozen(descriptorScrubber.executableIdentity.fileId) &&
|
|
1389
1530
|
Object.isFrozen(plan) &&
|
|
1390
1531
|
Object.isFrozen(plan.args) &&
|
|
1391
1532
|
Object.isFrozen(plan.options) &&
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import {
|
|
6
|
+
MCP_STDIO_MACOS_GATED_ENTRY_BOOTSTRAP,
|
|
7
|
+
MCP_STDIO_MACOS_GATED_ENTRY_BOOTSTRAP_SHA256,
|
|
8
|
+
} from "./mcp-fd-entry-bootstrap.js";
|
|
9
|
+
|
|
10
|
+
const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const PROTOCOL_PATH = path.join(MODULE_DIR, "macos-mcp-launcher-protocol.json");
|
|
12
|
+
const SOURCE_PATH = path.join(MODULE_DIR, "macos-mcp-launcher.c");
|
|
13
|
+
|
|
14
|
+
export function isMacosMcpLauncherPackageVersion(value) {
|
|
15
|
+
return /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/u.test(value || "");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function sha256(bytes) {
|
|
19
|
+
return crypto.createHash("sha256").update(bytes).digest("hex");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function strictObjectKeys(value, expected, label) {
|
|
23
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
24
|
+
throw new TypeError(`${label} must be an object`);
|
|
25
|
+
}
|
|
26
|
+
const actual = Object.keys(value).sort();
|
|
27
|
+
const wanted = [...expected].sort();
|
|
28
|
+
if (JSON.stringify(actual) !== JSON.stringify(wanted)) {
|
|
29
|
+
throw new Error(`${label} fields do not match the fixed contract`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function loadProtocolInputs() {
|
|
34
|
+
const sourceBytes = fs.readFileSync(SOURCE_PATH);
|
|
35
|
+
const protocolBytes = fs.readFileSync(PROTOCOL_PATH);
|
|
36
|
+
const protocol = JSON.parse(protocolBytes.toString("utf8"));
|
|
37
|
+
strictObjectKeys(
|
|
38
|
+
protocol,
|
|
39
|
+
[
|
|
40
|
+
"schema",
|
|
41
|
+
"protocolVersion",
|
|
42
|
+
"backend",
|
|
43
|
+
"packageIdentifier",
|
|
44
|
+
"helperInstallPath",
|
|
45
|
+
"installContractPath",
|
|
46
|
+
"snapshotRoot",
|
|
47
|
+
"snapshotLockName",
|
|
48
|
+
"sandboxExecutable",
|
|
49
|
+
"runtimeFd",
|
|
50
|
+
"entryFd",
|
|
51
|
+
"capsuleRootFd",
|
|
52
|
+
"gateFd",
|
|
53
|
+
"readyFd",
|
|
54
|
+
"callerLifelineFd",
|
|
55
|
+
"maximumRuntimeBytes",
|
|
56
|
+
"maximumEntryBytes",
|
|
57
|
+
"maximumPassthroughArgs",
|
|
58
|
+
"maximumStaleSnapshots",
|
|
59
|
+
"readyTimeoutMs",
|
|
60
|
+
"profileTemplateVersion",
|
|
61
|
+
],
|
|
62
|
+
"macOS MCP launcher protocol",
|
|
63
|
+
);
|
|
64
|
+
if (
|
|
65
|
+
protocol.schema !== "chainlesschain.macos-mcp-launcher-protocol.v1" ||
|
|
66
|
+
protocol.protocolVersion !== 1 ||
|
|
67
|
+
protocol.backend !== "macos-signed-root-fd-launcher" ||
|
|
68
|
+
protocol.packageIdentifier !== "com.chainlesschain.cli.mcp-launcher.pkg" ||
|
|
69
|
+
protocol.helperInstallPath !==
|
|
70
|
+
"/Library/PrivilegedHelperTools/com.chainlesschain.cli.mcp-launcher" ||
|
|
71
|
+
protocol.installContractPath !==
|
|
72
|
+
"/Library/PrivilegedHelperTools/com.chainlesschain.cli.mcp-launcher.json" ||
|
|
73
|
+
protocol.snapshotRoot !==
|
|
74
|
+
"/Library/Application Support/ChainlessChain/McpLauncher/runtime" ||
|
|
75
|
+
protocol.snapshotLockName !== "launcher.lock" ||
|
|
76
|
+
protocol.sandboxExecutable !== "/usr/bin/sandbox-exec" ||
|
|
77
|
+
protocol.runtimeFd !== 3 ||
|
|
78
|
+
protocol.entryFd !== 4 ||
|
|
79
|
+
protocol.capsuleRootFd !== 5 ||
|
|
80
|
+
protocol.gateFd !== 6 ||
|
|
81
|
+
protocol.readyFd !== 7 ||
|
|
82
|
+
protocol.callerLifelineFd !== 8 ||
|
|
83
|
+
protocol.maximumRuntimeBytes !== 256 * 1024 * 1024 ||
|
|
84
|
+
protocol.maximumEntryBytes !== 64 * 1024 * 1024 ||
|
|
85
|
+
protocol.maximumPassthroughArgs !== 128 ||
|
|
86
|
+
protocol.maximumStaleSnapshots !== 8 ||
|
|
87
|
+
protocol.readyTimeoutMs !== 15_000 ||
|
|
88
|
+
protocol.profileTemplateVersion !== 1
|
|
89
|
+
) {
|
|
90
|
+
throw new Error("macOS MCP launcher protocol contains unsupported values");
|
|
91
|
+
}
|
|
92
|
+
return Object.freeze({
|
|
93
|
+
sourcePath: SOURCE_PATH,
|
|
94
|
+
sourceBytes,
|
|
95
|
+
sourceSha256: sha256(sourceBytes),
|
|
96
|
+
protocolPath: PROTOCOL_PATH,
|
|
97
|
+
protocolBytes,
|
|
98
|
+
protocol,
|
|
99
|
+
protocolSha256: sha256(protocolBytes),
|
|
100
|
+
gateBootstrap: MCP_STDIO_MACOS_GATED_ENTRY_BOOTSTRAP,
|
|
101
|
+
gateBootstrapSha256: MCP_STDIO_MACOS_GATED_ENTRY_BOOTSTRAP_SHA256,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export const MACOS_MCP_LAUNCHER_INPUTS = loadProtocolInputs();
|
|
106
|
+
export const MACOS_MCP_LAUNCHER_INSTALL_CONTRACT_SCHEMA =
|
|
107
|
+
"chainlesschain.macos-mcp-launcher-install.v1";
|
|
108
|
+
|
|
109
|
+
function designatedRequirementMatchesReleaseIdentity(contract) {
|
|
110
|
+
const requirement = contract.designatedRequirement;
|
|
111
|
+
const team = contract.teamIdentifier;
|
|
112
|
+
return (
|
|
113
|
+
typeof requirement === "string" &&
|
|
114
|
+
requirement.length <= 4096 &&
|
|
115
|
+
!requirement.includes("\0") &&
|
|
116
|
+
!/[\r\n]/u.test(requirement) &&
|
|
117
|
+
!/\bor\b/iu.test(requirement) &&
|
|
118
|
+
requirement.includes('identifier "com.chainlesschain.cli.mcp-launcher"') &&
|
|
119
|
+
requirement.includes("anchor apple generic") &&
|
|
120
|
+
requirement.includes(
|
|
121
|
+
"certificate 1[field.1.2.840.113635.100.6.2.6] exists",
|
|
122
|
+
) &&
|
|
123
|
+
requirement.includes(
|
|
124
|
+
"certificate leaf[field.1.2.840.113635.100.6.1.13] exists",
|
|
125
|
+
) &&
|
|
126
|
+
requirement.includes(`certificate leaf[subject.OU] = ${team}`)
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function verifyMacosMcpLauncherInstallContract(
|
|
131
|
+
contract,
|
|
132
|
+
inputs = MACOS_MCP_LAUNCHER_INPUTS,
|
|
133
|
+
) {
|
|
134
|
+
strictObjectKeys(
|
|
135
|
+
contract,
|
|
136
|
+
[
|
|
137
|
+
"schema",
|
|
138
|
+
"protocolVersion",
|
|
139
|
+
"protocolSha256",
|
|
140
|
+
"sourceSha256",
|
|
141
|
+
"gateBootstrapSha256",
|
|
142
|
+
"helperSha256",
|
|
143
|
+
"helperBytes",
|
|
144
|
+
"packageIdentifier",
|
|
145
|
+
"packageVersion",
|
|
146
|
+
"helperInstallPath",
|
|
147
|
+
"installContractPath",
|
|
148
|
+
"snapshotRoot",
|
|
149
|
+
"snapshotLockName",
|
|
150
|
+
"sandboxExecutable",
|
|
151
|
+
"ownerUid",
|
|
152
|
+
"ownerGid",
|
|
153
|
+
"helperMode",
|
|
154
|
+
"contractMode",
|
|
155
|
+
"snapshotRootMode",
|
|
156
|
+
"snapshotLockMode",
|
|
157
|
+
"snapshotLockMechanism",
|
|
158
|
+
"signingIdentifier",
|
|
159
|
+
"teamIdentifier",
|
|
160
|
+
"designatedRequirement",
|
|
161
|
+
"hardenedRuntimeRequired",
|
|
162
|
+
"notarizedPackageRequired",
|
|
163
|
+
"rootInstallRequired",
|
|
164
|
+
"runtimeSnapshotMechanism",
|
|
165
|
+
"entrySnapshotMechanism",
|
|
166
|
+
"targetDescriptorMechanism",
|
|
167
|
+
"callerLifelineFd",
|
|
168
|
+
"globalLaunchSerialization",
|
|
169
|
+
"maximumStaleSnapshots",
|
|
170
|
+
"sandboxExecLiveGateRequired",
|
|
171
|
+
"parentDeathLiveGateRequired",
|
|
172
|
+
"inPlaceOverwriteLiveGateRequired",
|
|
173
|
+
"signalFloodLiveGateRequired",
|
|
174
|
+
"snapshotLockUpgradeLiveGateRequired",
|
|
175
|
+
],
|
|
176
|
+
"macOS MCP launcher install contract",
|
|
177
|
+
);
|
|
178
|
+
if (
|
|
179
|
+
contract.schema !== MACOS_MCP_LAUNCHER_INSTALL_CONTRACT_SCHEMA ||
|
|
180
|
+
contract.protocolVersion !== 1 ||
|
|
181
|
+
contract.protocolSha256 !== inputs.protocolSha256 ||
|
|
182
|
+
contract.sourceSha256 !== inputs.sourceSha256 ||
|
|
183
|
+
contract.gateBootstrapSha256 !== inputs.gateBootstrapSha256 ||
|
|
184
|
+
!/^[a-f0-9]{64}$/u.test(contract.helperSha256 || "") ||
|
|
185
|
+
!Number.isSafeInteger(contract.helperBytes) ||
|
|
186
|
+
contract.helperBytes <= 0 ||
|
|
187
|
+
contract.helperBytes > 16 * 1024 * 1024 ||
|
|
188
|
+
contract.packageIdentifier !== inputs.protocol.packageIdentifier ||
|
|
189
|
+
!isMacosMcpLauncherPackageVersion(contract.packageVersion) ||
|
|
190
|
+
contract.helperInstallPath !== inputs.protocol.helperInstallPath ||
|
|
191
|
+
contract.installContractPath !== inputs.protocol.installContractPath ||
|
|
192
|
+
contract.snapshotRoot !== inputs.protocol.snapshotRoot ||
|
|
193
|
+
contract.snapshotLockName !== inputs.protocol.snapshotLockName ||
|
|
194
|
+
contract.sandboxExecutable !== inputs.protocol.sandboxExecutable ||
|
|
195
|
+
contract.ownerUid !== 0 ||
|
|
196
|
+
contract.ownerGid !== 0 ||
|
|
197
|
+
contract.helperMode !== "4555" ||
|
|
198
|
+
contract.contractMode !== "0444" ||
|
|
199
|
+
contract.snapshotRootMode !== "0711" ||
|
|
200
|
+
contract.snapshotLockMode !== "0600" ||
|
|
201
|
+
contract.snapshotLockMechanism !==
|
|
202
|
+
"root-helper-openat-o_excl-preserve-inode-across-upgrade-v1" ||
|
|
203
|
+
contract.signingIdentifier !== "com.chainlesschain.cli.mcp-launcher" ||
|
|
204
|
+
!/^[A-Z0-9]{10}$/u.test(contract.teamIdentifier || "") ||
|
|
205
|
+
!designatedRequirementMatchesReleaseIdentity(contract) ||
|
|
206
|
+
contract.hardenedRuntimeRequired !== true ||
|
|
207
|
+
contract.notarizedPackageRequired !== true ||
|
|
208
|
+
contract.rootInstallRequired !== true ||
|
|
209
|
+
contract.runtimeSnapshotMechanism !==
|
|
210
|
+
"root-copy-hash-protected-path-ready-unlink-v1" ||
|
|
211
|
+
contract.entrySnapshotMechanism !==
|
|
212
|
+
"root-copy-hash-readonly-reopen-unlink-fsync-fd4-v1" ||
|
|
213
|
+
contract.targetDescriptorMechanism !==
|
|
214
|
+
"stdio-fd3-null-fd4-entry-fd5-null-fd6-gate-fd7-ready-bootstrap-close-v1" ||
|
|
215
|
+
contract.callerLifelineFd !== inputs.protocol.callerLifelineFd ||
|
|
216
|
+
contract.globalLaunchSerialization !== true ||
|
|
217
|
+
contract.maximumStaleSnapshots !== inputs.protocol.maximumStaleSnapshots ||
|
|
218
|
+
contract.sandboxExecLiveGateRequired !== true ||
|
|
219
|
+
contract.parentDeathLiveGateRequired !== true ||
|
|
220
|
+
contract.inPlaceOverwriteLiveGateRequired !== true ||
|
|
221
|
+
contract.signalFloodLiveGateRequired !== true ||
|
|
222
|
+
contract.snapshotLockUpgradeLiveGateRequired !== true
|
|
223
|
+
) {
|
|
224
|
+
throw new Error("macOS MCP launcher install contract is invalid");
|
|
225
|
+
}
|
|
226
|
+
return contract;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function seatbeltLiteral(value) {
|
|
230
|
+
const text = String(value);
|
|
231
|
+
if (
|
|
232
|
+
[...text].some((character) => {
|
|
233
|
+
const codePoint = character.codePointAt(0);
|
|
234
|
+
return codePoint <= 0x1f || codePoint === 0x7f;
|
|
235
|
+
})
|
|
236
|
+
) {
|
|
237
|
+
throw new Error("macOS MCP launcher path contains a control character");
|
|
238
|
+
}
|
|
239
|
+
return text.replace(/\\/gu, "\\\\").replace(/"/gu, '\\"');
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** Must remain byte-for-byte equivalent to build_fixed_profile() in C. */
|
|
243
|
+
export function generateMacosMcpLauncherSeatbeltProfile({
|
|
244
|
+
snapshotPath,
|
|
245
|
+
capsulePath,
|
|
246
|
+
}) {
|
|
247
|
+
const snapshot = seatbeltLiteral(snapshotPath);
|
|
248
|
+
const capsule = seatbeltLiteral(capsulePath);
|
|
249
|
+
return [
|
|
250
|
+
"(version 1)",
|
|
251
|
+
"(deny default)",
|
|
252
|
+
'(import "system.sb")',
|
|
253
|
+
"(allow signal (target self))",
|
|
254
|
+
"(allow sysctl-read)",
|
|
255
|
+
"(allow mach-lookup)",
|
|
256
|
+
"(deny network*)",
|
|
257
|
+
"(deny process-fork)",
|
|
258
|
+
`(allow process-exec (literal "${snapshot}"))`,
|
|
259
|
+
`(allow file-read* (literal "${snapshot}"))`,
|
|
260
|
+
'(allow file-read* (subpath "/bin"))',
|
|
261
|
+
'(allow file-read* (subpath "/usr/bin"))',
|
|
262
|
+
'(allow file-read* (subpath "/usr/lib"))',
|
|
263
|
+
'(allow file-read* (subpath "/usr/libexec"))',
|
|
264
|
+
'(allow file-read* (subpath "/System/Library"))',
|
|
265
|
+
'(allow file-read* (subpath "/Library/Frameworks"))',
|
|
266
|
+
'(allow file-read* (subpath "/usr/local/lib"))',
|
|
267
|
+
`(allow file-read* file-write* (subpath "${capsule}"))`,
|
|
268
|
+
'(allow file-read* file-write* (literal "/dev/null") (literal "/dev/stdin") (literal "/dev/stdout") (literal "/dev/stderr"))',
|
|
269
|
+
'(allow file-read* (literal "/dev/urandom"))',
|
|
270
|
+
'(allow file-read* (literal "/etc/passwd"))',
|
|
271
|
+
].join("\n");
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export function macosMcpLauncherPolicyDigest({ snapshotPath, capsulePath }) {
|
|
275
|
+
return sha256(
|
|
276
|
+
generateMacosMcpLauncherSeatbeltProfile({ snapshotPath, capsulePath }),
|
|
277
|
+
);
|
|
278
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "chainlesschain.macos-mcp-launcher-protocol.v1",
|
|
3
|
+
"protocolVersion": 1,
|
|
4
|
+
"backend": "macos-signed-root-fd-launcher",
|
|
5
|
+
"packageIdentifier": "com.chainlesschain.cli.mcp-launcher.pkg",
|
|
6
|
+
"helperInstallPath": "/Library/PrivilegedHelperTools/com.chainlesschain.cli.mcp-launcher",
|
|
7
|
+
"installContractPath": "/Library/PrivilegedHelperTools/com.chainlesschain.cli.mcp-launcher.json",
|
|
8
|
+
"snapshotRoot": "/Library/Application Support/ChainlessChain/McpLauncher/runtime",
|
|
9
|
+
"snapshotLockName": "launcher.lock",
|
|
10
|
+
"sandboxExecutable": "/usr/bin/sandbox-exec",
|
|
11
|
+
"runtimeFd": 3,
|
|
12
|
+
"entryFd": 4,
|
|
13
|
+
"capsuleRootFd": 5,
|
|
14
|
+
"gateFd": 6,
|
|
15
|
+
"readyFd": 7,
|
|
16
|
+
"callerLifelineFd": 8,
|
|
17
|
+
"maximumRuntimeBytes": 268435456,
|
|
18
|
+
"maximumEntryBytes": 67108864,
|
|
19
|
+
"maximumPassthroughArgs": 128,
|
|
20
|
+
"maximumStaleSnapshots": 8,
|
|
21
|
+
"readyTimeoutMs": 15000,
|
|
22
|
+
"profileTemplateVersion": 1
|
|
23
|
+
}
|