chainlesschain 0.162.183 → 0.162.184

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 (196) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/.build-hash +1 -1
  3. package/src/assets/web-panel/assets/{AIOps-BapS7lz4.js → AIOps-DzAl5fGx.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-CXYdXEUI.js → ActionButton-DAHtMGeC.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-CKR5Lexn.js → Analytics-BHQaexv5.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-DATVUOXB.js → AppLayout-Phz_pD0n.js} +4 -4
  7. package/src/assets/web-panel/assets/{Artifacts-vb_0ZlV1.js → Artifacts-DHt47kCA.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-BI1l9GWt.js → Audit--Y_8FULl.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-BFXbaUEf.js → BackgroundAgents-N1zchH7D.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-DEYBJJ6H.js → Backup-B_BoyN30.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-COdzeO0M.js → BaseInput-Gl4uQHcT.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-oSN6sfM5.js → Chat-Cg-eIyAZ.js} +6 -6
  13. package/src/assets/web-panel/assets/ChatBubbleRenderer-BzeUi3JH.js +1 -0
  14. package/src/assets/web-panel/assets/{Checkbox-BezEa4tm.js → Checkbox-D0MGR2wA.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-CNEL0Ife.js → Codegen-BdObJEFn.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-Bf2Y2Bn1.js → Col--ghxXT3z.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-BfUlu4Hc.js → Community-BUFeXOqz.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-BN4xWP9e.js → Compact-DhQO2_Mr.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-Bt6BKmEP.js → Compliance-3HoTqKYd.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-DKLp8YxO.js → Cowork-B3zmO4VW.js} +3 -3
  21. package/src/assets/web-panel/assets/{Cron-o7Hhw6ky.js → Cron-CJDrZOcc.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-DaNXWJIw.js → Crosschain-SMl15obd.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-B-Qa2mha.js → DID-CgTrTWrl.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-CMX0Qnxw.js → Dashboard-dXFKaKol.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-BLuLyRu_.js → Dropdown-qQHEhCvI.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-CFBAeMij.js → EmailListRenderer-C_ej0MWH.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DWzXQ67V.js → FamilyGuardDashboard-D6ajoE7I.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-DB1QSLgr.js → Federation-Cio2y49h.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-C-OKCToP.js → FormItemContext-ClJz1cYp.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-DMJFtFZf.js → GenericCardRenderer-Dr_8Maca.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-DsGSujOV.js → Git-CevLwp5u.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-B0iS9NEW.js → Governance-CW9YyQUY.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-CH004H7c.js → Inference-CQqeAyER.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-Q9MTQ83c.js → KnowledgeGraph-cuGVxHrw.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-B_fyjZK9.js → Logs-DIuHri5d.js} +2 -2
  36. package/src/assets/web-panel/assets/{MarkdownRenderer-C0o4FtpD.js → MarkdownRenderer-R91Qw5JA.js} +1 -1
  37. package/src/assets/web-panel/assets/{Marketplace-BIStF9d1.js → Marketplace-CY1VhFGx.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-pGfal768.js → McpTools-BBAbi1vt.js} +5 -5
  39. package/src/assets/web-panel/assets/{Memory-xbNqpIqB.js → Memory-BWYGHxJA.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-B5EQGrIK.js → MobileBridge-CPIFkW7A.js} +1 -1
  41. package/src/assets/web-panel/assets/MobileProjects-DQyWxCho.js +1 -0
  42. package/src/assets/web-panel/assets/{Mtc-a_rmfxJH.js → Mtc-Bo3GnQbx.js} +4 -4
  43. package/src/assets/web-panel/assets/{MtcAudit-BmKuofUr.js → MtcAudit-C8-c4rSW.js} +4 -4
  44. package/src/assets/web-panel/assets/{Multisig-BQbJ-CAN.js → Multisig-ChqMTtoq.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-JtPJKX25.js → NLProgramming-C48TyhvI.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-ZFKznTSG.js → Notes-zogUFWxp.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-B6aHRBBR.js → NotificationSettings-v-K9XpSB.js} +1 -1
  48. package/src/assets/web-panel/assets/OrderTableRenderer-P94JGGNz.js +1 -0
  49. package/src/assets/web-panel/assets/{Organization-BFDTAUgS.js → Organization-Boi1dQfR.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-0FoTfbWH.js → Overflow-DM5YWwgA.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-CWd90etw.js → P2P-C57LKpKK.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-DtCGC-W-.js → PdhVaultBrowser-BFkPqu6Q.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-CvQ7nr7T.js → Permissions-D6fB9YSp.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-rdNPcR-Z.js → PersonalDataHub-Bp7EefEo.js} +3 -3
  55. package/src/assets/web-panel/assets/{Pipeline-CmrfiNOs.js → Pipeline-BVln3hZf.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-D7ep1h_t.js → Privacy-Bf8P3nF6.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-C0xKINHS.js → ProjectInit-DM6wA2E2.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-AOmZFp-F.js → ProjectSettings-CGbc5Iho.js} +2 -2
  59. package/src/assets/web-panel/assets/{Projects-BWHSkXZP.js → Projects-D0p9EOxm.js} +1 -1
  60. package/src/assets/web-panel/assets/{Providers-Cb7JCTPL.js → Providers-B2kJcxS6.js} +1 -1
  61. package/src/assets/web-panel/assets/{QrScannerModal-BDMehcXC.js → QrScannerModal-Cxu7dXYy.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-BF6_1nvx.js → QuickAsk-DTlrTPms.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-BHfT-A28.js → Recommend-Cm3X-cCj.js} +1 -1
  64. package/src/assets/web-panel/assets/RemoteSession-DNb2kjvt.js +5 -0
  65. package/src/assets/web-panel/assets/{Reputation-CsWHLEcj.js → Reputation-CZUFFjc1.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-D6srnWhm.js → Row-DAPgloxA.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-Xhr-KyVd.js → RssFeed-dsx9S793.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-vIbIJvwL.js → Search-DnnC8kz-.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-Bzi5Aiko.js → Security-VuZknRMK.js} +4 -4
  70. package/src/assets/web-panel/assets/{Services-BHtVX52P.js → Services-B3XNX8Vx.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-C0R8B2jf.js → Skeleton-Dl1nVtCj.js} +1 -1
  72. package/src/assets/web-panel/assets/Skills-CY09CZ_W.js +1 -0
  73. package/src/assets/web-panel/assets/{Sla-0B37mxVU.js → Sla-HzU56n1z.js} +1 -1
  74. package/src/assets/web-panel/assets/{SpeechSettings-0V2jE1Bs.js → SpeechSettings-CRle7Jl2.js} +1 -1
  75. package/src/assets/web-panel/assets/{SyncSettings-CYedRzaj.js → SyncSettings-DWadz7Sl.js} +2 -2
  76. package/src/assets/web-panel/assets/{Tasks-D-R1x8vm.js → Tasks-CNVTDGg8.js} +1 -1
  77. package/src/assets/web-panel/assets/{Templates-BKoHztGT.js → Templates-BBAgvrlM.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant--17nwVNZ.js → Tenant-BsbbvGN8.js} +1 -1
  79. package/src/assets/web-panel/assets/Terminal-uscpZI4q.js +3 -0
  80. package/src/assets/web-panel/assets/{TimelineRenderer-C5jx4AE3.js → TimelineRenderer-mTyjNE6r.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-DYJKYa9t.js → Tokens-Bz97oBgs.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-DChpWiQ9.js → Trigger-BTRKC140.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-DfWG52EA.js → Trust-B4A_KuyX.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-CMugYcyA.js → UkeySign-DES9TmLU.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-BOSmrHAd.js → VideoEditing-ClXs7Qxp.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-D5g3k3Sa.js → Wallet-IzZqFz-7.js} +4 -4
  87. package/src/assets/web-panel/assets/{WebAuthn-D-7u4Mkc.js → WebAuthn-BtOP04g_.js} +3 -3
  88. package/src/assets/web-panel/assets/{WorkflowEditor-CFzZMSUJ.js → WorkflowEditor-_0cqnopY.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-VbR6l6mc.js → chat-ax7193uU.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-BSZn8EDS.js → colors-Bu4WGJah.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-y74obMEq.js → compact-item-BX1dlTW0.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-C326bjex.js → createContext-CktA_Dj7.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-x877iKKS.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-D_INJQT_.js → hasIn-D5wd817l.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-CsovTpx9.js → index-5PYYkr8S.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-9PIVuXqo.js → index-A4uBPQCz.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BjcWKg1S.js → index-BAtBNfkr.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CMHqs3Jb.js → index-BLLsUNDc.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-B7SrC-On.js → index-BQtoRyTO.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-DUU2606o.js → index-BRfXoRuh.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-Iw0FfqUz.js → index-Bad2CYeH.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-Dlxh9D8D.js → index-BcGdL3sG.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DuIkfnTF.js → index-C3HmzCLt.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-E_v1ZCTP.js → index-C8DkWyNr.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-4eyH-eC2.js → index-C8tLR2TG.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-BnSfnSMP.js → index-CP8ELJBc.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-DwHSZLXg.js → index-CUForzsG.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-C2NyllnW.js → index-CYRE0NJA.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Bnua8IX3.js → index-CeVZaJSC.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-KF9Zmqln.js → index-CfzxR61U.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-Cr3uuz0C.js → index-Ci3y1ZAv.js} +3 -3
  112. package/src/assets/web-panel/assets/{index-DBkzrpiL.js → index-CjEJjl5C.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-abmn_8Yz.js → index-Cv7bVWJ5.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-qMA4GYdQ.js → index-D-o4Rwjk.js} +1 -1
  115. package/src/assets/web-panel/assets/index-D7pfPouB.js +1 -0
  116. package/src/assets/web-panel/assets/{index-jYaogFE8.js → index-D9op8poE.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-GA80ir_u.js → index-DF1TysIF.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-CzE53HiB.js → index-DYo9S5OT.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-gINyI1rh.js → index-D_cycOET.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-FQBsuExX.js → index-Db3CpWTr.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-IZAWt0H8.js → index-DkD1K-fF.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-C327pLbw.js → index-DmPJ6T6F.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-DdyjrCAu.js → index-DmVUeWUk.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-CfLJ42kv.js → index-Dzdr0zDf.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DkH1JvEt.js → index-PBLzwYnu.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-DNMxIsDg.js → index-bFCaM7Eq.js} +1 -1
  127. package/src/assets/web-panel/assets/index-e4i-VLBd.js +1 -0
  128. package/src/assets/web-panel/assets/{index-C-ZCaUJc.js → index-h3KJZr95.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-Bfw2hf2s.js → index-iHcPtQ2e.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BJi3UqBt.js → index-jzlzm4VK.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-BY8-nCgs.js → index-o14NNnxw.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-nSn2-C4N.js → index-tYPSfGbd.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-4PIeTM--.js → index-ytp2H5Zx.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-DI0Zaf8-.js → initDefaultProps-D2Iut83B.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-BZDKSy3Z.js → motion-BuaJVdK9.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-DsIW01Vp.js → move-CaEuM92y.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-CohkDhsf.js → mtc-parser-wuKNBwys.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-DpiN5rzg.js → omit-7a3eklaq.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-qbuqni3y.js → pickAttrs-Dn4z7KvJ.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-mBky6714.js → placementArrow-DVn_qT4-.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-Bas3eQ2K.js → responsiveObserve-Dodz1OMQ.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-CBx_SKoK.js → slide-CxoGskbp.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-BlYguJSV.js → statusUtils-DBh_epQH.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-BCYQmRGv.js → styleChecker-RXQ4gG5P.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-Dp5dybLM.js → useFlexGapSupport-1Wxm0HEG.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-DHAMBgA2.js → useFs-CI_ySNxJ.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-W6jsSw76.js → usePersonalDataHub-C6973rZP.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-BkI6aayc.js → vnode-CalynwKr.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-C_IMGueq.js → zoom-CM1cd-Q0.js} +1 -1
  150. package/src/assets/web-panel/index.html +1 -1
  151. package/src/commands/agenda.js +74 -1
  152. package/src/commands/background-session.js +11 -1
  153. package/src/commands/batch.js +160 -5
  154. package/src/commands/plugin.js +90 -27
  155. package/src/commands/session.js +31 -1
  156. package/src/commands/team.js +212 -6
  157. package/src/data/changelog.json +13 -0
  158. package/src/harness/jsonl-session-store.js +57 -6
  159. package/src/harness/mcp-client.js +65 -43
  160. package/src/lib/agent-batch.js +4 -1
  161. package/src/lib/agent-team/team-worktree.js +3 -0
  162. package/src/lib/async-hook-supervisor.cjs +82 -10
  163. package/src/lib/async-hook-supervisor.js +50 -4
  164. package/src/lib/collaboration-run-store.js +362 -0
  165. package/src/lib/hook-runner.cjs +98 -17
  166. package/src/lib/hook-runner.js +77 -6
  167. package/src/lib/hook-shell-command.cjs +148 -0
  168. package/src/lib/hooks-v2-runtime.js +188 -77
  169. package/src/lib/jsonl-session-store.js +2 -0
  170. package/src/lib/lsp/__tests__/lsp-client.test.js +18 -0
  171. package/src/lib/lsp/lsp-client.js +12 -1
  172. package/src/lib/plugin-monitor-supervisor.js +53 -16
  173. package/src/lib/plugin-runtime/bin.js +1 -1
  174. package/src/lib/plugin-runtime/install.js +249 -57
  175. package/src/lib/plugin-runtime/mcp.js +21 -2
  176. package/src/lib/plugin-runtime/monitors.js +19 -3
  177. package/src/lib/plugin-runtime/sandbox-policy.js +99 -0
  178. package/src/lib/process-execution-broker/index.js +453 -12
  179. package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +1347 -0
  180. package/src/lib/process-execution-broker/linux-generic-bwrap.js +1260 -0
  181. package/src/lib/process-execution-broker/platform-sandbox.js +580 -56
  182. package/src/lib/session-usage.js +202 -2
  183. package/src/lib/stream-retry.js +29 -0
  184. package/src/repl/agent-repl.js +32 -3
  185. package/src/runtime/agent-core.js +32 -4
  186. package/src/runtime/headless-runner.js +37 -0
  187. package/src/runtime/headless-stream.js +34 -2
  188. package/src/assets/web-panel/assets/ChatBubbleRenderer-CI_jT0ru.js +0 -1
  189. package/src/assets/web-panel/assets/MobileProjects-VTc3gT1y.js +0 -1
  190. package/src/assets/web-panel/assets/OrderTableRenderer-DdcsOqEz.js +0 -1
  191. package/src/assets/web-panel/assets/RemoteSession-B6EEf8hh.js +0 -5
  192. package/src/assets/web-panel/assets/Skills-DtT6rWOX.js +0 -1
  193. package/src/assets/web-panel/assets/Terminal-Dnkos7vW.js +0 -3
  194. package/src/assets/web-panel/assets/devWarning-D3Bho_6u.js +0 -1
  195. package/src/assets/web-panel/assets/index-5iAFwYx1.js +0 -1
  196. package/src/assets/web-panel/assets/index-BfnB7LPx.js +0 -1
@@ -30,6 +30,14 @@ import {
30
30
  } from "../harness/worktree-isolator.js";
31
31
  import { findProjectRoot } from "../lib/project-detector.js";
32
32
  import executionBroker from "../lib/process-execution-broker/index.js";
33
+ import {
34
+ createCollaborationRun,
35
+ createCollaborationRunId,
36
+ createCollaborationSessionId,
37
+ finalizeCollaborationRun,
38
+ updateCollaborationUnit,
39
+ } from "../lib/collaboration-run-store.js";
40
+ import { loadSideEffectLedger } from "../lib/side-effect-ledger-store.js";
33
41
 
34
42
  export const _processDeps = {
35
43
  spawn: executionBroker.spawn.bind(executionBroker),
@@ -86,6 +94,13 @@ export function registerBatchCommand(program) {
86
94
  .option("--test <cmd>", "Default test command run in each worktree")
87
95
  .option("--merge", "Merge clean, passing branches back to base")
88
96
  .option("--model <model>", "Model for agent runs")
97
+ .option(
98
+ "--permission-mode <mode>",
99
+ "Permission mode for each agent unit",
100
+ "acceptEdits",
101
+ )
102
+ .option("--max-turns <n>", "Per-unit agent turn cap")
103
+ .option("--max-budget-usd <amount>", "Per-unit agent cost cap")
89
104
  .option("--json", "Machine-readable JSON output")
90
105
  .action(async (options) => {
91
106
  process.exitCode = await runBatchCommand(options);
@@ -97,6 +112,18 @@ export async function runBatchCommand(options = {}, _deps = {}) {
97
112
  const errLog = _deps.err || ((m) => logger.error(m));
98
113
  const repoDir =
99
114
  _deps.repoDir || findProjectRoot(process.cwd()) || process.cwd();
115
+ const collaborationStore =
116
+ _deps.collaborationStore === false
117
+ ? null
118
+ : _deps.collaborationStore || {
119
+ createRun: createCollaborationRun,
120
+ createRunId: createCollaborationRunId,
121
+ createSessionId: createCollaborationSessionId,
122
+ updateUnit: updateCollaborationUnit,
123
+ finalizeRun: finalizeCollaborationRun,
124
+ loadSideEffects: (sessionId) =>
125
+ loadSideEffectLedger(sessionId, { failIfUnavailable: false }),
126
+ };
100
127
 
101
128
  // 1. Resolve the unit list — from a file, or by decomposing a goal.
102
129
  let units;
@@ -123,14 +150,53 @@ export async function runBatchCommand(options = {}, _deps = {}) {
123
150
  return 4;
124
151
  }
125
152
 
153
+ const permissionMode = normalizePermissionMode(options.permissionMode);
154
+ let governanceRun = null;
155
+ const governanceByKey = new Map();
156
+ if (collaborationStore) {
157
+ try {
158
+ const runId = collaborationStore.createRunId("batch");
159
+ governanceRun = collaborationStore.createRun({
160
+ id: runId,
161
+ kind: "batch",
162
+ repoRoot: repoDir,
163
+ permissionMode,
164
+ resourceBudget: {
165
+ maxTurns: options.maxTurns,
166
+ maxCostUsd: options.maxBudgetUsd,
167
+ maxTasks: Array.isArray(units) ? units.length : null,
168
+ },
169
+ units: (Array.isArray(units) ? units : []).map((unit, index) => {
170
+ const key = String(unit?.key || `unit-${index + 1}`);
171
+ const branch = `batch/${sanitize(key)}`;
172
+ const sessionId = collaborationStore.createSessionId(runId, key);
173
+ return { key, branch, sessionId };
174
+ }),
175
+ });
176
+ for (const unit of governanceRun.units) {
177
+ governanceByKey.set(unit.key, unit);
178
+ }
179
+ } catch (err) {
180
+ errLog(`Failed to persist batch governance: ${err.message}`);
181
+ return 1;
182
+ }
183
+ }
184
+
126
185
  // 2. Run the batch with real worktree + agent + git deps.
127
- const deps = _deps.batchDeps || {
186
+ const baseDeps = _deps.batchDeps || {
128
187
  createWorktree: (key, branch) => createWorktree(repoDir, branch).path,
129
188
  removeWorktree: (worktreePath, opts) =>
130
189
  removeWorktree(repoDir, worktreePath, opts),
131
190
  runAgent:
132
191
  _deps.runAgent ||
133
- ((prompt, cwd) => spawnAgent(prompt, cwd, { model: options.model })),
192
+ ((prompt, cwd, unit) =>
193
+ spawnAgent(prompt, cwd, {
194
+ model: options.model,
195
+ permissionMode,
196
+ maxTurns: options.maxTurns,
197
+ maxBudgetUsd: options.maxBudgetUsd,
198
+ sessionId: governanceByKey.get(unit?.key)?.sessionId,
199
+ })),
134
200
  runTest: _deps.runTest || runTestCommand,
135
201
  diffStat: _deps.diffStat || gitDiffStat,
136
202
  commit: _deps.commit || gitCommitAll,
@@ -139,6 +205,21 @@ export async function runBatchCommand(options = {}, _deps = {}) {
139
205
  mergeWorktree(repoDir, branch, { message }),
140
206
  branchFor: (key) => `batch/${sanitize(key)}`,
141
207
  };
208
+ const deps = {
209
+ ...baseDeps,
210
+ createWorktree: (key, branch) => {
211
+ const worktreePath = baseDeps.createWorktree(key, branch);
212
+ if (governanceRun) {
213
+ collaborationStore.updateUnit(governanceRun.id, key, {
214
+ status: "running",
215
+ branch,
216
+ worktreePath,
217
+ startedAt: Date.now(),
218
+ });
219
+ }
220
+ return worktreePath;
221
+ },
222
+ };
142
223
 
143
224
  const onEvent = options.json ? () => {} : (ev) => log(formatEvent(ev));
144
225
 
@@ -155,10 +236,61 @@ export async function runBatchCommand(options = {}, _deps = {}) {
155
236
  deps,
156
237
  );
157
238
  } catch (err) {
239
+ if (governanceRun) {
240
+ try {
241
+ collaborationStore.finalizeRun(governanceRun.id, "failed");
242
+ } catch {
243
+ /* retain the running record for diagnosis */
244
+ }
245
+ }
158
246
  errLog(`Batch failed: ${err.message}`);
159
247
  return 1;
160
248
  }
161
249
 
250
+ if (governanceRun) {
251
+ try {
252
+ for (const record of outcome.units) {
253
+ const unit = governanceByKey.get(record.key);
254
+ let sideEffects = null;
255
+ if (unit?.sessionId) {
256
+ try {
257
+ sideEffects = collaborationStore.loadSideEffects(unit.sessionId);
258
+ } catch {
259
+ /* side-effect summary is additive */
260
+ }
261
+ }
262
+ const completed = new Set(["done", "no-changes"]).has(record.status);
263
+ collaborationStore.updateUnit(governanceRun.id, record.key, {
264
+ status: completed ? "completed" : record.status,
265
+ endedAt: Date.now(),
266
+ ...(sideEffects ? { sideEffects } : {}),
267
+ });
268
+ }
269
+ const failed = outcome.summary.testFailed + outcome.summary.errored > 0;
270
+ const finalized = collaborationStore.finalizeRun(
271
+ governanceRun.id,
272
+ failed ? "failed" : "completed",
273
+ );
274
+ outcome.governance = {
275
+ runId: finalized.id,
276
+ owner: finalized.owner,
277
+ status: finalized.status,
278
+ permissionMode: finalized.permissionMode,
279
+ resourceBudget: finalized.resourceBudget,
280
+ units: finalized.units.map((unit) => ({
281
+ key: unit.key,
282
+ owner: unit.owner,
283
+ sessionId: unit.sessionId,
284
+ status: unit.status,
285
+ sideEffects: unit.sideEffects,
286
+ })),
287
+ };
288
+ } catch (err) {
289
+ errLog(`Failed to finalize batch governance: ${err.message}`);
290
+ return 1;
291
+ }
292
+ }
293
+
162
294
  if (options.json) {
163
295
  log(JSON.stringify(outcome, null, 2));
164
296
  } else {
@@ -187,6 +319,21 @@ function sanitize(key) {
187
319
  return String(key).replace(/[^a-zA-Z0-9._-]/g, "-");
188
320
  }
189
321
 
322
+ function normalizePermissionMode(value) {
323
+ const mode = String(value || "acceptEdits");
324
+ return new Set([
325
+ "manual",
326
+ "auto",
327
+ "dontAsk",
328
+ "default",
329
+ "plan",
330
+ "acceptEdits",
331
+ "bypassPermissions",
332
+ ]).has(mode)
333
+ ? mode
334
+ : "acceptEdits";
335
+ }
336
+
190
337
  function spawnBatchProcess(command, args, options, origin) {
191
338
  return _processDeps.spawn(command, args, {
192
339
  ...options,
@@ -212,14 +359,18 @@ function spawnAgent(prompt, cwd, opts = {}) {
212
359
  const args = [
213
360
  BIN,
214
361
  "agent",
215
- "-p",
216
- prompt,
217
362
  "--permission-mode",
218
- "acceptEdits",
363
+ normalizePermissionMode(opts.permissionMode),
219
364
  "--output-format",
220
365
  "text",
221
366
  ];
222
367
  if (opts.model) args.push("--model", opts.model);
368
+ if (opts.sessionId) args.push("--session", opts.sessionId);
369
+ if (Number(opts.maxTurns) > 0)
370
+ args.push("--max-turns", String(opts.maxTurns));
371
+ if (Number(opts.maxBudgetUsd) > 0) {
372
+ args.push("--max-budget-usd", String(opts.maxBudgetUsd));
373
+ }
223
374
  const child = spawnBatchProcess(
224
375
  process.execPath,
225
376
  args,
@@ -233,6 +384,10 @@ function spawnAgent(prompt, cwd, opts = {}) {
233
384
  );
234
385
  let err = "";
235
386
  child.stderr?.on("data", (d) => (err += d.toString("utf8")));
387
+ if (child.stdin) {
388
+ child.stdin.on("error", () => {});
389
+ child.stdin.end(String(prompt || ""));
390
+ }
236
391
  child.on("error", (e) => reject(new Error(e.message)));
237
392
  child.on("close", (code) =>
238
393
  code === 0
@@ -37,7 +37,12 @@ import {
37
37
  * (for --json folding) or null when the plugin declares nothing / can't be
38
38
  * resolved.
39
39
  */
40
- async function resolvePluginCapabilityNotice(name, scope, cwd) {
40
+ async function resolvePluginCapabilityNotice(
41
+ name,
42
+ scope,
43
+ cwd,
44
+ { strict = false } = {},
45
+ ) {
41
46
  try {
42
47
  const { discoverPlugins } = await import("../lib/plugin-runtime/scopes.js");
43
48
  const { describeCapabilities } =
@@ -46,7 +51,12 @@ async function resolvePluginCapabilityNotice(name, scope, cwd) {
46
51
  const installed = discoverPlugins({ cwd, skipPolicy: true }).find(
47
52
  (p) => p.name === name && p.scope === scope,
48
53
  );
49
- if (!installed) return null;
54
+ if (!installed) {
55
+ if (strict) {
56
+ throw new Error(`${name} is not discoverable at ${scope} scope`);
57
+ }
58
+ return null;
59
+ }
50
60
  const declared = installed.manifest?.capabilities;
51
61
  if (!declared || consent.capabilitiesAreEmpty(declared)) return null;
52
62
  const entry = consent.loadConsentStore()[`${scope}:${name}`] || null;
@@ -57,7 +67,12 @@ async function resolvePluginCapabilityNotice(name, scope, cwd) {
57
67
  reason: status.reason,
58
68
  added: status.added,
59
69
  };
60
- } catch {
70
+ } catch (error) {
71
+ if (strict) {
72
+ throw new Error(
73
+ `installed plugin capability validation failed: ${error.message}`,
74
+ );
75
+ }
61
76
  return null; // capability rendering is advisory — never break an install
62
77
  }
63
78
  }
@@ -1568,7 +1583,8 @@ export function registerPluginCommand(program) {
1568
1583
  )
1569
1584
  .option("--json", "Output as JSON")
1570
1585
  .action(async (source, options) => {
1571
- const { updatePlugin } = await import("../lib/plugin-runtime/install.js");
1586
+ const { updatePlugin, finalizePluginUpdate, rollbackPluginUpdate } =
1587
+ await import("../lib/plugin-runtime/install.js");
1572
1588
  let installSource = source;
1573
1589
  let integritySha = null;
1574
1590
  let sourceMetadata = null;
@@ -1647,8 +1663,9 @@ export function registerPluginCommand(program) {
1647
1663
  requireTrustedKey: requiresManagedSignature,
1648
1664
  }
1649
1665
  : null;
1666
+ let res = null;
1650
1667
  try {
1651
- const res = updatePlugin(installSource, {
1668
+ res = updatePlugin(installSource, {
1652
1669
  scope: options.scope,
1653
1670
  cwd: process.cwd(),
1654
1671
  force: options.force,
@@ -1656,11 +1673,13 @@ export function registerPluginCommand(program) {
1656
1673
  sourceMetadata,
1657
1674
  managedPolicy: managed,
1658
1675
  policySource: options.registry || source,
1676
+ transactional: true,
1659
1677
  });
1660
1678
  const upgradeNotice = await resolvePluginCapabilityNotice(
1661
1679
  res.name,
1662
1680
  options.scope,
1663
1681
  process.cwd(),
1682
+ { strict: true },
1664
1683
  );
1665
1684
  if (res.updated || res.reinstalled)
1666
1685
  await auditPluginInstall(
@@ -1670,19 +1689,53 @@ export function registerPluginCommand(program) {
1670
1689
  upgradeNotice,
1671
1690
  );
1672
1691
 
1692
+ let capabilitiesGranted = false;
1673
1693
  if (options.json) {
1674
- let capabilitiesGranted = false;
1675
- if (
1676
- options.grantCapabilities &&
1677
- upgradeNotice &&
1678
- !upgradeNotice.consented
1679
- ) {
1694
+ if (options.grantCapabilities && upgradeNotice?.consented === false) {
1680
1695
  capabilitiesGranted = await grantInstalledPluginCapabilities(
1681
1696
  res.name,
1682
1697
  options.scope,
1683
1698
  process.cwd(),
1684
1699
  );
1685
1700
  }
1701
+ } else {
1702
+ capabilitiesGranted = await applyCapabilityConsentGate(
1703
+ res.name,
1704
+ options.scope,
1705
+ upgradeNotice,
1706
+ process.cwd(),
1707
+ {
1708
+ grant: options.grantCapabilities === true,
1709
+ interactive: Boolean(process.stdin.isTTY),
1710
+ },
1711
+ );
1712
+ }
1713
+
1714
+ const changed = res.updated || res.reinstalled;
1715
+ const consentBlocked =
1716
+ changed &&
1717
+ upgradeNotice?.consented === false &&
1718
+ capabilitiesGranted !== true;
1719
+ const rollbackReason = consentBlocked
1720
+ ? options.grantCapabilities
1721
+ ? "capability_consent_failed"
1722
+ : "capability_consent_required"
1723
+ : null;
1724
+ let activationStatus = changed ? "activated" : "unchanged";
1725
+ let rollbackVersion = null;
1726
+ let cleanupPending = false;
1727
+ if (rollbackReason) {
1728
+ const recovery = rollbackPluginUpdate(res);
1729
+ if (!recovery.rolledBack) {
1730
+ throw new Error("upgrade rollback transaction was unavailable");
1731
+ }
1732
+ activationStatus = "rolled_back";
1733
+ rollbackVersion = recovery.version;
1734
+ } else {
1735
+ cleanupPending = finalizePluginUpdate(res).cleanupPending === true;
1736
+ }
1737
+
1738
+ if (options.json) {
1686
1739
  console.log(
1687
1740
  JSON.stringify(
1688
1741
  {
@@ -1690,6 +1743,10 @@ export function registerPluginCommand(program) {
1690
1743
  scope: options.scope,
1691
1744
  capabilities: upgradeNotice,
1692
1745
  capabilitiesGranted,
1746
+ activationStatus,
1747
+ rollbackVersion,
1748
+ rollbackReason,
1749
+ cleanupPending,
1693
1750
  },
1694
1751
  null,
1695
1752
  2,
@@ -1698,7 +1755,14 @@ export function registerPluginCommand(program) {
1698
1755
  return;
1699
1756
  }
1700
1757
 
1701
- if (res.updated) {
1758
+ if (activationStatus === "rolled_back") {
1759
+ logger.warn(
1760
+ `Upgrade not activated: ${rollbackReason.replaceAll("_", " ")}; ` +
1761
+ (rollbackVersion
1762
+ ? `restored ${res.name} v${rollbackVersion}`
1763
+ : `removed the rejected ${res.name} v${res.version} install`),
1764
+ );
1765
+ } else if (res.updated) {
1702
1766
  logger.success(
1703
1767
  `Updated ${res.name}: ${res.previousVersion ? `v${res.previousVersion} → ` : ""}v${res.version} (${options.scope} scope)`,
1704
1768
  );
@@ -1711,22 +1775,21 @@ export function registerPluginCommand(program) {
1711
1775
  `${res.name} is already up to date at v${res.version} (use --force to reinstall)`,
1712
1776
  );
1713
1777
  }
1714
- // Surface the (possibly widened) capability set + re-consent hint. An
1715
- // upgrade that adds a capability shows a `⚠ capability consent required`
1716
- // notice diffed against the prior consent, then either auto-grants
1717
- // (--grant-capabilities) or blocks interactively to re-consent now.
1718
- await applyCapabilityConsentGate(
1719
- res.name,
1720
- options.scope,
1721
- upgradeNotice,
1722
- process.cwd(),
1723
- {
1724
- grant: options.grantCapabilities === true,
1725
- interactive: Boolean(process.stdin.isTTY),
1726
- },
1727
- );
1728
1778
  } catch (err) {
1729
- logger.error(`Upgrade failed: ${err.message}`);
1779
+ let recoveryNote = "";
1780
+ if (res) {
1781
+ try {
1782
+ const recovery = rollbackPluginUpdate(res);
1783
+ if (recovery.rolledBack) {
1784
+ recoveryNote = recovery.version
1785
+ ? `; restored v${recovery.version}`
1786
+ : "; removed the rejected install";
1787
+ }
1788
+ } catch (recoveryError) {
1789
+ recoveryNote = `; automatic recovery failed: ${recoveryError.message}`;
1790
+ }
1791
+ }
1792
+ logger.error(`Upgrade failed: ${err.message}${recoveryNote}`);
1730
1793
  process.exitCode = 1;
1731
1794
  }
1732
1795
  });
@@ -1334,6 +1334,7 @@ export function registerSessionCommand(program) {
1334
1334
  "tool",
1335
1335
  "mcp",
1336
1336
  "plugin",
1337
+ "retry",
1337
1338
  "model",
1338
1339
  ];
1339
1340
 
@@ -1347,9 +1348,19 @@ export function registerSessionCommand(program) {
1347
1348
  logger.log(
1348
1349
  ` ${chalk.gray(String(label).padEnd(28))} in=${r.inputTokens} out=${r.outputTokens} total=${chalk.cyan(r.totalTokens.toLocaleString())} calls=${r.calls}`,
1349
1350
  );
1351
+ const elapsed = (ms) => {
1352
+ const value = Math.max(0, Number(ms) || 0);
1353
+ if (value < 1000) return `${Math.round(value)}ms`;
1354
+ return `${(value / 1000).toFixed(2)}s`;
1355
+ };
1350
1356
  const toolRow = (label, r) =>
1351
1357
  logger.log(
1352
- ` ${chalk.gray(String(label).padEnd(28))} calls=${r.calls} errors=${r.errors} turnTokens≈${chalk.cyan((r.turnTokens || 0).toLocaleString())}`,
1358
+ ` ${chalk.gray(String(label).padEnd(28))} calls=${r.calls} errors=${r.errors}` +
1359
+ (r.retries != null ? ` retries=${r.retries}` : "") +
1360
+ (r.timedCalls != null
1361
+ ? ` observed=${elapsed(r.durationMs)} (${r.timedCalls} timed)`
1362
+ : "") +
1363
+ ` turnTokens≈${chalk.cyan((r.turnTokens || 0).toLocaleString())}`,
1353
1364
  );
1354
1365
  const empty = (what) => logger.log(chalk.gray(` (no ${what} recorded)`));
1355
1366
 
@@ -1416,6 +1427,25 @@ export function registerSessionCommand(program) {
1416
1427
  );
1417
1428
  return;
1418
1429
  }
1430
+ case "retry": {
1431
+ const retry = a.retries || null;
1432
+ if (!retry || !retry.totalRetries)
1433
+ return empty("automatic LLM retries");
1434
+ logger.log(
1435
+ ` ${chalk.gray("all".padEnd(28))} retries=${retry.totalRetries} failedAttemptTime=${chalk.cyan(elapsed(retry.durationMs))}`,
1436
+ );
1437
+ for (const r of retry.byReason || []) {
1438
+ logger.log(
1439
+ ` ${chalk.gray(String(r.reason || "unknown").padEnd(28))} retries=${r.retries} failedAttemptTime=${chalk.cyan(elapsed(r.durationMs))}`,
1440
+ );
1441
+ }
1442
+ for (const r of retry.byModel || []) {
1443
+ logger.log(
1444
+ ` ${chalk.gray(`${r.provider || "?"}/${r.model || "?"}`.padEnd(28))} retries=${r.retries} failedAttemptTime=${chalk.cyan(elapsed(r.durationMs))}`,
1445
+ );
1446
+ }
1447
+ return;
1448
+ }
1419
1449
  default:
1420
1450
  break;
1421
1451
  }