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.
Files changed (240) hide show
  1. package/package.json +7 -4
  2. package/scripts/macos-mcp-launcher-build.mjs +317 -0
  3. package/scripts/macos-mcp-launcher-postinstall.sh +54 -0
  4. package/scripts/macos-mcp-launcher-preinstall.sh +61 -0
  5. package/src/assets/web-panel/.build-hash +1 -1
  6. package/src/assets/web-panel/assets/{AIOps-CavM7W3k.js → AIOps-CYxFDrcm.js} +1 -1
  7. package/src/assets/web-panel/assets/{ActionButton-CUvZGabQ.js → ActionButton-CPBtdiU2.js} +1 -1
  8. package/src/assets/web-panel/assets/{Analytics-DeBnWnbe.js → Analytics-Dayq7Dp7.js} +3 -3
  9. package/src/assets/web-panel/assets/{AppLayout-DbI5kxvd.js → AppLayout-6U7bPb2s.js} +4 -4
  10. package/src/assets/web-panel/assets/{Artifacts-D93bigKm.js → Artifacts-D2Iqg_3D.js} +1 -1
  11. package/src/assets/web-panel/assets/{Audit-CBNvfUZa.js → Audit-CdoOB7WV.js} +1 -1
  12. package/src/assets/web-panel/assets/{BackgroundAgents-CJLyh_YU.js → BackgroundAgents-DrnAVB8w.js} +1 -1
  13. package/src/assets/web-panel/assets/{Backup-D_0yoehD.js → Backup-CesMi5cy.js} +1 -1
  14. package/src/assets/web-panel/assets/{BaseInput-TJxmbObW.js → BaseInput-DaX9ptax.js} +1 -1
  15. package/src/assets/web-panel/assets/{Chat-CE0dto1q.js → Chat-OrwOPxDS.js} +5 -5
  16. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CZ5-yYiD.js → ChatBubbleRenderer-CvPZFRxM.js} +1 -1
  17. package/src/assets/web-panel/assets/{Checkbox-Ck1RVIVo.js → Checkbox-DiHbcysC.js} +1 -1
  18. package/src/assets/web-panel/assets/{Codegen-qpoyf6DK.js → Codegen-CbgCkaBJ.js} +1 -1
  19. package/src/assets/web-panel/assets/{Col-DUyPWjIE.js → Col-Du5hgrh4.js} +1 -1
  20. package/src/assets/web-panel/assets/{Community-D_S1BemS.js → Community-DsPOBW-p.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compact-BjxeK-Gc.js → Compact-BwHIFkNC.js} +1 -1
  22. package/src/assets/web-panel/assets/{Compliance-Dd3CEJsu.js → Compliance-BvrDQSgd.js} +1 -1
  23. package/src/assets/web-panel/assets/{Cowork-B4QG7-ad.js → Cowork-gwAE6arx.js} +3 -3
  24. package/src/assets/web-panel/assets/{Cron-BtZnids5.js → Cron-DW-0l4uF.js} +2 -2
  25. package/src/assets/web-panel/assets/{Crosschain-CHPfCBFD.js → Crosschain-j-NsLesB.js} +1 -1
  26. package/src/assets/web-panel/assets/{DID-DT8DCEOK.js → DID-CibVEBOI.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dashboard-COQab5_U.js → Dashboard-W4z9vSfe.js} +2 -2
  28. package/src/assets/web-panel/assets/{Dropdown-BY1PsQuU.js → Dropdown-DAcrkKxG.js} +1 -1
  29. package/src/assets/web-panel/assets/{EmailListRenderer-CsuAuaq3.js → EmailListRenderer-6GXah-89.js} +1 -1
  30. package/src/assets/web-panel/assets/{FamilyGuardDashboard-BqpinD-j.js → FamilyGuardDashboard-TKDCq8Ku.js} +1 -1
  31. package/src/assets/web-panel/assets/{Federation-D0gkfQFv.js → Federation-BXBLlcNm.js} +1 -1
  32. package/src/assets/web-panel/assets/{FormItemContext-BqgE-axK.js → FormItemContext-BoJJBkG3.js} +1 -1
  33. package/src/assets/web-panel/assets/{GenericCardRenderer-D0hJ2KvC.js → GenericCardRenderer-okjsl46v.js} +1 -1
  34. package/src/assets/web-panel/assets/{Git-CmMB0uPY.js → Git-Rvs7i6nn.js} +2 -2
  35. package/src/assets/web-panel/assets/{Governance-BnVEI0Dk.js → Governance-CHSUxXXS.js} +1 -1
  36. package/src/assets/web-panel/assets/{Inference-YTAMihRP.js → Inference-V3BlfxsB.js} +1 -1
  37. package/src/assets/web-panel/assets/{KnowledgeGraph-0ax7VHop.js → KnowledgeGraph-C_NlD4aR.js} +1 -1
  38. package/src/assets/web-panel/assets/{Logs-B9TRcokL.js → Logs-Nn4LNxhA.js} +2 -2
  39. package/src/assets/web-panel/assets/MarkdownRenderer-SVAgNnkt.js +1 -0
  40. package/src/assets/web-panel/assets/{Marketplace-B6CSuD_H.js → Marketplace-DEmjFcg-.js} +1 -1
  41. package/src/assets/web-panel/assets/{McpTools-CjMXvOVU.js → McpTools-DlopXipI.js} +3 -3
  42. package/src/assets/web-panel/assets/{Memory-CXRF71U3.js → Memory-BG3ynX60.js} +2 -2
  43. package/src/assets/web-panel/assets/{MobileBridge-DQgNp_oS.js → MobileBridge-DeRzWOfT.js} +1 -1
  44. package/src/assets/web-panel/assets/{MobileProjects-DlPwcCbq.js → MobileProjects-Tyd3o2A0.js} +1 -1
  45. package/src/assets/web-panel/assets/{Mtc-6hDTRPe1.js → Mtc-BoPbOv1C.js} +2 -2
  46. package/src/assets/web-panel/assets/{MtcAudit-BlVHU1DS.js → MtcAudit-un-rTHp7.js} +2 -2
  47. package/src/assets/web-panel/assets/{Multisig-DP9pzEbV.js → Multisig-Ds0oveEB.js} +3 -3
  48. package/src/assets/web-panel/assets/{NLProgramming-Djorh8EV.js → NLProgramming-D09JI-yY.js} +1 -1
  49. package/src/assets/web-panel/assets/{Notes-oLZ-JkUg.js → Notes-DTRhiKJn.js} +4 -4
  50. package/src/assets/web-panel/assets/{NotificationSettings-Cg288VH3.js → NotificationSettings-BAnnNCim.js} +1 -1
  51. package/src/assets/web-panel/assets/OrderTableRenderer-Yr-1fSYi.js +1 -0
  52. package/src/assets/web-panel/assets/{Organization-CBdo-bHs.js → Organization-S9EAolpj.js} +4 -4
  53. package/src/assets/web-panel/assets/{Overflow-qZdnVumx.js → Overflow-CqcLKqJ8.js} +1 -1
  54. package/src/assets/web-panel/assets/{P2P-D4kNfGNQ.js → P2P-Dw0F9EcU.js} +2 -2
  55. package/src/assets/web-panel/assets/{PdhVaultBrowser-DnlMemM7.js → PdhVaultBrowser-BDRwUevN.js} +5 -5
  56. package/src/assets/web-panel/assets/{Permissions-DHucHFBJ.js → Permissions-D3_c3nKB.js} +4 -4
  57. package/src/assets/web-panel/assets/{PersonalDataHub-BovlOIPR.js → PersonalDataHub-CxdMV98x.js} +4 -4
  58. package/src/assets/web-panel/assets/{Pipeline-Deru3CQY.js → Pipeline-CgjNQFLI.js} +1 -1
  59. package/src/assets/web-panel/assets/{Privacy-Bq5oTTbU.js → Privacy-BHghIIht.js} +1 -1
  60. package/src/assets/web-panel/assets/{ProjectInit-BfzxVWAz.js → ProjectInit-De6pqaKM.js} +2 -2
  61. package/src/assets/web-panel/assets/{ProjectSettings-CKC6XBtH.js → ProjectSettings-Bg4ZkNYQ.js} +2 -2
  62. package/src/assets/web-panel/assets/Projects-CP8vPvzs.js +1 -0
  63. package/src/assets/web-panel/assets/{Providers-C_jx4TWX.js → Providers-CUnHbNf-.js} +1 -1
  64. package/src/assets/web-panel/assets/{QrScannerModal-BdIHeVGC.js → QrScannerModal-DA2f3Wts.js} +1 -1
  65. package/src/assets/web-panel/assets/{QuickAsk-BwZwAcPD.js → QuickAsk-C1FeHDqp.js} +1 -1
  66. package/src/assets/web-panel/assets/{Recommend-BNTt0L-m.js → Recommend-B5guaUMN.js} +1 -1
  67. package/src/assets/web-panel/assets/RemoteSession-PDADSds3.js +5 -0
  68. package/src/assets/web-panel/assets/{Reputation-D6VpG32B.js → Reputation-eTlRhgvK.js} +1 -1
  69. package/src/assets/web-panel/assets/{Row-D_74OvQQ.js → Row-D7AqSGY0.js} +1 -1
  70. package/src/assets/web-panel/assets/{RssFeed-BTr0a-BQ.js → RssFeed-JiuLm4Ja.js} +3 -3
  71. package/src/assets/web-panel/assets/{Search-C3MCFoNU.js → Search-CwruahW3.js} +1 -1
  72. package/src/assets/web-panel/assets/{Security-CqW9aJ6s.js → Security-CdhqaR0b.js} +4 -4
  73. package/src/assets/web-panel/assets/{Services-Cw5GNaHF.js → Services-CU0ZIlcT.js} +2 -2
  74. package/src/assets/web-panel/assets/{Skeleton-DZps5qeY.js → Skeleton-CtduPfAb.js} +1 -1
  75. package/src/assets/web-panel/assets/{Skills-C6NQ1znT.js → Skills-CROXm6AY.js} +1 -1
  76. package/src/assets/web-panel/assets/{Sla-DFP8G2Sh.js → Sla-DiZiABFD.js} +1 -1
  77. package/src/assets/web-panel/assets/{SpeechSettings-ESt6MB6v.js → SpeechSettings-B5pLcXUw.js} +1 -1
  78. package/src/assets/web-panel/assets/{SyncSettings-BHnN98aM.js → SyncSettings-DBX6J1Oe.js} +2 -2
  79. package/src/assets/web-panel/assets/{Tasks-NiSCaOf-.js → Tasks-BLyRJd3-.js} +1 -1
  80. package/src/assets/web-panel/assets/{Templates-DsKFhW2C.js → Templates-BKa5qzmk.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tenant-CQ0E0ze5.js → Tenant-DnD3a4M6.js} +1 -1
  82. package/src/assets/web-panel/assets/{Terminal-D_rBu_by.js → Terminal-DEitQeTb.js} +2 -2
  83. package/src/assets/web-panel/assets/{TimelineRenderer-D3Vm4Po4.js → TimelineRenderer-CjHggTDq.js} +1 -1
  84. package/src/assets/web-panel/assets/{Tokens-DNTxRH6q.js → Tokens-CsGT7sfl.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trigger-Dgprz1ms.js → Trigger-yr4rFDrW.js} +1 -1
  86. package/src/assets/web-panel/assets/{Trust-B2rUnVBD.js → Trust-CLvu1Sjp.js} +1 -1
  87. package/src/assets/web-panel/assets/{UkeySign-DEGQNc6_.js → UkeySign-B0m7yUP8.js} +1 -1
  88. package/src/assets/web-panel/assets/{VideoEditing-jlsAx3Eh.js → VideoEditing-C0VvP4lc.js} +1 -1
  89. package/src/assets/web-panel/assets/{Wallet-8jQih1ij.js → Wallet-kllBAG1M.js} +4 -4
  90. package/src/assets/web-panel/assets/{WebAuthn-XLeO6xIB.js → WebAuthn-C54UQNLx.js} +3 -3
  91. package/src/assets/web-panel/assets/{WorkflowEditor-De_dgDAG.js → WorkflowEditor-B7y8qSvU.js} +1 -1
  92. package/src/assets/web-panel/assets/{chat-CI19R_Sk.js → chat-DRzTh8CJ.js} +1 -1
  93. package/src/assets/web-panel/assets/{colors-DsYTOYN3.js → colors-BSMwSnCx.js} +1 -1
  94. package/src/assets/web-panel/assets/{compact-item-CM3-t_Qr.js → compact-item-BTg602H5.js} +1 -1
  95. package/src/assets/web-panel/assets/{createContext-BjxlBRZv.js → createContext-B6EGsdvp.js} +1 -1
  96. package/src/assets/web-panel/assets/devWarning-Dol8jLEP.js +1 -0
  97. package/src/assets/web-panel/assets/{hasIn-RDaWX_4i.js → hasIn-DDKqJ8RD.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-nAH87mQP.js → index-323Hhxxt.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-DIUnNOjG.js → index-BICn3Qh1.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-DyIWssPC.js → index-BMuGd2--.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-DX7tuWVJ.js → index-BRqt4fO-.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-Cd3euP_4.js → index-BVTAl5N2.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-Cpqm1qfU.js → index-BsR7Y2NG.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-DcPFB8qJ.js → index-Bx044qDj.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-Cd9OJhHG.js → index-C1GFfuqN.js} +1 -1
  106. package/src/assets/web-panel/assets/index-C3QX5tOl.js +1 -0
  107. package/src/assets/web-panel/assets/{index-B-Z8eFUJ.js → index-C66NpWy5.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-BlT2VAEK.js → index-CDTvsX8t.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Dsij_KsN.js → index-CGNklbP6.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-C4gkzxkw.js → index-CHfLYwcW.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-D6sm5-Xq.js → index-CNxg61YP.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-C0yx-jtQ.js → index-CQlHFN_g.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-CjTrRt13.js → index-CUEU48o1.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-B7WBt_4T.js → index-CWGax2QW.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-IeiL9RKc.js → index-C_JzIXUq.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CnHH7bnD.js → index-Cf23wVMs.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-BKJr-TZp.js → index-CmAInUkX.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-CiECJi-Q.js → index-CmAubjDi.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-BCnZyIMA.js → index-Co7oM1qr.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-Drlnwr8F.js → index-CwPUZbMI.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-9R6BxAr0.js → index-D1naNj4U.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-BGqqJfL0.js → index-D5CsBShd.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-Bi46Xu4u.js → index-DBT3YeQ9.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-DXXtGMUJ.js → index-DLdrHhML.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-B0PMlbMs.js → index-Dc77VR3H.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-D0zcy54x.js → index-Dfv2lKu3.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-BN6UPD2E.js → index-DiW0sDkz.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-Dxge-xWl.js → index-DpTHIRfZ.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-CyOGN6a5.js → index-DqFXGzzC.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-B9O9YyWE.js → index-XFe-1twF.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-BHNYPO0b.js → index-p2HYn89m.js} +3 -3
  132. package/src/assets/web-panel/assets/{index-CVQMeiwH.js → index-pqfux8vZ.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-pPL66J85.js → index-rjzk9z1Q.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-DoQA0-52.js → index-th2ihDc0.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-B5REnKt8.js → index-u2YVld9W.js} +1 -1
  136. package/src/assets/web-panel/assets/index-xYybvEic.js +1 -0
  137. package/src/assets/web-panel/assets/{initDefaultProps-BTL88of4.js → initDefaultProps-C3Djh9fa.js} +1 -1
  138. package/src/assets/web-panel/assets/{motion-BUB2pXwB.js → motion-BzqFmbSe.js} +1 -1
  139. package/src/assets/web-panel/assets/{move-egCkkOMm.js → move-DJo_FFaW.js} +1 -1
  140. package/src/assets/web-panel/assets/{mtc-parser-DAWhZC8c.js → mtc-parser-_tlTiBvk.js} +1 -1
  141. package/src/assets/web-panel/assets/{omit-CvOxe_6d.js → omit-CB2ZyxUg.js} +1 -1
  142. package/src/assets/web-panel/assets/{pickAttrs-DZUSLZ5Z.js → pickAttrs-DZwIFD4u.js} +1 -1
  143. package/src/assets/web-panel/assets/{placementArrow-BERxGNMY.js → placementArrow-DxZY0dgk.js} +1 -1
  144. package/src/assets/web-panel/assets/{responsiveObserve-DZuDfZ9n.js → responsiveObserve-CzzGt7GL.js} +1 -1
  145. package/src/assets/web-panel/assets/{slide-DO756sgI.js → slide-BaIK52yz.js} +1 -1
  146. package/src/assets/web-panel/assets/{statusUtils-BRQlIz28.js → statusUtils-3-FHu9_M.js} +1 -1
  147. package/src/assets/web-panel/assets/{styleChecker-DCSfdybl.js → styleChecker-BkRT68fK.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFlexGapSupport-LD8dWVve.js → useFlexGapSupport-DHYwKS-s.js} +1 -1
  149. package/src/assets/web-panel/assets/{useFs-BX9uW2LK.js → useFs-DVVUhV8p.js} +1 -1
  150. package/src/assets/web-panel/assets/{usePersonalDataHub-BPSlPuHU.js → usePersonalDataHub-CkrFKAzQ.js} +1 -1
  151. package/src/assets/web-panel/assets/{vnode-BmOILC9V.js → vnode-BuBLFz0c.js} +1 -1
  152. package/src/assets/web-panel/assets/{zoom-1iKowKGg.js → zoom-kpm6LtXU.js} +1 -1
  153. package/src/assets/web-panel/index.html +1 -1
  154. package/src/command-help-index.json +3 -3
  155. package/src/commands/cowork.js +418 -41
  156. package/src/commands/permissions.js +240 -16
  157. package/src/commands/plugin.js +1293 -56
  158. package/src/commands/session-location.js +276 -0
  159. package/src/commands/session.js +2 -0
  160. package/src/data/changelog.json +28 -2
  161. package/src/gateways/ws/action-protocol.js +316 -17
  162. package/src/gateways/ws/message-dispatcher.js +30 -0
  163. package/src/gateways/ws/remote-session-protocol.js +565 -35
  164. package/src/gateways/ws/ws-agent-handler.js +12 -0
  165. package/src/gateways/ws/ws-approval-gate.js +5 -0
  166. package/src/gateways/ws/ws-server.js +510 -50
  167. package/src/harness/jsonl-session-store.js +341 -24
  168. package/src/harness/mcp-client.js +8 -1
  169. package/src/harness/remote-session-audit.js +2 -0
  170. package/src/harness/remote-session-crypto.js +929 -21
  171. package/src/harness/remote-session-registry.js +945 -24
  172. package/src/harness/session-list-index.js +233 -14
  173. package/src/lib/agent-authority.js +6 -0
  174. package/src/lib/auto-mode-config.js +98 -3
  175. package/src/lib/background-agent-keeper-client.js +248 -0
  176. package/src/lib/background-agent-keeper-protocol.js +291 -0
  177. package/src/lib/background-agent-supervisor.js +1357 -85
  178. package/src/lib/background-interaction-resolver.js +12 -0
  179. package/src/lib/background-session-transport.js +23 -6
  180. package/src/lib/background-turn-bootstrap-protocol.js +190 -0
  181. package/src/lib/cowork-workflow.js +1188 -76
  182. package/src/lib/delivery-production-adapter.js +38 -2
  183. package/src/lib/dynamic-workflow-facade.js +1736 -0
  184. package/src/lib/execution-location-contract.js +551 -0
  185. package/src/lib/execution-location-runtime.js +130 -0
  186. package/src/lib/ide-context.js +94 -6
  187. package/src/lib/mcp-stdio-package-materialization.js +166 -14
  188. package/src/lib/packer/pkg-config-generator.js +2 -0
  189. package/src/lib/permission-authority.js +77 -0
  190. package/src/lib/permission-side-effect-center.js +495 -0
  191. package/src/lib/plugin-runtime/install.js +514 -13
  192. package/src/lib/plugin-runtime/marketplace-artifact-readback.js +900 -0
  193. package/src/lib/plugin-runtime/marketplace-catalog.js +1181 -0
  194. package/src/lib/plugin-runtime/marketplace-impact.js +408 -0
  195. package/src/lib/plugin-runtime/marketplace-remote-artifacts.js +1567 -0
  196. package/src/lib/plugin-security.js +60 -3
  197. package/src/lib/process-execution-broker/index.js +1095 -57
  198. package/src/lib/process-execution-broker/linux-bwrap-descriptor-launch.js +375 -0
  199. package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +90 -16
  200. package/src/lib/process-execution-broker/linux-generic-bwrap.js +159 -18
  201. package/src/lib/process-execution-broker/macos-mcp-launcher-contract.js +278 -0
  202. package/src/lib/process-execution-broker/macos-mcp-launcher-protocol.json +23 -0
  203. package/src/lib/process-execution-broker/macos-mcp-launcher.c +1497 -0
  204. package/src/lib/process-execution-broker/mcp-fd-entry-bootstrap.js +37 -0
  205. package/src/lib/process-execution-broker/platform-sandbox.js +2330 -279
  206. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  207. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  208. package/src/lib/process-execution-broker/windows-sandbox.cs +50 -4
  209. package/src/lib/public-ide-capability-manifest.js +3 -0
  210. package/src/lib/remote-approval-bridge.js +777 -34
  211. package/src/lib/remote-control.js +2 -0
  212. package/src/lib/remote-membership-authority.js +632 -0
  213. package/src/lib/remote-membership-coordinator.js +2973 -0
  214. package/src/lib/remote-membership-host-store.js +1799 -0
  215. package/src/lib/runtime-provenance-ledger.js +171 -46
  216. package/src/lib/scoped-permission-store.js +369 -0
  217. package/src/lib/session-anti-rollback-anchor.js +262 -5
  218. package/src/lib/shell-approval.js +169 -6
  219. package/src/lib/sub-agent-context.js +4 -0
  220. package/src/lib/with-file-lock.js +73 -38
  221. package/src/lib/workflow-definition-contract.js +149 -0
  222. package/src/repl/agent-repl.js +111 -36
  223. package/src/repl/chat-repl.js +2 -0
  224. package/src/repl/clipboard-image.js +735 -16
  225. package/src/repl/ide-status.js +1 -1
  226. package/src/repl/prompt-interactions.js +59 -6
  227. package/src/repl/remote-approval.js +29 -7
  228. package/src/runtime/agent-core.js +1182 -155
  229. package/src/runtime/headless-runner.js +52 -30
  230. package/src/runtime/headless-stream.js +51 -28
  231. package/src/workers/background-agent-keeper.js +689 -0
  232. package/src/workers/background-agent-worker.js +365 -13
  233. package/src/workers/background-turn-bootstrap.js +170 -0
  234. package/src/assets/web-panel/assets/MarkdownRenderer-yySN5YNM.js +0 -1
  235. package/src/assets/web-panel/assets/OrderTableRenderer-Bb1O3Ofr.js +0 -1
  236. package/src/assets/web-panel/assets/Projects-CMolGhae.js +0 -1
  237. package/src/assets/web-panel/assets/RemoteSession-Biyn2-Ro.js +0 -5
  238. package/src/assets/web-panel/assets/devWarning-S1ld2LwU.js +0 -1
  239. package/src/assets/web-panel/assets/index-Drz6yq0m.js +0 -1
  240. 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
- return Object.freeze(
172
- args.map((value, index) => assertString(String(value), `args[${index}]`)),
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
- entries = [...stdio];
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
- return index < 3 ? "pipe" : "ignore";
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: probeCommand,
1177
- args: probePolicyArgs,
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 supervisorCommand = `/proc/self/fd/${supervisor.childFd}`;
1241
- const command = issued.pty
1242
- ? `/proc/self/fd/${ptyLauncher.childFd}`
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 ? ["--ctty", supervisorCommand, ...bwrapArgs] : bwrapArgs,
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
+ }