chainlesschain 0.163.7 → 0.164.0

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 (252) hide show
  1. package/package.json +5 -1
  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/assets/{AIOps-axqQfwv8.js → AIOps-D2MEn7fI.js} +1 -1
  6. package/src/assets/web-panel/assets/{ActionButton-DV-Ro0By.js → ActionButton-lCW_4Gf0.js} +1 -1
  7. package/src/assets/web-panel/assets/{Analytics-Bt72WEVu.js → Analytics-Bs7i-nsS.js} +3 -3
  8. package/src/assets/web-panel/assets/{AppLayout-BtepG55E.js → AppLayout-CK7B6S_j.js} +5 -5
  9. package/src/assets/web-panel/assets/{Artifacts-B7KaJ7S_.js → Artifacts-C8ILjpyo.js} +1 -1
  10. package/src/assets/web-panel/assets/{Audit-FNFaUg7A.js → Audit-Bb9cNaWc.js} +1 -1
  11. package/src/assets/web-panel/assets/{BackgroundAgents-DFb6J2wQ.js → BackgroundAgents-sC9ooXIf.js} +1 -1
  12. package/src/assets/web-panel/assets/{Backup-CC7YBhyj.js → Backup-D-DrsplT.js} +1 -1
  13. package/src/assets/web-panel/assets/{BaseInput-RkgTNVtj.js → BaseInput-uCNZpwSK.js} +1 -1
  14. package/src/assets/web-panel/assets/{Chat-hHEmGZy-.js → Chat-CsDK1uE9.js} +6 -6
  15. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CAP9YhHv.js → ChatBubbleRenderer-OqSDt50w.js} +1 -1
  16. package/src/assets/web-panel/assets/{Checkbox-z5wXOQP1.js → Checkbox-JhTXM1-K.js} +1 -1
  17. package/src/assets/web-panel/assets/{Codegen-DVaDJnxy.js → Codegen-BbzZLnyD.js} +1 -1
  18. package/src/assets/web-panel/assets/{Col-CJmaRDR5.js → Col-D4VW4m4j.js} +1 -1
  19. package/src/assets/web-panel/assets/{Community-DF29_2bI.js → Community-BXrYawxV.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compact-DtkQkBzn.js → Compact-DCihGy1u.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compliance-xoHDxp7I.js → Compliance-DlyZ-lk8.js} +1 -1
  22. package/src/assets/web-panel/assets/{Cowork-BUm-R7ht.js → Cowork-DvGZrhbO.js} +2 -2
  23. package/src/assets/web-panel/assets/{Cron-Cgl14ZkB.js → Cron-DUncZi8h.js} +2 -2
  24. package/src/assets/web-panel/assets/{Crosschain-BNcbmoqh.js → Crosschain-C_hLuUcm.js} +1 -1
  25. package/src/assets/web-panel/assets/{DID-Bwja0Zo9.js → DID-b6YSUqxr.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dashboard-Bk5XjEdJ.js → Dashboard-uvM15Cfb.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dropdown-Ci36Oitq.js → Dropdown-D1-Nd4qY.js} +1 -1
  28. package/src/assets/web-panel/assets/{EmailListRenderer--U04ZN4q.js → EmailListRenderer-8ApvL6Zc.js} +1 -1
  29. package/src/assets/web-panel/assets/{FamilyGuardDashboard-B2gNPR2s.js → FamilyGuardDashboard-LYJt8811.js} +1 -1
  30. package/src/assets/web-panel/assets/{Federation-C4KghYn7.js → Federation-BbI3HGpv.js} +1 -1
  31. package/src/assets/web-panel/assets/{FormItemContext-QL7x_Q_0.js → FormItemContext-DSoEKuFu.js} +1 -1
  32. package/src/assets/web-panel/assets/{GenericCardRenderer-F3Ryltwm.js → GenericCardRenderer-B0S9OWd5.js} +1 -1
  33. package/src/assets/web-panel/assets/{Git-2HassK5k.js → Git-DIs9Zhf3.js} +2 -2
  34. package/src/assets/web-panel/assets/{Governance-DoBIp7oe.js → Governance-jzZXrxcl.js} +1 -1
  35. package/src/assets/web-panel/assets/{Inference--W01QhZ-.js → Inference-JUPjf2ZI.js} +1 -1
  36. package/src/assets/web-panel/assets/{KnowledgeGraph-DmvwqGpT.js → KnowledgeGraph-DxnfJvlP.js} +1 -1
  37. package/src/assets/web-panel/assets/{Logs-BBJ4yAel.js → Logs-iXiz8BEE.js} +2 -2
  38. package/src/assets/web-panel/assets/{MarkdownRenderer-BLCZMzhJ.js → MarkdownRenderer-GmB6DOr6.js} +1 -1
  39. package/src/assets/web-panel/assets/{Marketplace-D5lNngSI.js → Marketplace-Y3Xch312.js} +1 -1
  40. package/src/assets/web-panel/assets/{McpTools-CkEVOMKH.js → McpTools-D7kGGbO7.js} +4 -4
  41. package/src/assets/web-panel/assets/{Memory-B1Ow1xVE.js → Memory-Do_hVxzh.js} +2 -2
  42. package/src/assets/web-panel/assets/{MobileBridge-SgYbUfb6.js → MobileBridge-CtrR0Tas.js} +1 -1
  43. package/src/assets/web-panel/assets/MobileProjects-BL0Czcoj.js +1 -0
  44. package/src/assets/web-panel/assets/{Mtc-DcTXSSma.js → Mtc-qo5QCTGd.js} +2 -2
  45. package/src/assets/web-panel/assets/{MtcAudit-Dt3WG4oj.js → MtcAudit-cq5mnjYj.js} +2 -2
  46. package/src/assets/web-panel/assets/{Multisig-B9B38UZx.js → Multisig-Bq0MAQHw.js} +3 -3
  47. package/src/assets/web-panel/assets/{NLProgramming-B0S4GGvG.js → NLProgramming-DdWE6Vi2.js} +1 -1
  48. package/src/assets/web-panel/assets/{Notes-DZ5U58Ng.js → Notes-BxMBFcIp.js} +3 -3
  49. package/src/assets/web-panel/assets/{NotificationSettings-PjL5ZW34.js → NotificationSettings-RTrAcbUe.js} +1 -1
  50. package/src/assets/web-panel/assets/{OrderTableRenderer-DrAX2ESt.js → OrderTableRenderer-DJbpGqzT.js} +1 -1
  51. package/src/assets/web-panel/assets/{Organization-Cv1GYs-c.js → Organization-SQzIPdqC.js} +4 -4
  52. package/src/assets/web-panel/assets/{Overflow-Bbkp_PL3.js → Overflow-02yECh22.js} +1 -1
  53. package/src/assets/web-panel/assets/{P2P-BD8QUgoZ.js → P2P-BNg4pNCM.js} +2 -2
  54. package/src/assets/web-panel/assets/{PdhVaultBrowser-BO-2PeaB.js → PdhVaultBrowser-BxPJZsD3.js} +3 -3
  55. package/src/assets/web-panel/assets/{Permissions-D_OPVa02.js → Permissions-CLnDnPAz.js} +4 -4
  56. package/src/assets/web-panel/assets/{PersonalDataHub-mh-pEmaB.js → PersonalDataHub-C5m0AjGf.js} +4 -4
  57. package/src/assets/web-panel/assets/{Pipeline-6JC2EDdb.js → Pipeline-VwOf5Dhv.js} +1 -1
  58. package/src/assets/web-panel/assets/{Privacy-CUshzUAG.js → Privacy-CC0W2hZd.js} +1 -1
  59. package/src/assets/web-panel/assets/{ProjectInit-Cs2Aalri.js → ProjectInit-Dz893Bob.js} +2 -2
  60. package/src/assets/web-panel/assets/{ProjectSettings-1ak49tcj.js → ProjectSettings-CxQkvl0k.js} +2 -2
  61. package/src/assets/web-panel/assets/Projects-DDAjkUkT.js +1 -0
  62. package/src/assets/web-panel/assets/{Providers-CXXxvafH.js → Providers-DeB9IkxK.js} +1 -1
  63. package/src/assets/web-panel/assets/{QrScannerModal-PTcDsF58.js → QrScannerModal-OCeoaswn.js} +1 -1
  64. package/src/assets/web-panel/assets/{QuickAsk-CDwucrJw.js → QuickAsk-DenotaAj.js} +1 -1
  65. package/src/assets/web-panel/assets/{Recommend-CJlLVRXR.js → Recommend-Cies_jjI.js} +1 -1
  66. package/src/assets/web-panel/assets/{RemoteSession-DlN-ETsO.js → RemoteSession-Dxzl5n2T.js} +3 -3
  67. package/src/assets/web-panel/assets/{Reputation-DI23LR6m.js → Reputation-CW0mvxgZ.js} +1 -1
  68. package/src/assets/web-panel/assets/{Row-Cl7UQMrM.js → Row-SEd32qZU.js} +1 -1
  69. package/src/assets/web-panel/assets/{RssFeed-CexHNfh8.js → RssFeed-BSwnJ3Lm.js} +3 -3
  70. package/src/assets/web-panel/assets/{Search-BneBWvRN.js → Search-xe2m8bkC.js} +1 -1
  71. package/src/assets/web-panel/assets/{Security-DX7Phgrp.js → Security-Mq2F9Nro.js} +4 -4
  72. package/src/assets/web-panel/assets/{Services-BWXO8Mte.js → Services-BKGw2V3P.js} +2 -2
  73. package/src/assets/web-panel/assets/{Skeleton-DCyOjKPJ.js → Skeleton-DW95-Rxf.js} +1 -1
  74. package/src/assets/web-panel/assets/{Skills-CXqERsTB.js → Skills-CHgChCv_.js} +1 -1
  75. package/src/assets/web-panel/assets/{Sla-bhbrbz8E.js → Sla-tKh6k3R7.js} +1 -1
  76. package/src/assets/web-panel/assets/{SpeechSettings-3IPU0HBZ.js → SpeechSettings-D6UL3dA5.js} +1 -1
  77. package/src/assets/web-panel/assets/{SyncSettings-DBNTQLbM.js → SyncSettings-D0Fw8fVL.js} +2 -2
  78. package/src/assets/web-panel/assets/{Tasks-quP0bkN-.js → Tasks-20x1GB3D.js} +1 -1
  79. package/src/assets/web-panel/assets/{Templates-BouWmgho.js → Templates-DJ-lts-a.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tenant-qv0D9s7z.js → Tenant-BFdGpbs7.js} +1 -1
  81. package/src/assets/web-panel/assets/{Terminal-BxvbE8BB.js → Terminal-Xpx61vHL.js} +2 -2
  82. package/src/assets/web-panel/assets/{TimelineRenderer-D-IeLnJ2.js → TimelineRenderer-C6UIvyZQ.js} +1 -1
  83. package/src/assets/web-panel/assets/{Tokens-CFMKKyVG.js → Tokens-Dellq08f.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trigger-L8as3UuJ.js → Trigger-VKw8d0J-.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trust-MxmA4VZG.js → Trust-DNftdKT5.js} +1 -1
  86. package/src/assets/web-panel/assets/{UkeySign-C0VvJYRi.js → UkeySign-DX9VAKJI.js} +1 -1
  87. package/src/assets/web-panel/assets/{VideoEditing-Bf5QZj8N.js → VideoEditing-B2h3jO8q.js} +1 -1
  88. package/src/assets/web-panel/assets/{Wallet-BIJ9riRz.js → Wallet-CjGkof7f.js} +4 -4
  89. package/src/assets/web-panel/assets/{WebAuthn-B8p9Mhkw.js → WebAuthn-2Zfcu55P.js} +4 -4
  90. package/src/assets/web-panel/assets/{WorkflowEditor-BVsuaPen.js → WorkflowEditor-B9eZ8UxZ.js} +1 -1
  91. package/src/assets/web-panel/assets/{chat-BfkjoKpV.js → chat-CQNfD-YO.js} +1 -1
  92. package/src/assets/web-panel/assets/{colors-DeAlsWK8.js → colors-D4usyFT2.js} +1 -1
  93. package/src/assets/web-panel/assets/{compact-item-Cs97bz5j.js → compact-item-s4TpjvjX.js} +1 -1
  94. package/src/assets/web-panel/assets/{createContext-BqbG60LH.js → createContext-BRCSvYxj.js} +1 -1
  95. package/src/assets/web-panel/assets/devWarning-DKJjSWRn.js +1 -0
  96. package/src/assets/web-panel/assets/{hasIn-i_RY0b1X.js → hasIn-AdkUbkV-.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BOVkf1K3.js → index--00U6vXZ.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-B-3tEpTc.js → index-B2V-eKfK.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-D2B4VPyP.js → index-B4JJCfQ2.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-BkBi5TmC.js → index-BIoG5yYf.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-79V_zv1s.js → index-BMcimU-2.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-U4f5izHz.js → index-BPhkFZ1I.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DiSkx4UB.js → index-BQ3DXBtD.js} +3 -3
  104. package/src/assets/web-panel/assets/{index-dIHr4B_u.js → index-Bad4VNvz.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-CIG8fQ2_.js → index-BgiXR_-_.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DqBgBpgp.js → index-BtobShro.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-ZxO_-E8a.js → index-Bw2MEnUk.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DUUrv141.js → index-C1mJtE6q.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Bm7lLR4c.js → index-C484EJiS.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-COdGA-8n.js → index-C5KAQFPQ.js} +1 -1
  111. package/src/assets/web-panel/assets/index-C61cnl3K.js +1 -0
  112. package/src/assets/web-panel/assets/{index-CED2PL_y.js → index-C7Y8Aluc.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-YXgLng0K.js → index-CCsM_Ybx.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-0-agYlWL.js → index-CJCFe2Qf.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-B5UkyA3c.js → index-CJVEOa4i.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-B1CbOH1i.js → index-CJdQrZth.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-s1opAL-M.js → index-CKC1t3Ic.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-yObj1O4n.js → index-CQhAVU5t.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-CgsqdnRV.js → index-CYdoQsa1.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-Dk7-v4hP.js → index-Cduu2Hhr.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-B-JVTrpr.js → index-CkwiSLhU.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-CeWoNHau.js → index-Cvyt-zhm.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CE2VtTlp.js → index-D2GjI2oe.js} +1 -1
  124. package/src/assets/web-panel/assets/index-D4XFHxBr.js +1 -0
  125. package/src/assets/web-panel/assets/{index-DmbfhJUP.js → index-DARsAyUp.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-BESLFt4q.js → index-DVKfQ0Ux.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-PT_5sBMA.js → index-DZT36ZYq.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-gyFpvL7l.js → index-D_XBHopw.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-BYUVuwKt.js → index-DdCB70SS.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BcUXAB2s.js → index-DzRjHxEv.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-Dk2qouAz.js → index-MMN9V6JF.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-D9evtvg2.js → index-RfMr79MW.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-BuLQobzW.js → index-_IRVsV9X.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-Cf3WCLmy.js → index-nXyk8GZ9.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-CG3PRyAL.js → index-s_buFMEG.js} +1 -1
  136. package/src/assets/web-panel/assets/{initDefaultProps-C9h9yKL3.js → initDefaultProps-Blmpk7HL.js} +1 -1
  137. package/src/assets/web-panel/assets/{motion-BvmLsPdu.js → motion-DPBJMv1n.js} +1 -1
  138. package/src/assets/web-panel/assets/{move-CoL4ekU1.js → move-ButdzCM7.js} +1 -1
  139. package/src/assets/web-panel/assets/{mtc-parser-C4pMy6xV.js → mtc-parser-cyRC_QCe.js} +1 -1
  140. package/src/assets/web-panel/assets/{omit-DPuJfNxx.js → omit-1epSV7hz.js} +1 -1
  141. package/src/assets/web-panel/assets/{pickAttrs-D0KEeaK2.js → pickAttrs-DuPY8xJs.js} +1 -1
  142. package/src/assets/web-panel/assets/{placementArrow-BpkyINxt.js → placementArrow-6XZqarhe.js} +1 -1
  143. package/src/assets/web-panel/assets/{responsiveObserve-DQI_wOq8.js → responsiveObserve-B40pXBWM.js} +1 -1
  144. package/src/assets/web-panel/assets/{slide-DYfdDiRg.js → slide-jbZ9Wu4n.js} +1 -1
  145. package/src/assets/web-panel/assets/{statusUtils-B5dtvb0D.js → statusUtils-BKQQcVy4.js} +1 -1
  146. package/src/assets/web-panel/assets/{styleChecker-CF310mSj.js → styleChecker-NiKfWjUT.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFlexGapSupport-D1Qp4BLp.js → useFlexGapSupport-bQUCvPeb.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFs-C7_iyvJK.js → useFs-CUGji7ph.js} +1 -1
  149. package/src/assets/web-panel/assets/{usePersonalDataHub-DZUt_fIm.js → usePersonalDataHub-4veyN2N2.js} +1 -1
  150. package/src/assets/web-panel/assets/{vnode-D3dsi0lZ.js → vnode-1-nLug-Z.js} +1 -1
  151. package/src/assets/web-panel/assets/{zoom-WdbOlvdQ.js → zoom-dhCeRDMo.js} +1 -1
  152. package/src/assets/web-panel/index.html +1 -1
  153. package/src/command-help-index.json +6 -6
  154. package/src/commands/automation.js +103 -1
  155. package/src/commands/cowork.js +174 -19
  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/commands/team-merge-review.js +937 -0
  161. package/src/commands/team.js +2 -0
  162. package/src/data/changelog.json +27 -1
  163. package/src/gateways/ws/action-protocol.js +35 -10
  164. package/src/gateways/ws/remote-session-protocol.js +24 -1
  165. package/src/gateways/ws/ws-agent-handler.js +12 -0
  166. package/src/gateways/ws/ws-server.js +48 -12
  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 +1 -0
  170. package/src/harness/remote-session-crypto.js +210 -2
  171. package/src/harness/remote-session-registry.js +159 -6
  172. package/src/harness/session-list-index.js +233 -14
  173. package/src/lib/agent-authority.js +6 -0
  174. package/src/lib/agent-schedule-store.js +139 -28
  175. package/src/lib/agent-team/team-merge-review-store.js +765 -0
  176. package/src/lib/agent-team/team-merge-review-transaction.js +1223 -0
  177. package/src/lib/agent-team/team-merge-review.js +1847 -0
  178. package/src/lib/automation-center-incidents.js +314 -0
  179. package/src/lib/automation-center-runtime.js +448 -0
  180. package/src/lib/automation-center.js +182 -38
  181. package/src/lib/automation-engine.js +41 -0
  182. package/src/lib/automation-execution-authority.js +241 -12
  183. package/src/lib/automation-execution-incident.js +737 -0
  184. package/src/lib/background-agent-keeper-client.js +248 -0
  185. package/src/lib/background-agent-keeper-protocol.js +147 -0
  186. package/src/lib/background-agent-supervisor.js +520 -40
  187. package/src/lib/background-interaction-resolver.js +12 -0
  188. package/src/lib/background-turn-bootstrap-protocol.js +126 -0
  189. package/src/lib/cowork-cron.js +85 -14
  190. package/src/lib/cowork-workflow.js +336 -16
  191. package/src/lib/dynamic-workflow-facade.js +648 -0
  192. package/src/lib/execution-location-contract.js +551 -0
  193. package/src/lib/execution-location-runtime.js +130 -0
  194. package/src/lib/ide-context.js +94 -6
  195. package/src/lib/mcp-stdio-package-materialization.js +166 -14
  196. package/src/lib/packer/pkg-config-generator.js +2 -0
  197. package/src/lib/permission-authority.js +77 -0
  198. package/src/lib/permission-side-effect-center.js +495 -0
  199. package/src/lib/plugin-runtime/install.js +514 -13
  200. package/src/lib/plugin-runtime/marketplace-artifact-readback.js +900 -0
  201. package/src/lib/plugin-runtime/marketplace-catalog.js +1181 -0
  202. package/src/lib/plugin-runtime/marketplace-impact.js +408 -0
  203. package/src/lib/plugin-runtime/marketplace-remote-artifacts.js +1567 -0
  204. package/src/lib/plugin-security.js +60 -3
  205. package/src/lib/process-execution-broker/index.js +1095 -57
  206. package/src/lib/process-execution-broker/linux-bwrap-descriptor-launch.js +375 -0
  207. package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +90 -16
  208. package/src/lib/process-execution-broker/linux-generic-bwrap.js +159 -18
  209. package/src/lib/process-execution-broker/macos-mcp-launcher-contract.js +278 -0
  210. package/src/lib/process-execution-broker/macos-mcp-launcher-protocol.json +23 -0
  211. package/src/lib/process-execution-broker/macos-mcp-launcher.c +1497 -0
  212. package/src/lib/process-execution-broker/mcp-fd-entry-bootstrap.js +37 -0
  213. package/src/lib/process-execution-broker/platform-sandbox.js +2330 -279
  214. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  215. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  216. package/src/lib/process-execution-broker/windows-sandbox.cs +50 -4
  217. package/src/lib/public-ide-capability-manifest.js +3 -0
  218. package/src/lib/remote-approval-bridge.js +123 -17
  219. package/src/lib/remote-membership-authority.js +632 -0
  220. package/src/lib/remote-membership-coordinator.js +2409 -0
  221. package/src/lib/remote-membership-host-store.js +1750 -0
  222. package/src/lib/scheduler-kernel/agenda-adapter.js +17 -7
  223. package/src/lib/scheduler-kernel/automation-adapter.js +105 -11
  224. package/src/lib/scheduler-kernel/automation-event-adapter.js +87 -11
  225. package/src/lib/scheduler-kernel/contract.js +91 -0
  226. package/src/lib/scheduler-kernel/cowork-cron-adapter.js +12 -1
  227. package/src/lib/scheduler-kernel/loop-adapter.js +7 -1
  228. package/src/lib/scheduler-kernel/routine-adapter.js +7 -1
  229. package/src/lib/scheduler-kernel/runtime-control-capabilities.js +31 -0
  230. package/src/lib/scheduler-kernel/runtime.js +176 -3
  231. package/src/lib/scheduler-kernel/store.js +1253 -45
  232. package/src/lib/scoped-permission-store.js +369 -0
  233. package/src/lib/session-anti-rollback-anchor.js +262 -5
  234. package/src/lib/sub-agent-context.js +4 -0
  235. package/src/lib/workflow-definition-contract.js +149 -0
  236. package/src/repl/agent-repl.js +41 -7
  237. package/src/repl/chat-repl.js +2 -0
  238. package/src/repl/clipboard-image.js +735 -16
  239. package/src/repl/ide-status.js +1 -1
  240. package/src/repl/prompt-interactions.js +59 -6
  241. package/src/runtime/agent-core.js +93 -3
  242. package/src/runtime/headless-runner.js +30 -25
  243. package/src/runtime/headless-stream.js +32 -25
  244. package/src/runtime/mcp-config.js +81 -10
  245. package/src/workers/background-agent-keeper.js +498 -0
  246. package/src/workers/background-agent-worker.js +358 -13
  247. package/src/workers/background-turn-bootstrap.js +143 -0
  248. package/src/assets/web-panel/assets/MobileProjects-BWdOvQAj.js +0 -1
  249. package/src/assets/web-panel/assets/Projects-BV4oApsm.js +0 -1
  250. package/src/assets/web-panel/assets/devWarning-DPty0mGN.js +0 -1
  251. package/src/assets/web-panel/assets/index-Bt7g0Vq_.js +0 -1
  252. package/src/assets/web-panel/assets/index-ChVT0p9u.js +0 -1
@@ -0,0 +1,937 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { createHash } from "node:crypto";
5
+ import { getHomeDir } from "../lib/paths.js";
6
+ import { ensurePrivateDirectory } from "../lib/secure-fs.js";
7
+ import { redactSecrets } from "../lib/secret-scan.js";
8
+ import {
9
+ TEAM_MERGE_REVIEW_SCHEMA,
10
+ TEAM_MERGE_REVIEW_SCHEMA_VERSION,
11
+ buildMergeReview,
12
+ canonicalizeMergeReviewConflicts,
13
+ canonicalMergeReviewJson,
14
+ computeMergeReviewConflictsDigest,
15
+ digestMergeReview,
16
+ validateMergeReview,
17
+ } from "../lib/agent-team/team-merge-review.js";
18
+ import { TeamMergeReviewStore } from "../lib/agent-team/team-merge-review-store.js";
19
+ import {
20
+ bindMergeReviewInspection,
21
+ inspectMergeReviewRepository,
22
+ mergeReviewInputFromInspection,
23
+ prepareMergeReviewTransaction,
24
+ publishPreparedMergeReview,
25
+ readMergeReviewBaseState,
26
+ resolveMergeReviewRepositoryRoot,
27
+ rollbackPublishedMergeReview,
28
+ } from "../lib/agent-team/team-merge-review-transaction.js";
29
+
30
+ const DIGEST_PATTERN = /^sha256:[a-f0-9]{64}$/u;
31
+ const REVIEW_ID_PATTERN = /^tmr_[a-f0-9]{32}$/u;
32
+
33
+ export const _deps = {
34
+ buildMergeReview,
35
+ bindMergeReviewInspection,
36
+ inspectMergeReviewRepository,
37
+ mergeReviewInputFromInspection,
38
+ prepareMergeReviewTransaction,
39
+ publishPreparedMergeReview,
40
+ readMergeReviewBaseState,
41
+ resolveMergeReviewRepositoryRoot,
42
+ rollbackPublishedMergeReview,
43
+ createStore: (filePath) => new TeamMergeReviewStore({ filePath }),
44
+ ensurePrivateDirectory,
45
+ getHomeDir,
46
+ };
47
+
48
+ export class TeamMergeReviewCliError extends Error {
49
+ constructor(code, message, details = null, cause = null) {
50
+ super(message, cause ? { cause } : undefined);
51
+ this.name = "TeamMergeReviewCliError";
52
+ this.code = code;
53
+ if (details != null) this.details = details;
54
+ }
55
+ }
56
+
57
+ function fail(code, message, details = null, cause = null) {
58
+ throw new TeamMergeReviewCliError(code, message, details, cause);
59
+ }
60
+
61
+ function collect(value, previous = []) {
62
+ return [...previous, value];
63
+ }
64
+
65
+ function pathInside(child, root) {
66
+ const relative = path.relative(root, child);
67
+ return (
68
+ relative === "" ||
69
+ (!path.isAbsolute(relative) &&
70
+ relative !== ".." &&
71
+ !relative.startsWith(`..${path.sep}`))
72
+ );
73
+ }
74
+
75
+ function normalizeForIdentity(value) {
76
+ const resolved = path.resolve(value);
77
+ return process.platform === "win32" ? resolved.toLowerCase() : resolved;
78
+ }
79
+
80
+ function repoStoreName(repoRoot) {
81
+ return `reviews-${createHash("sha256")
82
+ .update(normalizeForIdentity(repoRoot), "utf8")
83
+ .digest("hex")
84
+ .slice(0, 32)}.jsonl`;
85
+ }
86
+
87
+ export function resolveTeamMergeReviewState(
88
+ { stateDir = null, repoDir = process.cwd() } = {},
89
+ dependencies = _deps,
90
+ ) {
91
+ const repoRoot = dependencies.resolveMergeReviewRepositoryRoot(repoDir);
92
+ const requested = path.resolve(
93
+ stateDir || path.join(dependencies.getHomeDir(), "team-merge-reviews"),
94
+ );
95
+ if (pathInside(requested, repoRoot)) {
96
+ fail(
97
+ "TEAM_MERGE_REVIEW_STATE_UNSAFE",
98
+ "merge-review state must be outside the agent-writable repository",
99
+ );
100
+ }
101
+ dependencies.ensurePrivateDirectory(requested, {
102
+ applyWindowsAcl: true,
103
+ failIfUnavailable: true,
104
+ });
105
+ const canonicalStateDir = fs.realpathSync.native(requested);
106
+ if (pathInside(canonicalStateDir, repoRoot)) {
107
+ fail(
108
+ "TEAM_MERGE_REVIEW_STATE_UNSAFE",
109
+ "merge-review state resolves inside the agent-writable repository",
110
+ );
111
+ }
112
+ const filePath = path.join(canonicalStateDir, repoStoreName(repoRoot));
113
+ return {
114
+ repoRoot,
115
+ stateDir: canonicalStateDir,
116
+ actionStateDir: stateDir == null ? null : String(stateDir),
117
+ filePath,
118
+ store: dependencies.createStore(filePath),
119
+ };
120
+ }
121
+
122
+ function expectedRevision(value) {
123
+ const revision = Number(value);
124
+ if (!Number.isSafeInteger(revision) || revision < 0) {
125
+ fail(
126
+ "TEAM_MERGE_REVIEW_INVALID_REVISION",
127
+ "--revision must be a non-negative integer",
128
+ );
129
+ }
130
+ return revision;
131
+ }
132
+
133
+ function expectedDigest(value, label) {
134
+ const digest = String(value || "").toLowerCase();
135
+ if (!DIGEST_PATTERN.test(digest)) {
136
+ fail("TEAM_MERGE_REVIEW_INVALID_DIGEST", `${label} must be sha256:<hex>`);
137
+ }
138
+ return digest;
139
+ }
140
+
141
+ function reviewId(value) {
142
+ const id = String(value || "").toLowerCase();
143
+ if (!REVIEW_ID_PATTERN.test(id)) {
144
+ fail("TEAM_MERGE_REVIEW_INVALID_ID", "merge-review ID is invalid");
145
+ }
146
+ return id;
147
+ }
148
+
149
+ function requireStoredReview(store, id) {
150
+ const review = store.get(reviewId(id));
151
+ if (!review) {
152
+ fail("TEAM_MERGE_REVIEW_NOT_FOUND", `merge-review not found: ${id}`);
153
+ }
154
+ return validateMergeReview(review);
155
+ }
156
+
157
+ function assertRequestBinding(review, options) {
158
+ const revision = expectedRevision(options.revision);
159
+ const planDigest = expectedDigest(options.planDigest, "--plan-digest");
160
+ if (review.revision + 1 !== revision) {
161
+ fail(
162
+ "TEAM_MERGE_REVIEW_STALE",
163
+ `merge-review revision ${revision} is stale; current revision is ${review.revision + 1}`,
164
+ );
165
+ }
166
+ if (review.planDigest !== planDigest) {
167
+ fail(
168
+ "TEAM_MERGE_REVIEW_PLAN_STALE",
169
+ "--plan-digest does not bind the stored review",
170
+ );
171
+ }
172
+ }
173
+
174
+ function sameSelection(decision, fileIds, hunkIds) {
175
+ if (!decision) return false;
176
+ const sameSet = (left, right) => {
177
+ const leftSet = new Set(left);
178
+ const rightSet = new Set(right);
179
+ return (
180
+ left.length === right.length &&
181
+ leftSet.size === left.length &&
182
+ rightSet.size === right.length &&
183
+ leftSet.size === rightSet.size &&
184
+ [...leftSet].every((value) => rightSet.has(value))
185
+ );
186
+ };
187
+ return (
188
+ sameSet(decision.selectedFileIds, fileIds) &&
189
+ sameSet(decision.selectedHunkIds, hunkIds)
190
+ );
191
+ }
192
+
193
+ function decisionActor(value) {
194
+ const actor = String(value || "").trim();
195
+ if (!/^[A-Za-z0-9][A-Za-z0-9._:-]{0,159}$/u.test(actor)) {
196
+ fail(
197
+ "TEAM_MERGE_REVIEW_INVALID_ACTOR",
198
+ "merge-review actor must be a stable 1..160 character identifier",
199
+ );
200
+ }
201
+ return actor;
202
+ }
203
+
204
+ function decisionReason(value) {
205
+ const reason = String(value || "").trim();
206
+ if (!reason || reason.length > 500 || /[\0\r\n]/u.test(reason)) {
207
+ fail(
208
+ "TEAM_MERGE_REVIEW_INVALID_REASON",
209
+ "merge-review reason must be one line of at most 500 characters",
210
+ );
211
+ }
212
+ return reason;
213
+ }
214
+
215
+ function transitionEvidence(review, operation, evidence = {}) {
216
+ return digestMergeReview("cc-team-merge-review-transition-evidence-v1", {
217
+ reviewId: review.reviewId,
218
+ revision: review.revision,
219
+ state: review.state,
220
+ operation,
221
+ evidence,
222
+ });
223
+ }
224
+
225
+ function stateArgs(stateDir) {
226
+ return stateDir == null ? ["--json"] : ["--state-dir", stateDir, "--json"];
227
+ }
228
+
229
+ function applyArgv(review, stateDir) {
230
+ if (!review.decision) return [];
231
+ const argv = [
232
+ "team",
233
+ "merge-review",
234
+ "apply",
235
+ review.reviewId,
236
+ "--revision",
237
+ String(review.revision + 1),
238
+ "--plan-digest",
239
+ review.planDigest,
240
+ ];
241
+ if (stateDir != null) argv.push("--state-dir", stateDir);
242
+ for (const id of review.decision.selectedFileIds) {
243
+ argv.push("--file-id", id);
244
+ }
245
+ for (const id of review.decision.selectedHunkIds) {
246
+ argv.push("--hunk-id", id);
247
+ }
248
+ argv.push(
249
+ "--actor",
250
+ review.decision.actor,
251
+ "--reason",
252
+ review.decision.reason,
253
+ );
254
+ argv.push("--json");
255
+ return argv;
256
+ }
257
+
258
+ function actionsFor(review, stateDir) {
259
+ const actions = [
260
+ {
261
+ id: "show",
262
+ enabled: true,
263
+ argv: [
264
+ "team",
265
+ "merge-review",
266
+ "show",
267
+ review.reviewId,
268
+ ...stateArgs(stateDir),
269
+ ],
270
+ reason: null,
271
+ },
272
+ ];
273
+ const resumable = ["planned", "prepared", "publishing"].includes(
274
+ review.state,
275
+ );
276
+ actions.push({
277
+ id: "apply",
278
+ enabled: resumable && review.decision != null,
279
+ argv: resumable
280
+ ? review.decision
281
+ ? applyArgv(review, stateDir)
282
+ : ["team", "merge-review", "apply", review.reviewId]
283
+ : ["team", "merge-review", "apply", review.reviewId],
284
+ reason:
285
+ resumable && review.decision == null
286
+ ? "Select at least one reviewed file or hunk first."
287
+ : resumable
288
+ ? null
289
+ : `Review state ${review.state} cannot be applied.`,
290
+ });
291
+ const rollbackEnabled = [
292
+ "published",
293
+ "conflicted",
294
+ "rollback_required",
295
+ ].includes(review.state);
296
+ actions.push({
297
+ id: "rollback",
298
+ enabled: rollbackEnabled,
299
+ argv: rollbackEnabled
300
+ ? [
301
+ "team",
302
+ "merge-review",
303
+ "rollback",
304
+ review.reviewId,
305
+ "--revision",
306
+ String(review.revision + 1),
307
+ "--evidence-digest",
308
+ review.evidenceDigest,
309
+ "--confirm",
310
+ review.reviewId,
311
+ ...stateArgs(stateDir),
312
+ ]
313
+ : ["team", "merge-review", "rollback", review.reviewId],
314
+ reason: rollbackEnabled
315
+ ? null
316
+ : `Review state ${review.state} has no controlled rollback action.`,
317
+ });
318
+ return actions;
319
+ }
320
+
321
+ function projectedConflict(conflict) {
322
+ return {
323
+ candidateKey: conflict.candidateKey,
324
+ path: conflict.path,
325
+ type: conflict.type,
326
+ explanation: conflict.explanation,
327
+ suggestion: conflict.suggestion ?? null,
328
+ hunkIds: [...(conflict.hunkIds || [])],
329
+ };
330
+ }
331
+
332
+ function projectedReview(review, conflicts = review.conflicts || []) {
333
+ const selectedFileIds = review.decision?.selectedFileIds || [];
334
+ const selectedHunkIds = review.decision?.selectedHunkIds || [];
335
+ const selectedFiles = new Set(selectedFileIds);
336
+ const selectedHunks = new Set(selectedHunkIds);
337
+ return {
338
+ reviewId: review.reviewId,
339
+ revision: review.revision + 1,
340
+ state: review.state,
341
+ base: { branch: review.base.branch, oid: review.base.commitOid },
342
+ candidates: review.candidates.map((candidate) => ({
343
+ key: candidate.key,
344
+ branch: candidate.branch,
345
+ oid: candidate.commitOid,
346
+ })),
347
+ files: review.files.map((file) => ({
348
+ id: file.id,
349
+ candidateKey: file.candidateKey,
350
+ path: file.path,
351
+ status: file.status,
352
+ binary: file.binary,
353
+ selected: selectedFiles.has(file.id),
354
+ hunks: file.hunks.map((hunk) => ({
355
+ id: hunk.id,
356
+ header:
357
+ `@@ -${hunk.oldStart},${hunk.oldLines} ` +
358
+ `+${hunk.newStart},${hunk.newLines} @@`,
359
+ oldStart: hunk.oldStart,
360
+ oldLines: hunk.oldLines,
361
+ newStart: hunk.newStart,
362
+ newLines: hunk.newLines,
363
+ selected: selectedHunks.has(hunk.id),
364
+ })),
365
+ })),
366
+ selection: {
367
+ fileIds: [...selectedFileIds],
368
+ hunkIds: [...selectedHunkIds],
369
+ },
370
+ conflicts: conflicts.map(projectedConflict),
371
+ decision: review.decision
372
+ ? {
373
+ actor: review.decision.actor,
374
+ reason: review.decision.reason,
375
+ host: review.decision.host,
376
+ decidedAt: review.decision.decidedAt,
377
+ }
378
+ : null,
379
+ planDigest: review.planDigest,
380
+ evidenceDigest: review.evidenceDigest,
381
+ createdAt: review.createdAt,
382
+ updatedAt: review.updatedAt,
383
+ details: {},
384
+ };
385
+ }
386
+
387
+ function envelope(operation, review, stateDir, extra = {}) {
388
+ const conflicts = extra.conflicts ?? review.conflicts ?? [];
389
+ return {
390
+ schema: TEAM_MERGE_REVIEW_SCHEMA,
391
+ schemaVersion: TEAM_MERGE_REVIEW_SCHEMA_VERSION,
392
+ operation,
393
+ review: projectedReview(validateMergeReview(review), conflicts),
394
+ actions: actionsFor(review, stateDir),
395
+ };
396
+ }
397
+
398
+ function inspectExactReview(review, repoRoot, dependencies) {
399
+ const inspection = dependencies.inspectMergeReviewRepository({
400
+ repoDir: repoRoot,
401
+ baseBranch: review.base.branch,
402
+ branches: review.candidates.map((candidate) => candidate.branch),
403
+ keys: review.candidates.map((candidate) => candidate.key),
404
+ });
405
+ const rebuilt = dependencies.buildMergeReview({
406
+ ...dependencies.mergeReviewInputFromInspection(inspection),
407
+ createdAt: review.createdAt,
408
+ });
409
+ if (
410
+ rebuilt.reviewId !== review.reviewId ||
411
+ rebuilt.planDigest !== review.planDigest ||
412
+ canonicalMergeReviewJson(rebuilt.files) !==
413
+ canonicalMergeReviewJson(review.files)
414
+ ) {
415
+ fail(
416
+ "TEAM_MERGE_REVIEW_PLAN_STALE",
417
+ "candidate/base Git evidence changed after preview",
418
+ );
419
+ }
420
+ return dependencies.bindMergeReviewInspection(inspection, review);
421
+ }
422
+
423
+ export function previewTeamMergeReview(
424
+ {
425
+ branches,
426
+ base = null,
427
+ stateDir = null,
428
+ repoDir = process.cwd(),
429
+ createdAt = null,
430
+ } = {},
431
+ dependencies = _deps,
432
+ ) {
433
+ const context = resolveTeamMergeReviewState(
434
+ { stateDir, repoDir },
435
+ dependencies,
436
+ );
437
+ const inspection = dependencies.inspectMergeReviewRepository({
438
+ repoDir: context.repoRoot,
439
+ baseBranch: base,
440
+ branches,
441
+ });
442
+ const review = dependencies.buildMergeReview({
443
+ ...dependencies.mergeReviewInputFromInspection(inspection),
444
+ ...(createdAt ? { createdAt } : {}),
445
+ });
446
+ const persisted = context.store.create(review).review;
447
+ return envelope("preview", persisted, context.actionStateDir);
448
+ }
449
+
450
+ export function showTeamMergeReview(
451
+ { id, stateDir = null, repoDir = process.cwd() } = {},
452
+ dependencies = _deps,
453
+ ) {
454
+ const context = resolveTeamMergeReviewState(
455
+ { stateDir, repoDir },
456
+ dependencies,
457
+ );
458
+ const review = requireStoredReview(context.store, id);
459
+ return envelope("show", review, context.actionStateDir);
460
+ }
461
+
462
+ function transitionToRollbackRequired(store, review, reason) {
463
+ if (review.state === "rollback_required") return review;
464
+ const evidence = transitionEvidence(review, "rollback-required", { reason });
465
+ return store.transition(review.reviewId, {
466
+ expectedRevision: review.revision,
467
+ to: "rollback_required",
468
+ transitionEvidenceDigest: evidence,
469
+ }).review;
470
+ }
471
+
472
+ function publishPreparedReview(context, review, dependencies) {
473
+ if (review.state === "prepared") {
474
+ review = context.store.transition(review.reviewId, {
475
+ expectedRevision: review.revision,
476
+ to: "publishing",
477
+ transitionEvidenceDigest: transitionEvidence(review, "publishing", {
478
+ preparedOid: review.settlement.preparedOid,
479
+ }),
480
+ }).review;
481
+ }
482
+ const preparedOid = review.settlement.preparedOid;
483
+ const repository = dependencies.readMergeReviewBaseState({
484
+ repoDir: context.repoRoot,
485
+ branch: review.base.branch,
486
+ });
487
+ if (repository.currentBranch !== review.base.branch) {
488
+ const current = transitionToRollbackRequired(
489
+ context.store,
490
+ review,
491
+ "base branch checkout changed before publish",
492
+ );
493
+ const error = new TeamMergeReviewCliError(
494
+ "TEAM_MERGE_REVIEW_PUBLISH_STALE",
495
+ "checked-out branch changed before reviewed publish",
496
+ { review: current },
497
+ );
498
+ throw error;
499
+ }
500
+ if (![review.base.commitOid, preparedOid].includes(repository.oid)) {
501
+ const current = transitionToRollbackRequired(
502
+ context.store,
503
+ review,
504
+ "base branch advanced outside reviewed transaction",
505
+ );
506
+ throw new TeamMergeReviewCliError(
507
+ "TEAM_MERGE_REVIEW_PUBLISH_STALE",
508
+ "base branch advanced outside the reviewed transaction",
509
+ { review: current },
510
+ );
511
+ }
512
+ if (repository.oid === preparedOid && repository.dirty) {
513
+ const current = transitionToRollbackRequired(
514
+ context.store,
515
+ review,
516
+ "published ref has an unclean or incomplete worktree",
517
+ );
518
+ throw new TeamMergeReviewCliError(
519
+ "TEAM_MERGE_REVIEW_PUBLISH_AMBIGUOUS",
520
+ "reviewed commit reached the base ref, but the worktree is not clean",
521
+ { review: current },
522
+ );
523
+ }
524
+ if (repository.oid === review.base.commitOid) {
525
+ try {
526
+ dependencies.publishPreparedMergeReview({
527
+ inspection: {
528
+ repoRoot: context.repoRoot,
529
+ base: { branch: review.base.branch, oid: review.base.commitOid },
530
+ },
531
+ prepared: {
532
+ success: true,
533
+ state: "prepared",
534
+ resultOid: preparedOid,
535
+ },
536
+ });
537
+ } catch (cause) {
538
+ const current = transitionToRollbackRequired(
539
+ context.store,
540
+ review,
541
+ "reviewed fast-forward publish failed or became ambiguous",
542
+ );
543
+ throw new TeamMergeReviewCliError(
544
+ "TEAM_MERGE_REVIEW_PUBLISH_FAILED",
545
+ redactSecrets(cause?.message || "reviewed publish failed"),
546
+ { review: current },
547
+ cause,
548
+ );
549
+ }
550
+ }
551
+ return context.store.transition(review.reviewId, {
552
+ expectedRevision: review.revision,
553
+ to: "published",
554
+ publishedOid: preparedOid,
555
+ transitionEvidenceDigest: transitionEvidence(review, "published", {
556
+ baseOid: review.base.commitOid,
557
+ publishedOid: preparedOid,
558
+ }),
559
+ }).review;
560
+ }
561
+
562
+ export function applyTeamMergeReview(
563
+ {
564
+ id,
565
+ revision,
566
+ planDigest,
567
+ fileIds = [],
568
+ hunkIds = [],
569
+ actor = "local-operator",
570
+ reason = "reviewed multi-agent merge",
571
+ stateDir = null,
572
+ repoDir = process.cwd(),
573
+ } = {},
574
+ dependencies = _deps,
575
+ ) {
576
+ const context = resolveTeamMergeReviewState(
577
+ { stateDir, repoDir },
578
+ dependencies,
579
+ );
580
+ let review = requireStoredReview(context.store, id);
581
+ assertRequestBinding(review, { revision, planDigest });
582
+ if (review.state === "published") {
583
+ return envelope("apply", review, context.actionStateDir);
584
+ }
585
+ if (!["planned", "prepared", "publishing"].includes(review.state)) {
586
+ fail(
587
+ "TEAM_MERGE_REVIEW_STATE_INVALID",
588
+ `merge-review state ${review.state} cannot be applied`,
589
+ );
590
+ }
591
+ if (review.decision) {
592
+ if (!sameSelection(review.decision, fileIds, hunkIds)) {
593
+ fail(
594
+ "TEAM_MERGE_REVIEW_DECISION_IMMUTABLE",
595
+ "requested selection differs from the persisted decision",
596
+ );
597
+ }
598
+ } else {
599
+ review = context.store.decide(review.reviewId, {
600
+ expectedRevision: review.revision,
601
+ actor: decisionActor(actor),
602
+ reason: decisionReason(reason),
603
+ host: os.hostname().slice(0, 256) || "local-host",
604
+ selectedFileIds: fileIds,
605
+ selectedHunkIds: hunkIds,
606
+ }).review;
607
+ }
608
+ if (review.state === "planned") {
609
+ const inspection = inspectExactReview(
610
+ review,
611
+ context.repoRoot,
612
+ dependencies,
613
+ );
614
+ const prepared = dependencies.prepareMergeReviewTransaction({
615
+ inspection,
616
+ fileIds: review.decision.selectedFileIds,
617
+ hunkIds: review.decision.selectedHunkIds,
618
+ reviewId: review.reviewId,
619
+ stateDir: context.stateDir,
620
+ actor: review.decision.actor,
621
+ reason: review.decision.reason,
622
+ decidedAt: review.updatedAt,
623
+ });
624
+ if (!prepared.success) {
625
+ const durableConflicts = canonicalizeMergeReviewConflicts(
626
+ review,
627
+ prepared.conflicts.map(projectedConflict),
628
+ );
629
+ const conflictDigest =
630
+ computeMergeReviewConflictsDigest(durableConflicts);
631
+ review = context.store.transition(review.reviewId, {
632
+ expectedRevision: review.revision,
633
+ to: "conflicted",
634
+ conflicts: durableConflicts,
635
+ conflictDigest,
636
+ transitionEvidenceDigest: transitionEvidence(review, "conflicted", {
637
+ conflictDigest,
638
+ selection: prepared.selection,
639
+ }),
640
+ }).review;
641
+ return envelope("apply", review, context.actionStateDir);
642
+ }
643
+ review = context.store.transition(review.reviewId, {
644
+ expectedRevision: review.revision,
645
+ to: "prepared",
646
+ preparedOid: prepared.resultOid,
647
+ transitionEvidenceDigest: transitionEvidence(review, "prepared", {
648
+ resultOid: prepared.resultOid,
649
+ selection: prepared.selection,
650
+ }),
651
+ }).review;
652
+ }
653
+ review = publishPreparedReview(context, review, dependencies);
654
+ return envelope("apply", review, context.actionStateDir);
655
+ }
656
+
657
+ export function rollbackTeamMergeReview(
658
+ {
659
+ id,
660
+ revision,
661
+ evidenceDigest,
662
+ confirm,
663
+ stateDir = null,
664
+ repoDir = process.cwd(),
665
+ } = {},
666
+ dependencies = _deps,
667
+ ) {
668
+ const context = resolveTeamMergeReviewState(
669
+ { stateDir, repoDir },
670
+ dependencies,
671
+ );
672
+ let review = requireStoredReview(context.store, id);
673
+ const requestedRevision = expectedRevision(revision);
674
+ const requestedEvidence = expectedDigest(evidenceDigest, "--evidence-digest");
675
+ if (
676
+ confirm !== review.reviewId ||
677
+ review.revision + 1 !== requestedRevision ||
678
+ review.evidenceDigest !== requestedEvidence
679
+ ) {
680
+ fail(
681
+ "TEAM_MERGE_REVIEW_ROLLBACK_STALE",
682
+ "controlled rollback confirmation, revision, or evidence is stale",
683
+ );
684
+ }
685
+ if (review.state === "rolled_back") {
686
+ return envelope("rollback", review, context.actionStateDir);
687
+ }
688
+ if (
689
+ ![
690
+ "prepared",
691
+ "publishing",
692
+ "published",
693
+ "conflicted",
694
+ "rollback_required",
695
+ ].includes(review.state)
696
+ ) {
697
+ fail(
698
+ "TEAM_MERGE_REVIEW_STATE_INVALID",
699
+ `merge-review state ${review.state} cannot be rolled back`,
700
+ );
701
+ }
702
+ if (review.state === "conflicted") {
703
+ review = context.store.transition(review.reviewId, {
704
+ expectedRevision: review.revision,
705
+ to: "rolled_back",
706
+ rollbackOid: review.base.commitOid,
707
+ transitionEvidenceDigest: transitionEvidence(
708
+ review,
709
+ "conflict-dismissed",
710
+ { baseOid: review.base.commitOid },
711
+ ),
712
+ }).review;
713
+ return envelope("rollback", review, context.actionStateDir);
714
+ }
715
+ review = transitionToRollbackRequired(
716
+ context.store,
717
+ review,
718
+ "operator authorized controlled rollback",
719
+ );
720
+ const repository = dependencies.readMergeReviewBaseState({
721
+ repoDir: context.repoRoot,
722
+ branch: review.base.branch,
723
+ });
724
+ const resultOid =
725
+ review.settlement.publishedOid || review.settlement.preparedOid;
726
+ if (repository.currentBranch !== review.base.branch) {
727
+ fail(
728
+ "TEAM_MERGE_REVIEW_ROLLBACK_STALE",
729
+ "controlled rollback refused because the base branch advanced or changed",
730
+ );
731
+ }
732
+ let rollbackOid = review.base.commitOid;
733
+ if (repository.oid === review.base.commitOid) {
734
+ if (repository.dirty) {
735
+ fail(
736
+ "TEAM_MERGE_REVIEW_ROLLBACK_DIRTY",
737
+ "controlled rollback cannot settle an unclean base worktree",
738
+ );
739
+ }
740
+ } else {
741
+ const rollback = dependencies.rollbackPublishedMergeReview({
742
+ repoDir: context.repoRoot,
743
+ base: { branch: review.base.branch, oid: review.base.commitOid },
744
+ resultOid,
745
+ reviewId: review.reviewId,
746
+ decidedAt: review.updatedAt,
747
+ actor: review.decision?.actor || "local-operator",
748
+ reason: "operator authorized controlled merge-review rollback",
749
+ evidenceDigest: review.evidenceDigest,
750
+ expectedEvidenceDigest: review.evidenceDigest,
751
+ });
752
+ rollbackOid = rollback.rollbackOid;
753
+ }
754
+ review = context.store.transition(review.reviewId, {
755
+ expectedRevision: review.revision,
756
+ to: "rolled_back",
757
+ rollbackOid,
758
+ transitionEvidenceDigest: transitionEvidence(review, "rolled-back", {
759
+ baseOid: review.base.commitOid,
760
+ publishedOid: resultOid,
761
+ rollbackOid,
762
+ }),
763
+ }).review;
764
+ return envelope("rollback", review, context.actionStateDir);
765
+ }
766
+
767
+ function printResult(result, { json = false, logger = console } = {}) {
768
+ if (json) {
769
+ (logger.log || console.log)(JSON.stringify(result, null, 2));
770
+ return;
771
+ }
772
+ const review = result.review;
773
+ (logger.log || console.log)(
774
+ `${result.operation}: ${review.reviewId} r${review.revision} ${review.state}`,
775
+ );
776
+ (logger.log || console.log)(
777
+ `base ${review.base.branch}@${review.base.oid.slice(0, 12)}; ` +
778
+ `${review.candidates.length} branch(es), ${review.files.length} file(s)`,
779
+ );
780
+ for (const conflict of result.review.conflicts || []) {
781
+ (logger.warn || console.warn)(
782
+ `conflict ${conflict.path}: ${conflict.explanation}`,
783
+ );
784
+ }
785
+ }
786
+
787
+ function handleAction(operation, options, callback, logger) {
788
+ try {
789
+ const result = callback();
790
+ printResult(result, { json: options.json === true, logger });
791
+ } catch (error) {
792
+ const message = redactSecrets(error?.message || String(error)).slice(
793
+ 0,
794
+ 4096,
795
+ );
796
+ if (options.json === true) {
797
+ (logger.log || console.log)(
798
+ JSON.stringify({
799
+ schema: TEAM_MERGE_REVIEW_SCHEMA,
800
+ schemaVersion: TEAM_MERGE_REVIEW_SCHEMA_VERSION,
801
+ operation,
802
+ error: {
803
+ code: error?.code || "TEAM_MERGE_REVIEW_FAILED",
804
+ message,
805
+ },
806
+ }),
807
+ );
808
+ } else {
809
+ (logger.error || console.error)(message);
810
+ }
811
+ process.exitCode = 1;
812
+ }
813
+ }
814
+
815
+ export function registerTeamMergeReviewCommands(
816
+ team,
817
+ { logger = console, dependencies = _deps } = {},
818
+ ) {
819
+ const mergeReview = team
820
+ .command("merge-review")
821
+ .description(
822
+ "Review, atomically publish, and safely roll back multi-agent branches",
823
+ );
824
+
825
+ mergeReview
826
+ .command("preview")
827
+ .description("Create an exact-base file/hunk selection review")
828
+ .requiredOption(
829
+ "--branch <name>",
830
+ "Candidate branch (repeatable)",
831
+ collect,
832
+ [],
833
+ )
834
+ .option("--base <branch>", "Base branch (defaults to current branch)")
835
+ .option("--state-dir <dir>", "External owner-only review state directory")
836
+ .option("--actor <id>", "Reserved operator identity for IDE callers")
837
+ .option("--reason <text>", "Reserved review reason for IDE callers")
838
+ .option("--json", "Output the strict v1 envelope")
839
+ .action((options) =>
840
+ handleAction(
841
+ "preview",
842
+ options,
843
+ () =>
844
+ previewTeamMergeReview(
845
+ {
846
+ branches: options.branch,
847
+ base: options.base,
848
+ stateDir: options.stateDir,
849
+ },
850
+ dependencies,
851
+ ),
852
+ logger,
853
+ ),
854
+ );
855
+
856
+ mergeReview
857
+ .command("show <review-id>")
858
+ .description("Show one persisted merge review and its exact next actions")
859
+ .option("--state-dir <dir>", "External owner-only review state directory")
860
+ .option("--json", "Output the strict v1 envelope")
861
+ .action((id, options) =>
862
+ handleAction(
863
+ "show",
864
+ options,
865
+ () =>
866
+ showTeamMergeReview({ id, stateDir: options.stateDir }, dependencies),
867
+ logger,
868
+ ),
869
+ );
870
+
871
+ mergeReview
872
+ .command("apply <review-id>")
873
+ .description("Prepare and publish one exact reviewed selection atomically")
874
+ .requiredOption("--revision <n>", "Exact review revision")
875
+ .requiredOption("--plan-digest <digest>", "Exact reviewed plan digest")
876
+ .option("--file-id <id>", "Select a whole file (repeatable)", collect, [])
877
+ .option("--hunk-id <id>", "Select a text hunk (repeatable)", collect, [])
878
+ .option("--actor <id>", "Decision actor", "local-operator")
879
+ .option("--reason <text>", "Decision reason", "reviewed multi-agent merge")
880
+ .option("--state-dir <dir>", "External owner-only review state directory")
881
+ .option("--json", "Output the strict v1 envelope")
882
+ .action((id, options) =>
883
+ handleAction(
884
+ "apply",
885
+ options,
886
+ () =>
887
+ applyTeamMergeReview(
888
+ {
889
+ id,
890
+ revision: options.revision,
891
+ planDigest: options.planDigest,
892
+ fileIds: options.fileId,
893
+ hunkIds: options.hunkId,
894
+ actor: options.actor,
895
+ reason: options.reason,
896
+ stateDir: options.stateDir,
897
+ },
898
+ dependencies,
899
+ ),
900
+ logger,
901
+ ),
902
+ );
903
+
904
+ mergeReview
905
+ .command("rollback <review-id>")
906
+ .description(
907
+ "Restore the exact pre-publish base under revision/evidence CAS",
908
+ )
909
+ .requiredOption("--revision <n>", "Exact review revision")
910
+ .requiredOption(
911
+ "--evidence-digest <digest>",
912
+ "Exact current evidence digest",
913
+ )
914
+ .requiredOption("--confirm <review-id>", "Repeat the exact review ID")
915
+ .option("--state-dir <dir>", "External owner-only review state directory")
916
+ .option("--json", "Output the strict v1 envelope")
917
+ .action((id, options) =>
918
+ handleAction(
919
+ "rollback",
920
+ options,
921
+ () =>
922
+ rollbackTeamMergeReview(
923
+ {
924
+ id,
925
+ revision: options.revision,
926
+ evidenceDigest: options.evidenceDigest,
927
+ confirm: options.confirm,
928
+ stateDir: options.stateDir,
929
+ },
930
+ dependencies,
931
+ ),
932
+ logger,
933
+ ),
934
+ );
935
+
936
+ return mergeReview;
937
+ }