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
@@ -12,10 +12,13 @@
12
12
  * `timeoutMs`, it proceeds unlocked. Callers that set `failIfUnavailable` get a
13
13
  * strict lock: every owner has a PID + unguessable token, a live owner is never
14
14
  * reclaimed merely because the directory is old, and corrupt ownership fails
15
- * closed. Confirmed-dead owners are reclaimed with an exact-token marker inside
16
- * the lock directory so a delayed contender cannot delete a replacement lock.
17
- * Strict callers may use bounded jittered retries and an after-release yield to
18
- * avoid Windows sharing transients and fixed-interval lock convoys.
15
+ * closed. The default filesystem publishes a fully populated, uniquely staged
16
+ * directory in one rename so a process killed during acquisition cannot expose
17
+ * an ownerless lock. Confirmed-dead owners are reclaimed with an exact-token
18
+ * marker inside the lock directory so a delayed contender cannot delete a
19
+ * replacement lock. Strict callers may use bounded jittered retries and an
20
+ * after-release yield to avoid Windows sharing transients and fixed-interval
21
+ * lock convoys.
19
22
  *
20
23
  * @param {string} targetPath the file being guarded (lock is `${targetPath}.lock`)
21
24
  * @param {(ctx:{locked:boolean})=>T} fn critical section; receives whether the lock was held
@@ -37,6 +40,10 @@ export function withFileLock(targetPath, fn, opts = {}) {
37
40
  _ownerToken = () => randomUUID(),
38
41
  failIfUnavailable = false,
39
42
  } = opts;
43
+ const isOwnerAlive =
44
+ typeof opts._isOwnerAlive === "function"
45
+ ? opts._isOwnerAlive
46
+ : (candidate) => _isProcessAlive(candidate.pid);
40
47
 
41
48
  const lockDir = `${targetPath}.lock`;
42
49
  const ownerPath = path.join(lockDir, "owner.json");
@@ -52,36 +59,9 @@ export function withFileLock(targetPath, fn, opts = {}) {
52
59
 
53
60
  for (;;) {
54
61
  try {
55
- _fs.mkdirSync(lockDir);
56
- try {
57
- _fs.writeFileSync(ownerPath, JSON.stringify(owner), {
58
- encoding: "utf8",
59
- mode: 0o600,
60
- flag: "wx",
61
- });
62
- held = true;
63
- break;
64
- } catch (error) {
65
- _fs.rmSync(lockDir, { recursive: true, force: true });
66
- acquisitionError = error;
67
- if (
68
- failIfUnavailable &&
69
- isTransientLockError(error) &&
70
- waitForRetry({
71
- _now,
72
- _sleep,
73
- _random,
74
- deadline,
75
- retryAttempt: retryAttempt++,
76
- retryMs,
77
- maxRetryMs,
78
- retryJitterMs,
79
- })
80
- ) {
81
- continue;
82
- }
83
- break;
84
- }
62
+ acquireOwnedDirectory(_fs, lockDir, owner);
63
+ held = true;
64
+ break;
85
65
  } catch (error) {
86
66
  if (!error || error.code !== "EEXIST") {
87
67
  acquisitionError = error;
@@ -108,8 +88,8 @@ export function withFileLock(targetPath, fn, opts = {}) {
108
88
  const incumbent = ownerRead.owner;
109
89
  acquisitionError = ownerRead.error;
110
90
  if (incumbent) {
111
- if (!_isProcessAlive(incumbent.pid)) {
112
- if (reclaimOwnedDirectory(_fs, lockDir, incumbent, _isProcessAlive)) {
91
+ if (!isOwnerAlive(incumbent)) {
92
+ if (reclaimOwnedDirectory(_fs, lockDir, incumbent, isOwnerAlive)) {
113
93
  continue;
114
94
  }
115
95
  }
@@ -200,6 +180,61 @@ const defaultFs = {
200
180
  rmSync: (p, o) => fs.rmSync(p, o),
201
181
  };
202
182
 
183
+ function acquireOwnedDirectory(_fs, lockDir, owner) {
184
+ const serializedOwner = JSON.stringify(owner);
185
+ // Injected legacy filesystems used by a few consumers may not implement
186
+ // rename. Keep their old acquire path, while the real Node filesystem always
187
+ // uses the crash-safe staged publication below.
188
+ if (typeof _fs.renameSync !== "function") {
189
+ _fs.mkdirSync(lockDir);
190
+ try {
191
+ _fs.writeFileSync(path.join(lockDir, "owner.json"), serializedOwner, {
192
+ encoding: "utf8",
193
+ mode: 0o600,
194
+ flag: "wx",
195
+ });
196
+ return;
197
+ } catch (error) {
198
+ _fs.rmSync(lockDir, { recursive: true, force: true });
199
+ throw error;
200
+ }
201
+ }
202
+
203
+ const candidateDir = `${lockDir}.acquire-${owner.token}`;
204
+ try {
205
+ _fs.mkdirSync(candidateDir);
206
+ _fs.writeFileSync(path.join(candidateDir, "owner.json"), serializedOwner, {
207
+ encoding: "utf8",
208
+ mode: 0o600,
209
+ flag: "wx",
210
+ });
211
+ _fs.renameSync(candidateDir, lockDir);
212
+ } catch (error) {
213
+ try {
214
+ _fs.rmSync(candidateDir, { recursive: true, force: true });
215
+ } catch {
216
+ /* uniquely-tokened acquisition debris cannot block the lock path */
217
+ }
218
+ if (directoryExists(_fs, lockDir)) {
219
+ const contention = new Error("State lock already exists", {
220
+ cause: error,
221
+ });
222
+ contention.code = "EEXIST";
223
+ throw contention;
224
+ }
225
+ throw error;
226
+ }
227
+ }
228
+
229
+ function directoryExists(_fs, target) {
230
+ try {
231
+ _fs.statSync(target);
232
+ return true;
233
+ } catch {
234
+ return false;
235
+ }
236
+ }
237
+
203
238
  function isProcessAlive(pid) {
204
239
  try {
205
240
  process.kill(pid, 0);
@@ -310,7 +345,7 @@ function writeOwnerMarker(_fs, markerPath, owner) {
310
345
  });
311
346
  }
312
347
 
313
- function reclaimOwnedDirectory(_fs, lockDir, owner, processAlive) {
348
+ function reclaimOwnedDirectory(_fs, lockDir, owner, ownerAlive) {
314
349
  const markerPath = path.join(lockDir, `.reclaim-${owner.token}`);
315
350
  try {
316
351
  writeOwnerMarker(_fs, markerPath, owner);
@@ -319,7 +354,7 @@ function reclaimOwnedDirectory(_fs, lockDir, owner, processAlive) {
319
354
  throw error;
320
355
  }
321
356
  const current = readOwner(_fs, path.join(lockDir, "owner.json"));
322
- if (!sameOwner(current, owner) || processAlive(owner.pid)) {
357
+ if (!sameOwner(current, owner) || ownerAlive(owner)) {
323
358
  removeOwnMarker(_fs, markerPath, owner);
324
359
  return false;
325
360
  }
@@ -0,0 +1,149 @@
1
+ import { createHash } from "node:crypto";
2
+
3
+ export const WORKFLOW_DEFINITION_SCHEMA = "cc-dynamic-workflow-definition/v1";
4
+ export const COWORK_WORKFLOW_RECORD_SCHEMA = "cc-cowork-workflow-record/v1";
5
+ export const MAX_WORKFLOW_DEFINITION_BYTES = 1024 * 1024;
6
+
7
+ function stableJsonValue(value, state = { nodes: 0, depth: 0 }) {
8
+ state.nodes += 1;
9
+ if (state.nodes > 20_000 || state.depth > 32) {
10
+ throw new TypeError("workflow definition exceeds canonicalization limits");
11
+ }
12
+ if (
13
+ value === null ||
14
+ typeof value === "boolean" ||
15
+ typeof value === "string"
16
+ ) {
17
+ return value;
18
+ }
19
+ if (typeof value === "number") {
20
+ if (!Number.isFinite(value)) {
21
+ throw new TypeError("workflow definition contains a non-finite number");
22
+ }
23
+ return Object.is(value, -0) ? 0 : value;
24
+ }
25
+ if (Array.isArray(value)) {
26
+ const childState = { ...state, depth: state.depth + 1 };
27
+ const output = value.map((item) => stableJsonValue(item, childState));
28
+ state.nodes = childState.nodes;
29
+ return output;
30
+ }
31
+ if (value && typeof value === "object") {
32
+ const prototype = Object.getPrototypeOf(value);
33
+ if (prototype !== Object.prototype && prototype !== null) {
34
+ throw new TypeError(
35
+ "workflow definition must contain plain JSON objects",
36
+ );
37
+ }
38
+ const childState = { ...state, depth: state.depth + 1 };
39
+ const output = {};
40
+ for (const key of Object.keys(value).sort()) {
41
+ const child = value[key];
42
+ if (child === undefined) continue;
43
+ if (["function", "symbol", "bigint"].includes(typeof child)) {
44
+ throw new TypeError("workflow definition contains a non-JSON value");
45
+ }
46
+ output[key] = stableJsonValue(child, childState);
47
+ }
48
+ state.nodes = childState.nodes;
49
+ return output;
50
+ }
51
+ throw new TypeError("workflow definition contains a non-JSON value");
52
+ }
53
+
54
+ function deepFreeze(value) {
55
+ if (!value || typeof value !== "object" || Object.isFrozen(value)) {
56
+ return value;
57
+ }
58
+ for (const child of Object.values(value)) deepFreeze(child);
59
+ return Object.freeze(value);
60
+ }
61
+
62
+ function digestDefinition(definition) {
63
+ const canonical = JSON.stringify(definition);
64
+ if (Buffer.byteLength(canonical, "utf8") > MAX_WORKFLOW_DEFINITION_BYTES) {
65
+ throw new TypeError(
66
+ `workflow definition exceeds ${MAX_WORKFLOW_DEFINITION_BYTES} bytes`,
67
+ );
68
+ }
69
+ return `sha256:${createHash("sha256").update(canonical).digest("hex")}`;
70
+ }
71
+
72
+ function integrityError(message) {
73
+ const error = new Error(message);
74
+ error.code = "WORKFLOW_DEFINITION_INTEGRITY";
75
+ return error;
76
+ }
77
+
78
+ export function normalizeWorkflowDefinitionDigest(value) {
79
+ if (typeof value !== "string") return null;
80
+ const normalized = value.trim().toLowerCase();
81
+ return /^sha256:[a-f0-9]{64}$/u.test(normalized) ? normalized : null;
82
+ }
83
+
84
+ export function createWorkflowDefinitionAuthority(workflow) {
85
+ const definition = deepFreeze(stableJsonValue(workflow));
86
+ return Object.freeze({
87
+ schema: WORKFLOW_DEFINITION_SCHEMA,
88
+ definitionDigest: digestDefinition(definition),
89
+ definition,
90
+ });
91
+ }
92
+
93
+ export function createCoworkWorkflowRecord(workflow) {
94
+ const authority = createWorkflowDefinitionAuthority(workflow);
95
+ const record = {
96
+ schema: COWORK_WORKFLOW_RECORD_SCHEMA,
97
+ definitionSchema: authority.schema,
98
+ definitionDigest: authority.definitionDigest,
99
+ definition: authority.definition,
100
+ };
101
+ const serialized = JSON.stringify(record, null, 2);
102
+ if (Buffer.byteLength(serialized, "utf8") > MAX_WORKFLOW_DEFINITION_BYTES) {
103
+ throw new TypeError(
104
+ `workflow definition exceeds ${MAX_WORKFLOW_DEFINITION_BYTES} bytes`,
105
+ );
106
+ }
107
+ return Object.freeze(record);
108
+ }
109
+
110
+ export function verifyCoworkWorkflowRecord(value, options = {}) {
111
+ if (
112
+ value?.schema !== COWORK_WORKFLOW_RECORD_SCHEMA &&
113
+ options.allowLegacy === true
114
+ ) {
115
+ const authority = createWorkflowDefinitionAuthority(value);
116
+ return Object.freeze({
117
+ status: "legacy-unversioned",
118
+ recordSchema: null,
119
+ definitionSchema: authority.schema,
120
+ definitionDigest: authority.definitionDigest,
121
+ definition: authority.definition,
122
+ });
123
+ }
124
+ if (!value || value.schema !== COWORK_WORKFLOW_RECORD_SCHEMA) {
125
+ throw integrityError(
126
+ `workflow record must use ${COWORK_WORKFLOW_RECORD_SCHEMA}`,
127
+ );
128
+ }
129
+ if (value.definitionSchema !== WORKFLOW_DEFINITION_SCHEMA) {
130
+ throw integrityError("workflow definition schema is unsupported");
131
+ }
132
+ const declaredDigest = normalizeWorkflowDefinitionDigest(
133
+ value.definitionDigest,
134
+ );
135
+ if (!declaredDigest) {
136
+ throw integrityError("workflow definition digest is invalid");
137
+ }
138
+ const authority = createWorkflowDefinitionAuthority(value.definition);
139
+ if (authority.definitionDigest !== declaredDigest) {
140
+ throw integrityError("workflow definition digest mismatch");
141
+ }
142
+ return Object.freeze({
143
+ status: "versioned",
144
+ recordSchema: COWORK_WORKFLOW_RECORD_SCHEMA,
145
+ definitionSchema: authority.schema,
146
+ definitionDigest: authority.definitionDigest,
147
+ definition: authority.definition,
148
+ });
149
+ }
@@ -25,6 +25,7 @@ import path from "path";
25
25
  import { randomUUID } from "node:crypto";
26
26
  import { isPromise, isProxy } from "node:util/types";
27
27
  import { logger } from "../lib/logger.js";
28
+ import { captureAmbientExecutionLocation } from "../lib/execution-location-runtime.js";
28
29
  import { issueMcpStdioExecutionAuthority } from "../lib/mcp-stdio-execution-authority.js";
29
30
  import { getPlanModeManager, PlanState } from "../lib/plan-mode.js";
30
31
  import { createVimState, feedNormalKey } from "../lib/repl-vim.js";
@@ -88,6 +89,7 @@ import {
88
89
  persistSideEffectLedger,
89
90
  } from "../lib/side-effect-ledger-store.js";
90
91
  import { operationIdempotencyKey } from "../lib/idempotency.js";
92
+ import { collectToolResourceIdentifiers } from "../lib/permission-side-effect-center.js";
91
93
  import {
92
94
  preserveDurableSystemMessageProvenance,
93
95
  projectCanonicalResumeMessages,
@@ -173,6 +175,7 @@ import {
173
175
  createPromptInteractionSurface,
174
176
  mergeClipboardImageChips,
175
177
  } from "./prompt-interactions.js";
178
+ import { createSystemClipboardImageBinding } from "./clipboard-image.js";
176
179
  import {
177
180
  buildPermissionPrompt,
178
181
  resolveAskIdleTimeoutMs,
@@ -407,9 +410,11 @@ export async function runReplDirectToolWithLedger({
407
410
  let _hookDb = null;
408
411
  let _compressor = null;
409
412
  let _approvalGate = null;
410
- // .claude/settings.json permission rules (deny > ask > allow) + an interactive
411
- // confirmer for `ask` matches. Loaded once at REPL startup; null = no file.
413
+ // Static + CLI-owned scoped permission rules (deny > ask > allow) and an
414
+ // interactive confirmer for `ask` matches. Scoped rules are refreshed at each
415
+ // tool boundary so TTL expiry and external revocation affect a live session.
412
416
  let _permissionRules = null;
417
+ let _permissionRulesProvider = null;
413
418
  let _permissionConfirm = null;
414
419
  let _managedPermissionRulesOnly = false;
415
420
  // .claude/settings.json `hooks` block (decision-capable PreToolUse/PostToolUse).
@@ -546,6 +551,7 @@ async function executeTool(name, args) {
546
551
  cwd: process.cwd(),
547
552
  approvalGate: _approvalGate,
548
553
  permissionRules: _permissionRules,
554
+ permissionRulesProvider: _permissionRulesProvider,
549
555
  permissionConfirm: _permissionConfirm,
550
556
  settingsHooks: _settingsHooks,
551
557
  classifyAllShell: _classifyAllShell,
@@ -770,6 +776,12 @@ export async function agentLoop(messages, options) {
770
776
  key: sideEffect.key,
771
777
  meta: {
772
778
  tool: event.tool,
779
+ toolUseId: event.tool_use_id || null,
780
+ turnId: event.turn_id || null,
781
+ resources: collectToolResourceIdentifiers(
782
+ event.tool,
783
+ event.args,
784
+ ),
773
785
  idempotencyKey: operationIdempotencyKey({
774
786
  tool: event.tool,
775
787
  args: event.args,
@@ -3163,6 +3175,11 @@ async function startAgentReplInWorkspaceOwned(
3163
3175
  const { getApprovalGate } =
3164
3176
  await import("../lib/session-core-singletons.js");
3165
3177
  _approvalGate = await getApprovalGate();
3178
+ _approvalGate =
3179
+ _approvalGate?.createSessionScope?.(
3180
+ sessionId || `repl-scope:${randomUUID()}`,
3181
+ ) || _approvalGate;
3182
+ _approvalGate?.setAuthorizationConsumer?.(null);
3166
3183
  // autoMode.decisions: wrap the gate with the configurable classifier
3167
3184
  // BEFORE setConfirmer so the wrapper captures the interactive confirmer.
3168
3185
  // Inactive (delegating) unless the session mode is "auto"; not installed
@@ -3240,29 +3257,53 @@ async function startAgentReplInWorkspaceOwned(
3240
3257
  },
3241
3258
  };
3242
3259
  };
3243
- _approvalGate.setConfirmer(async ({ tool, args, riskLevel }) => {
3244
- if (_dontAskActive()) {
3245
- process.stdout.write(
3246
- chalk.yellow(
3247
- `\n ✕ denied without asking (dontAsk mode): ${riskLevel || "medium"}-risk ${tool || "run_shell"}${args?.command ? " — " + args.command : ""}\n`,
3248
- ),
3260
+ _approvalGate.setConfirmer(
3261
+ async ({
3262
+ tool,
3263
+ args,
3264
+ riskLevel,
3265
+ action,
3266
+ cwd,
3267
+ workspace,
3268
+ sessionId,
3269
+ session,
3270
+ targetEnv,
3271
+ policyVersion,
3272
+ }) => {
3273
+ if (_dontAskActive()) {
3274
+ process.stdout.write(
3275
+ chalk.yellow(
3276
+ `\n ✕ denied without asking (dontAsk mode): ${riskLevel || "medium"}-risk ${tool || "run_shell"}${args?.command ? " — " + args.command : ""}\n`,
3277
+ ),
3278
+ );
3279
+ return false;
3280
+ }
3281
+ await _fireNotification(
3282
+ `Permission needed: ${riskLevel || "medium"}-risk ${tool || "run_shell"}${args?.command ? " — " + args.command : ""}`,
3283
+ "info",
3284
+ _sessionHandle,
3249
3285
  );
3250
- return false;
3251
- }
3252
- await _fireNotification(
3253
- `Permission needed: ${riskLevel || "medium"}-risk ${tool || "run_shell"}${args?.command ? " — " + args.command : ""}`,
3254
- "info",
3255
- _sessionHandle,
3256
- );
3257
- const local = askGateApprovalLocally({ tool, args, riskLevel });
3258
- if (!_remoteApproval?.bridge) return local.promise;
3259
- return raceLocalAndRemote({
3260
- bridge: _remoteApproval.bridge,
3261
- ask: describeAskContext({ tool, args, riskLevel }),
3262
- local,
3263
- writeOut: (text) => process.stdout.write(chalk.cyan(text)),
3264
- });
3265
- });
3286
+ const local = askGateApprovalLocally({ tool, args, riskLevel });
3287
+ if (!_remoteApproval?.bridge) return local.promise;
3288
+ return raceLocalAndRemote({
3289
+ bridge: _remoteApproval.bridge,
3290
+ ask: describeAskContext({
3291
+ tool,
3292
+ args,
3293
+ riskLevel,
3294
+ action,
3295
+ cwd,
3296
+ workspace,
3297
+ sessionId,
3298
+ session,
3299
+ targetEnv,
3300
+ policyVersion,
3301
+ }),
3302
+ local,
3303
+ writeOut: (text) => process.stdout.write(chalk.cyan(text)),
3304
+ });
3305
+ },
3306
+ );
3266
3307
  }
3267
3308
  } catch (_err) {
3268
3309
  _approvalGate = null;
@@ -3271,9 +3312,14 @@ async function startAgentReplInWorkspaceOwned(
3271
3312
  // Load .claude/settings.json permission rules + wire an interactive confirmer
3272
3313
  // so `ask` rules prompt (rather than fall closed like headless does).
3273
3314
  try {
3274
- const { loadSettings, readBooleanSetting } =
3275
- await import("../lib/settings-loader.cjs");
3276
- const loaded = loadSettings({ cwd: process.cwd() });
3315
+ const { readBooleanSetting } = await import("../lib/settings-loader.cjs");
3316
+ const { createPermissionRulesProvider, loadPermissionAuthority } =
3317
+ await import("../lib/permission-authority.js");
3318
+ const permissionAuthorityOptions = { cwd: process.cwd() };
3319
+ const loaded = loadPermissionAuthority(permissionAuthorityOptions);
3320
+ _permissionRulesProvider = createPermissionRulesProvider(
3321
+ permissionAuthorityOptions,
3322
+ );
3277
3323
  _managedPermissionRulesOnly =
3278
3324
  loaded.managed?.allowManagedPermissionRulesOnly === true;
3279
3325
  // Claude-Code 2.1.186 respondToBashCommands (default OFF / opt-in when unset).
@@ -3347,17 +3393,23 @@ async function startAgentReplInWorkspaceOwned(
3347
3393
  _sessionHandle,
3348
3394
  );
3349
3395
  const local = askPermissionLocally({ tool, args, rule, reason });
3350
- if (!_remoteApproval?.bridge) return local.promise;
3351
- return raceLocalAndRemote({
3352
- bridge: _remoteApproval.bridge,
3353
- ask: describeAskContext({ tool, args, rule, reason }),
3354
- local,
3355
- writeOut: (text) => process.stdout.write(chalk.cyan(text)),
3356
- });
3396
+ // This confirmer is consumed as a legacy boolean by settings/hook
3397
+ // admission. A remote lease must never be flattened there and then skip
3398
+ // the ApprovalGate consume, so this path remains local-only until it can
3399
+ // carry the opaque authorization through its own dispatch boundary.
3400
+ return local.promise;
3357
3401
  };
3358
3402
  } catch (_err) {
3359
- if (_err?.code === "CC_MANAGED_SETTINGS_INVALID") throw _err;
3403
+ if (
3404
+ _err?.code === "CC_MANAGED_SETTINGS_INVALID" ||
3405
+ _err?.code === "CONFIG_HOME_UNSAFE" ||
3406
+ String(_err?.code || "").startsWith("CC_SCOPED_PERMISSION_") ||
3407
+ String(_err?.code || "").startsWith("DURABLE_SECURITY_STORE_")
3408
+ ) {
3409
+ throw _err;
3410
+ }
3360
3411
  _permissionRules = null;
3412
+ _permissionRulesProvider = null;
3361
3413
  _permissionConfirm = null;
3362
3414
  _managedPermissionRulesOnly = false;
3363
3415
  }
@@ -3475,6 +3527,7 @@ async function startAgentReplInWorkspaceOwned(
3475
3527
  title: `Agent ${new Date().toISOString().slice(0, 10)}`,
3476
3528
  provider,
3477
3529
  model,
3530
+ executionLocation: captureAmbientExecutionLocation({ provider, model }),
3478
3531
  };
3479
3532
  if (useJsonl) {
3480
3533
  sessionId = startReplJsonlSession(
@@ -3542,6 +3595,18 @@ async function startAgentReplInWorkspaceOwned(
3542
3595
  // purely how the confirmers consume it — they RACE the terminal prompt
3543
3596
  // against the paired device instead of gating on the remote alone.
3544
3597
  const _startRemoteApproval = async () => {
3598
+ if (
3599
+ !_approvalGate ||
3600
+ typeof _approvalGate.setConfirmer !== "function" ||
3601
+ typeof _approvalGate.setAuthorizationConsumer !== "function" ||
3602
+ typeof _approvalGate.consumeAuthorization !== "function"
3603
+ ) {
3604
+ const error = new Error(
3605
+ "installed session-core cannot bind and consume durable remote approval",
3606
+ );
3607
+ error.code = "CC_REMOTE_APPROVAL_GATE_UNAVAILABLE";
3608
+ throw error;
3609
+ }
3545
3610
  const { startHeadlessRemoteApproval } =
3546
3611
  await import("../lib/remote-approval-bridge.js");
3547
3612
  const started = await startHeadlessRemoteApproval({
@@ -3554,6 +3619,7 @@ async function startAgentReplInWorkspaceOwned(
3554
3619
  pairing: started.pairing,
3555
3620
  close: started.close,
3556
3621
  };
3622
+ _approvalGate.setAuthorizationConsumer(started.consumeAuthorization);
3557
3623
  logger.log(
3558
3624
  chalk.cyan(
3559
3625
  " remote-control: permission prompts can be answered from a paired device (first answer — terminal or device — wins)",
@@ -3571,6 +3637,7 @@ async function startAgentReplInWorkspaceOwned(
3571
3637
  const _stopRemoteApproval = async () => {
3572
3638
  const active = _remoteApproval;
3573
3639
  _remoteApproval = null; // confirmers fall back to local-only immediately
3640
+ _approvalGate?.setAuthorizationConsumer?.(null);
3574
3641
  if (active) await active.close().catch(() => undefined);
3575
3642
  };
3576
3643
 
@@ -4642,6 +4709,12 @@ async function startAgentReplInWorkspaceOwned(
4642
4709
 
4643
4710
  // Prompt-side interaction modules share the production readline surface.
4644
4711
  // A per-REPL registry avoids singleton handlers retaining an old session.
4712
+ const _clipboardBinding = Object.prototype.hasOwnProperty.call(
4713
+ options,
4714
+ "clipboardBinding",
4715
+ )
4716
+ ? options.clipboardBinding
4717
+ : createSystemClipboardImageBinding();
4645
4718
  const _promptInteractionSurface = createPromptInteractionSurface({
4646
4719
  readline: rl,
4647
4720
  config: _promptInteractionConfig,
@@ -4649,7 +4722,7 @@ async function startAgentReplInWorkspaceOwned(
4649
4722
  getSessionId: () => sessionId,
4650
4723
  getSuggestionContext: () => ({ messages: messages.slice() }),
4651
4724
  persistSuggestionEnabled: _persistPromptSuggestionsEnabled,
4652
- clipboardBinding: options.clipboardBinding || null,
4725
+ clipboardBinding: _clipboardBinding,
4653
4726
  generateSuggestions: resolveReplPromptSuggestionGenerator(
4654
4727
  useJsonl,
4655
4728
  options.generatePromptSuggestions,
@@ -5936,6 +6009,7 @@ async function startAgentReplInWorkspaceOwned(
5936
6009
  if (snap) _clearedConversation = snap;
5937
6010
  messages.length = 1; // Keep system prompt
5938
6011
  _checkpointMarks.length = 0; // checkpoint marks no longer map to anything
6012
+ _promptInteractions.clearClipboardImageChips();
5939
6013
  logger.info(
5940
6014
  snap
5941
6015
  ? "Conversation cleared — run /rewind clear to restore it"
@@ -9056,6 +9130,7 @@ async function startAgentReplInWorkspaceOwned(
9056
9130
  prepareCall,
9057
9131
  approvalGate: _approvalGate,
9058
9132
  permissionRules: _permissionRules,
9133
+ permissionRulesProvider: _permissionRulesProvider,
9059
9134
  permissionConfirm: _permissionConfirm,
9060
9135
  settingsHooks: _settingsHooks,
9061
9136
  hookSupervisor: _asyncHookSupervisor,
@@ -55,6 +55,7 @@ import {
55
55
  import { installPipeSafety } from "../runtime/pipe-safety.js";
56
56
  import { installOutputBackpressure } from "../runtime/output-backpressure.js";
57
57
  import { assertChatSessionUsageAdmission } from "../lib/chat-session-admission.js";
58
+ import { captureAmbientExecutionLocation } from "../lib/execution-location-runtime.js";
58
59
 
59
60
  const SLASH_COMMANDS = {
60
61
  "/exit": "Exit the chat",
@@ -114,6 +115,7 @@ export async function startChatRepl(options = {}) {
114
115
  title: "chat-repl",
115
116
  provider,
116
117
  model,
118
+ executionLocation: captureAmbientExecutionLocation({ provider, model }),
117
119
  });
118
120
  } catch {
119
121
  sessionId = null;