chainlesschain 0.162.180 → 0.162.182

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 (263) hide show
  1. package/package.json +7 -3
  2. package/scripts/build-windows-sandbox-helper.ps1 +163 -0
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-D_TIL54O.js → AIOps-DzZ5_xoj.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-eQwy9r-f.js → ActionButton-DeLXddIg.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-D2eNuDgT.js → Analytics-rvDCmet1.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-CFhwOFsf.js → AppLayout-Yt6QVDnp.js} +5 -5
  8. package/src/assets/web-panel/assets/{Artifacts-CJUMw6PB.js → Artifacts-BS112K5L.js} +1 -1
  9. package/src/assets/web-panel/assets/{Audit-CDB9V58o.js → Audit-0wJuQrNu.js} +1 -1
  10. package/src/assets/web-panel/assets/{BackgroundAgents-TBppYFjN.js → BackgroundAgents-B90PMgbn.js} +1 -1
  11. package/src/assets/web-panel/assets/{Backup-CYEOUpzJ.js → Backup-TkgMglQQ.js} +1 -1
  12. package/src/assets/web-panel/assets/{BaseInput-C88fFT2u.js → BaseInput-CQVS9p1l.js} +1 -1
  13. package/src/assets/web-panel/assets/{Chat-mkr1vC3N.js → Chat-YTjQHoC7.js} +6 -6
  14. package/src/assets/web-panel/assets/ChatBubbleRenderer-PR074hUN.js +1 -0
  15. package/src/assets/web-panel/assets/{Checkbox-CVU4xqti.js → Checkbox-5bwaOabq.js} +1 -1
  16. package/src/assets/web-panel/assets/{Codegen-rrNcByz3.js → Codegen-BFmNQ_Xe.js} +1 -1
  17. package/src/assets/web-panel/assets/{Col-Cqu-zCvh.js → Col-BT_u4Dzp.js} +1 -1
  18. package/src/assets/web-panel/assets/{Community-RGRlSgXV.js → Community-CJP52u5b.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compact-DBm6epOK.js → Compact-BpzhJE9i.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compliance-BgKw5iaW.js → Compliance-Cg7rfslp.js} +1 -1
  21. package/src/assets/web-panel/assets/{Cowork-BqQcNO3Z.js → Cowork-JisxL6Yy.js} +3 -3
  22. package/src/assets/web-panel/assets/{Cron-DO5gTFNb.js → Cron-Bu7Ug_MC.js} +2 -2
  23. package/src/assets/web-panel/assets/{Crosschain-B8hbJNuN.js → Crosschain-CvuqoLdj.js} +1 -1
  24. package/src/assets/web-panel/assets/{DID-B08bFJ2C.js → DID-C2u9G8Pu.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dashboard-xNdy_ifo.js → Dashboard-BFt5Yv3d.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dropdown-D-KIZgWL.js → Dropdown-DIaT9Wxq.js} +1 -1
  27. package/src/assets/web-panel/assets/{EmailListRenderer-DKCvsaGo.js → EmailListRenderer-D_A601Y4.js} +1 -1
  28. package/src/assets/web-panel/assets/{FamilyGuardDashboard-D_cfqama.js → FamilyGuardDashboard--IyQ8I8w.js} +1 -1
  29. package/src/assets/web-panel/assets/{Federation-B-UqQD68.js → Federation-BihWHxuY.js} +1 -1
  30. package/src/assets/web-panel/assets/{FormItemContext-BWWvWuJW.js → FormItemContext-BB8dOXc_.js} +1 -1
  31. package/src/assets/web-panel/assets/{GenericCardRenderer-CPchx6N7.js → GenericCardRenderer-DQYhj1HH.js} +1 -1
  32. package/src/assets/web-panel/assets/{Git-Vx4co9Ff.js → Git-B-2QZxGf.js} +2 -2
  33. package/src/assets/web-panel/assets/{Governance-D4x0pp_m.js → Governance-CusSb-nG.js} +1 -1
  34. package/src/assets/web-panel/assets/{Inference-T3KvwPYR.js → Inference-BAjmvPPL.js} +1 -1
  35. package/src/assets/web-panel/assets/{KnowledgeGraph-Ddv3KUv3.js → KnowledgeGraph-DoNYWKYq.js} +1 -1
  36. package/src/assets/web-panel/assets/{Logs-DfH-Dkae.js → Logs-B8fKWD-n.js} +2 -2
  37. package/src/assets/web-panel/assets/{MarkdownRenderer-DHW3PbCq.js → MarkdownRenderer-BlJm1J7E.js} +1 -1
  38. package/src/assets/web-panel/assets/{Marketplace-tjgb0R3D.js → Marketplace-CyOscbSL.js} +1 -1
  39. package/src/assets/web-panel/assets/{McpTools-DHAk5nYX.js → McpTools-Ex6Om5da.js} +5 -5
  40. package/src/assets/web-panel/assets/{Memory-A2Yx7thM.js → Memory-CDcD8l8r.js} +2 -2
  41. package/src/assets/web-panel/assets/{MobileBridge-BEmTVfN5.js → MobileBridge-xfBqoFDg.js} +1 -1
  42. package/src/assets/web-panel/assets/{MobileProjects-DuFHUgE4.js → MobileProjects-BwObMMA2.js} +1 -1
  43. package/src/assets/web-panel/assets/{Mtc-BDSll0OZ.js → Mtc-CIWd36OV.js} +4 -4
  44. package/src/assets/web-panel/assets/{MtcAudit-CuBvluaS.js → MtcAudit-CPX0ouuA.js} +4 -4
  45. package/src/assets/web-panel/assets/{Multisig-BmXAA-Sb.js → Multisig-BDJsIUuW.js} +3 -3
  46. package/src/assets/web-panel/assets/{NLProgramming-ci2stZAe.js → NLProgramming-DEkbuD3N.js} +1 -1
  47. package/src/assets/web-panel/assets/{Notes-D-1RpqnS.js → Notes-DJpHRhH1.js} +3 -3
  48. package/src/assets/web-panel/assets/{NotificationSettings-C0GyitIT.js → NotificationSettings-C1UZ-Qd5.js} +1 -1
  49. package/src/assets/web-panel/assets/{OrderTableRenderer-U2bN-hj5.js → OrderTableRenderer-GlJtqLjT.js} +1 -1
  50. package/src/assets/web-panel/assets/{Organization-BNZgpPci.js → Organization-Bbhj0fac.js} +4 -4
  51. package/src/assets/web-panel/assets/{Overflow-CDidKmUN.js → Overflow-1H04x3kx.js} +1 -1
  52. package/src/assets/web-panel/assets/{P2P-BnreBaXq.js → P2P-CDpPe3et.js} +2 -2
  53. package/src/assets/web-panel/assets/{PdhVaultBrowser-DwJUxO9j.js → PdhVaultBrowser-MUX0Bpvw.js} +3 -3
  54. package/src/assets/web-panel/assets/{Permissions-BQGgJPH0.js → Permissions-A07-0Ci1.js} +4 -4
  55. package/src/assets/web-panel/assets/{PersonalDataHub-k_fSkCwL.js → PersonalDataHub-DhhDWxAZ.js} +5 -5
  56. package/src/assets/web-panel/assets/{Pipeline-WGqKMqau.js → Pipeline-CyfbJfe-.js} +1 -1
  57. package/src/assets/web-panel/assets/{Privacy-DtHj9Ymq.js → Privacy-CNFps3ED.js} +1 -1
  58. package/src/assets/web-panel/assets/{ProjectInit-B3wH2SFC.js → ProjectInit--T-u3Dr5.js} +2 -2
  59. package/src/assets/web-panel/assets/{ProjectSettings-Cd0cgcA1.js → ProjectSettings-DJmrK2fC.js} +2 -2
  60. package/src/assets/web-panel/assets/Projects-Qx_MdX9k.js +1 -0
  61. package/src/assets/web-panel/assets/{Providers-DTpxEXur.js → Providers-DLzzbOZd.js} +1 -1
  62. package/src/assets/web-panel/assets/{QrScannerModal-B2v6gR-C.js → QrScannerModal-CexOomKS.js} +1 -1
  63. package/src/assets/web-panel/assets/{QuickAsk-D3Nr9xXR.js → QuickAsk-QklGi19_.js} +1 -1
  64. package/src/assets/web-panel/assets/{Recommend-C9inoMky.js → Recommend-Bb9kwSw8.js} +1 -1
  65. package/src/assets/web-panel/assets/RemoteSession-DZuVNNN5.js +5 -0
  66. package/src/assets/web-panel/assets/{Reputation-41KFG646.js → Reputation-Dr5cLP0N.js} +1 -1
  67. package/src/assets/web-panel/assets/{Row-DqAaqqCv.js → Row-oCQHYv5t.js} +1 -1
  68. package/src/assets/web-panel/assets/{RssFeed-CMDpCDKc.js → RssFeed-IFDEykIR.js} +3 -3
  69. package/src/assets/web-panel/assets/{Search-B6mtegNL.js → Search-CspVIxDc.js} +1 -1
  70. package/src/assets/web-panel/assets/{Security-BaePFVZ8.js → Security-Bm66o_DH.js} +3 -3
  71. package/src/assets/web-panel/assets/{Services-DeG3Qscl.js → Services-DvanNqXl.js} +2 -2
  72. package/src/assets/web-panel/assets/{Skeleton-D_QP7F90.js → Skeleton-CHjEe9_O.js} +1 -1
  73. package/src/assets/web-panel/assets/{Skills-DLGyUgIA.js → Skills-Cb8jWjMX.js} +1 -1
  74. package/src/assets/web-panel/assets/{Sla-BN2pxW1Q.js → Sla-DxZm1491.js} +1 -1
  75. package/src/assets/web-panel/assets/{SpeechSettings-BWsZPd8B.js → SpeechSettings-DWxEEclC.js} +1 -1
  76. package/src/assets/web-panel/assets/{SyncSettings-VOZRPODW.js → SyncSettings-FIvOFw5p.js} +2 -2
  77. package/src/assets/web-panel/assets/Tasks-CyuLnDFR.js +1 -0
  78. package/src/assets/web-panel/assets/{Templates-eJSob-q0.js → Templates-CaNjzV_t.js} +1 -1
  79. package/src/assets/web-panel/assets/{Tenant-Bdwk8Rwy.js → Tenant-DjlP6TmH.js} +1 -1
  80. package/src/assets/web-panel/assets/Terminal-DwzGMniO.js +3 -0
  81. package/src/assets/web-panel/assets/{TimelineRenderer-D5qkbPKT.js → TimelineRenderer-DoZ8y7y8.js} +1 -1
  82. package/src/assets/web-panel/assets/{Tokens-DKgwn8hI.js → Tokens-390cg2TC.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trigger-HlEHniGM.js → Trigger-CLrtCj5_.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trust-CdPcsBpN.js → Trust-DpESfSPn.js} +1 -1
  85. package/src/assets/web-panel/assets/{UkeySign-vAdXd-vG.js → UkeySign-CN6279O0.js} +1 -1
  86. package/src/assets/web-panel/assets/{VideoEditing-9hHBYFnH.js → VideoEditing-DPtAUlSe.js} +1 -1
  87. package/src/assets/web-panel/assets/{Wallet-Dxh5d1yR.js → Wallet-nKOMV_1n.js} +4 -4
  88. package/src/assets/web-panel/assets/{WebAuthn-BsFmLHkp.js → WebAuthn-HuXlSOc4.js} +5 -5
  89. package/src/assets/web-panel/assets/{WorkflowEditor-Cn0OIwLn.js → WorkflowEditor-CUfFjARi.js} +1 -1
  90. package/src/assets/web-panel/assets/chat-6Eq0PcZJ.js +1 -0
  91. package/src/assets/web-panel/assets/{colors-Du9jzLN0.js → colors-BP_Sf6Iy.js} +1 -1
  92. package/src/assets/web-panel/assets/{compact-item-DhEscfzw.js → compact-item-BufMKIh5.js} +1 -1
  93. package/src/assets/web-panel/assets/{createContext-CwzEfF3i.js → createContext-BBMXxWSW.js} +1 -1
  94. package/src/assets/web-panel/assets/devWarning-DgVKduH2.js +1 -0
  95. package/src/assets/web-panel/assets/{hasIn-DT_GSE6J.js → hasIn-fUK_tRO2.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-tND8-TDU.js → index-2A5ph8b2.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-B8s5FxJY.js → index-3FuwBewR.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-53z1YUxX.js → index-6GmBa4Kg.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BFD0cEna.js → index-B2vS66eI.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CQWxDOvM.js → index-B7Etk0Te.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-VeHs6qH0.js → index-B9WYSn4m.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CGvgnfl9.js → index-BHy6yNiF.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-D3llLkYM.js → index-BMLHv389.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-Dny_ZnAO.js → index-BWKoBU8R.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DzjzrOli.js → index-Bkg4ZePE.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DN60VBn5.js → index-C44atv4k.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-v5HLYCVa.js → index-CE2DdTP2.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-BF-ZCVGE.js → index-CGjmILDm.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-gFjYdstW.js → index-CW_G-MXw.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-NA2oBLSB.js → index-CZ6Yt17L.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-Mobw3PHs.js → index-CeASi4fr.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-DWL3SYN3.js → index-CgiECHu2.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-1LoutPJd.js → index-Cp8vhyZy.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BnHhFnwt.js → index-CwSf5pnf.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-B6QDWRLk.js → index-D4_MuGkd.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-D-QkW1fp.js → index-D9vU25ij.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-C4SN3by5.js → index-DASluSqY.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-CyEhUJcu.js → index-DLpIs_P_.js} +1 -1
  119. package/src/assets/web-panel/assets/index-DOZTSoS7.js +1 -0
  120. package/src/assets/web-panel/assets/{index-BrkJ7JPm.js → index-DPdUNk1i.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-Cnok8mhZ.js → index-DVsqvI4M.js} +1 -1
  122. package/src/assets/web-panel/assets/index-DhpvjpqI.js +1 -0
  123. package/src/assets/web-panel/assets/{index-CAVW0cWM.js → index-DmkMXwnR.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-Cc9aPkv-.js → index-DocdRcbd.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DnVVYKCE.js → index-Dyngbd29.js} +20 -20
  126. package/src/assets/web-panel/assets/{index-D8gt0j7r.js → index-GwdRUZ-x.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-BIYTjbv_.js → index-LvCBfTLo.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-DhXay17G.js → index-cpEli44X.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-BQWENaZf.js → index-fzaMtSJ8.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-DfRDyY1q.js → index-pum7HYBA.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-BgSR2WMG.js → index-t8N1tSeX.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-D5IytTND.js → index-uCbEN7cY.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-DtRwLhee.js → index-wKTLbKyc.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-D4kZoXNr.js → index-wV6iGdpY.js} +1 -1
  135. package/src/assets/web-panel/assets/{initDefaultProps-Cvt59c10.js → initDefaultProps-V5Fo95FM.js} +1 -1
  136. package/src/assets/web-panel/assets/{motion-D15pPEzl.js → motion-BYWU0hUT.js} +1 -1
  137. package/src/assets/web-panel/assets/{move-N55KeXJ7.js → move-Cr1M-J2h.js} +1 -1
  138. package/src/assets/web-panel/assets/{mtc-parser-CyFO1bYP.js → mtc-parser-BysQKi2N.js} +1 -1
  139. package/src/assets/web-panel/assets/{omit-B5IXfxU2.js → omit-D1zHU8GC.js} +1 -1
  140. package/src/assets/web-panel/assets/{pickAttrs-CpVqsulV.js → pickAttrs-CUArxtfi.js} +1 -1
  141. package/src/assets/web-panel/assets/{placementArrow-ME36sMF3.js → placementArrow-ChoYEys0.js} +1 -1
  142. package/src/assets/web-panel/assets/{responsiveObserve-BXAIR1r-.js → responsiveObserve-BQRs3Mo7.js} +1 -1
  143. package/src/assets/web-panel/assets/{slide-BkOX3-Dp.js → slide-B8zbsCkg.js} +1 -1
  144. package/src/assets/web-panel/assets/{statusUtils-Cy4Aklpt.js → statusUtils-C2U8Gs6h.js} +1 -1
  145. package/src/assets/web-panel/assets/{styleChecker-gUd2T206.js → styleChecker-Dd8MgL_V.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFlexGapSupport-CaVD4o99.js → useFlexGapSupport-hknqY5NH.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFs--pFGl0KD.js → useFs-CLTAmcfw.js} +1 -1
  148. package/src/assets/web-panel/assets/{usePersonalDataHub-D45iP86i.js → usePersonalDataHub-ByegHbiB.js} +1 -1
  149. package/src/assets/web-panel/assets/{vnode-BayoChH_.js → vnode-DqlAy5DP.js} +1 -1
  150. package/src/assets/web-panel/assets/{zoom-CpP38poi.js → zoom-DiXiztQn.js} +1 -1
  151. package/src/assets/web-panel/index.html +1 -1
  152. package/src/commands/agenda.js +115 -3
  153. package/src/commands/agent.js +10 -1
  154. package/src/commands/background-session.js +2 -1
  155. package/src/commands/context.js +69 -2
  156. package/src/data/changelog.json +26 -0
  157. package/src/gateways/terminal/PtyManager.js +45 -4
  158. package/src/gateways/ws/background-agent-protocol.js +38 -0
  159. package/src/gateways/ws/message-dispatcher.js +1 -0
  160. package/src/gateways/ws/remote-session-protocol.js +65 -6
  161. package/src/gateways/ws/ws-server.js +18 -2
  162. package/src/harness/background-task-manager.js +70 -2
  163. package/src/harness/feature-flags.js +15 -8
  164. package/src/harness/mcp-client.js +618 -43
  165. package/src/harness/worktree-isolator.js +14 -3
  166. package/src/lazy-dispatch.js +30 -1
  167. package/src/lib/agent-authority.js +22 -0
  168. package/src/lib/agent-core.js +3 -0
  169. package/src/lib/agent-sandbox.js +161 -0
  170. package/src/lib/agent-schedule-store.js +45 -22
  171. package/src/lib/agent-team/team-runner.js +22 -0
  172. package/src/lib/artifact-store.js +35 -0
  173. package/src/lib/async-hook-supervisor.cjs +13 -2
  174. package/src/lib/audit-mtc.js +3 -2
  175. package/src/lib/background-agent-supervisor.js +104 -3
  176. package/src/lib/background-interaction-journal.js +407 -0
  177. package/src/lib/background-interaction-resolver.js +23 -34
  178. package/src/lib/background-session-transport.js +12 -2
  179. package/src/lib/capability-manifest.js +41 -3
  180. package/src/lib/capability-negotiation.js +1 -1
  181. package/src/lib/channels/channel-manager.js +33 -0
  182. package/src/lib/channels/telegram-channel.js +23 -5
  183. package/src/lib/channels/webhook-channel.js +38 -15
  184. package/src/lib/chrome-connector.js +169 -23
  185. package/src/lib/config-manager.js +23 -9
  186. package/src/lib/context-breakdown.js +31 -0
  187. package/src/lib/cowork-cron.js +274 -32
  188. package/src/lib/cross-chain-mtc.js +3 -2
  189. package/src/lib/durable-security-store.js +124 -0
  190. package/src/lib/event-runtime-host.js +67 -6
  191. package/src/lib/event-runtime-store.js +163 -0
  192. package/src/lib/goal-store.js +32 -12
  193. package/src/lib/headless-manifest.js +2 -1
  194. package/src/lib/hook-environment.cjs +58 -0
  195. package/src/lib/hook-manager.js +12 -5
  196. package/src/lib/hook-runner.cjs +122 -28
  197. package/src/lib/hook-runner.js +7 -2
  198. package/src/lib/hooks-v2-producers.js +36 -0
  199. package/src/lib/hooks-v2-runtime.js +329 -52
  200. package/src/lib/interaction-adapter.js +60 -19
  201. package/src/lib/interaction-binding.js +64 -0
  202. package/src/lib/json-schema-output.js +439 -14
  203. package/src/lib/json-schema-validate.js +514 -883
  204. package/src/lib/lan-pairing-tokens.js +115 -57
  205. package/src/lib/lsp/__tests__/lsp-client.test.js +32 -0
  206. package/src/lib/lsp/__tests__/lsp-manager.test.js +25 -0
  207. package/src/lib/lsp/lsp-client.js +4 -0
  208. package/src/lib/lsp/lsp-manager.js +3 -0
  209. package/src/lib/lsp/lsp-server-registry.js +18 -0
  210. package/src/lib/mcp-client.js +1 -0
  211. package/src/lib/mcp-oauth.js +35 -21
  212. package/src/lib/packer/pkg-config-generator.js +3 -0
  213. package/src/lib/permission-decision.js +99 -0
  214. package/src/lib/plugin-monitor-supervisor.js +3 -0
  215. package/src/lib/plugin-runtime/bin.js +1148 -70
  216. package/src/lib/plugin-runtime/capabilities.js +50 -0
  217. package/src/lib/plugin-runtime/capability-consent.js +42 -35
  218. package/src/lib/plugin-runtime/hooks.js +36 -9
  219. package/src/lib/plugin-runtime/install.js +23 -7
  220. package/src/lib/plugin-runtime/lsp.js +4 -0
  221. package/src/lib/plugin-runtime/manifest.js +112 -8
  222. package/src/lib/plugin-runtime/mcp.js +30 -5
  223. package/src/lib/plugin-runtime/monitors.js +11 -0
  224. package/src/lib/plugin-runtime/plugin-options.js +94 -38
  225. package/src/lib/plugin-runtime/policy.js +29 -2
  226. package/src/lib/plugin-runtime/sandbox-policy.js +84 -0
  227. package/src/lib/plugin-runtime/scopes.js +27 -13
  228. package/src/lib/plugin-runtime/trust.js +36 -31
  229. package/src/lib/process-execution-broker/credential-agent.js +114 -16
  230. package/src/lib/process-execution-broker/credential-transport-worker.js +312 -0
  231. package/src/lib/process-execution-broker/credential-transport.js +378 -0
  232. package/src/lib/process-execution-broker/index.js +765 -49
  233. package/src/lib/process-execution-broker/platform-sandbox.js +4233 -138
  234. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  235. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  236. package/src/lib/process-execution-broker/windows-sandbox.cs +3856 -0
  237. package/src/lib/project-mcp-trust.js +21 -26
  238. package/src/lib/protocol-replay.js +19 -12
  239. package/src/lib/repl-bang-memorize.js +67 -10
  240. package/src/lib/settings-hooks.cjs +13 -0
  241. package/src/lib/skill-loader.js +83 -10
  242. package/src/lib/slash-commands.js +27 -4
  243. package/src/lib/sync-credentials.js +5 -4
  244. package/src/lib/turn-binding.js +8 -6
  245. package/src/repl/agent-repl.js +117 -31
  246. package/src/repl/repl-turn-binding.js +5 -2
  247. package/src/runtime/agent-core.js +699 -70
  248. package/src/runtime/agent-runtime.js +13 -1
  249. package/src/runtime/coding-agent-contract-shared.cjs +3 -3
  250. package/src/runtime/headless-runner.js +105 -7
  251. package/src/runtime/headless-stream.js +209 -23
  252. package/src/runtime/mcp-config.js +29 -17
  253. package/src/runtime/policies/agent-policy.js +2 -0
  254. package/src/workers/background-agent-worker.js +128 -13
  255. package/src/assets/web-panel/assets/ChatBubbleRenderer-C7bofJuA.js +0 -1
  256. package/src/assets/web-panel/assets/Projects-BbgmyQnS.js +0 -1
  257. package/src/assets/web-panel/assets/RemoteSession-Bqk3EYSu.js +0 -4
  258. package/src/assets/web-panel/assets/Tasks-3bDAUz8K.js +0 -1
  259. package/src/assets/web-panel/assets/Terminal-CsMLKIoV.js +0 -3
  260. package/src/assets/web-panel/assets/chat-CJ19O6Dh.js +0 -1
  261. package/src/assets/web-panel/assets/devWarning-BBMFnsja.js +0 -1
  262. package/src/assets/web-panel/assets/index-Do8JMV4N.js +0 -1
  263. package/src/assets/web-panel/assets/index-UYAJ6iNM.js +0 -1
@@ -456,7 +456,11 @@ export function previewWorktreeMerge(repoDir, branchName, options = {}) {
456
456
 
457
457
  let mergeStarted = false;
458
458
  try {
459
- gitExec(`merge ${baseBranch} --no-commit --no-ff`, worktree.path);
459
+ // Use argv form here rather than routing through a shell. Besides avoiding
460
+ // another quoting surface, this is important on Windows where a conflicted
461
+ // `git merge` followed immediately by another shell-wrapped git process can
462
+ // race the hosted runner's process/job cleanup and hide the unmerged index.
463
+ gitExecArgs(["merge", baseBranch, "--no-commit", "--no-ff"], worktree.path);
460
464
  mergeStarted = true;
461
465
 
462
466
  return {
@@ -713,7 +717,14 @@ function _hasBranchCommits(repoDir, branchName) {
713
717
 
714
718
  function _collectConflictFiles(repoDir) {
715
719
  try {
716
- const output = gitExec("diff --name-only --diff-filter=U", repoDir);
720
+ // A conflict is expected to make the preceding merge exit non-zero. Query
721
+ // the index with a direct git argv invocation so Windows shell/process
722
+ // teardown cannot turn the authoritative conflict probe into an empty
723
+ // best-effort result.
724
+ const output = gitExecArgs(
725
+ ["diff", "--name-only", "--diff-filter=U"],
726
+ repoDir,
727
+ );
717
728
  return output
718
729
  .split("\n")
719
730
  .map((line) => line.trim())
@@ -988,7 +999,7 @@ function _resolveAutomationCandidate(type, filePath, branchName, candidateId) {
988
999
 
989
1000
  function _abortMergeIfPresent(repoDir) {
990
1001
  try {
991
- gitExec("merge --abort", repoDir);
1002
+ gitExecArgs(["merge", "--abort"], repoDir);
992
1003
  } catch (_e) {
993
1004
  // Ignore if there is no in-progress merge.
994
1005
  }
@@ -6,6 +6,10 @@ import { pathToFileURL } from "node:url";
6
6
  import { dirname, join } from "node:path";
7
7
  import { fileURLToPath } from "node:url";
8
8
  import { readFileSync } from "node:fs";
9
+ import {
10
+ startDefaultEventRuntimeHost,
11
+ stopDefaultEventRuntimeHost,
12
+ } from "./lib/event-runtime-host.js";
9
13
 
10
14
  const __dirname = dirname(fileURLToPath(import.meta.url));
11
15
  const manifest = JSON.parse(
@@ -29,7 +33,28 @@ export function resolveCommandToken(argv = []) {
29
33
  return null;
30
34
  }
31
35
 
32
- export async function runCli(argv) {
36
+ export async function withDefaultEventRuntimeLifecycle(
37
+ task,
38
+ { hostOptions = {} } = {},
39
+ ) {
40
+ if (typeof task !== "function") {
41
+ throw new TypeError("Event Runtime lifecycle task must be a function");
42
+ }
43
+ const host = startDefaultEventRuntimeHost({
44
+ ...hostOptions,
45
+ // Let the selected command finish registering its handlers before the
46
+ // first claim. Resident commands then run on the normal interval; short
47
+ // commands receive a bounded final drain in the finally block.
48
+ immediate: false,
49
+ });
50
+ try {
51
+ return await task(host);
52
+ } finally {
53
+ if (host) await stopDefaultEventRuntimeHost({ drain: true });
54
+ }
55
+ }
56
+
57
+ async function dispatchCli(argv) {
33
58
  const args = argv.slice(2);
34
59
 
35
60
  // Resolve the command before deciding whether help/version needs the eager
@@ -95,6 +120,10 @@ export async function runCli(argv) {
95
120
  }
96
121
  }
97
122
 
123
+ export async function runCli(argv) {
124
+ return withDefaultEventRuntimeLifecycle(() => dispatchCli(argv));
125
+ }
126
+
98
127
  export class LazyDispatch {
99
128
  constructor(manifest) {
100
129
  this.manifest = manifest;
@@ -154,6 +154,28 @@ export function canManageSession(envelope = {}) {
154
154
  );
155
155
  }
156
156
 
157
+ /**
158
+ * True when this envelope may answer a human-interaction request. A local UI
159
+ * owns this authority. A remote peer must be authenticated and explicitly
160
+ * paired for prompt/approve/manage control; observe-only peers cannot answer.
161
+ */
162
+ export function canAnswerInteraction(envelope = {}) {
163
+ if (envelope.origin === ORIGIN.USER) return true;
164
+ if (envelope.origin !== ORIGIN.REMOTE || envelope.authenticated !== true) {
165
+ return false;
166
+ }
167
+ const scopes = normalizeScopes(envelope);
168
+ return scopes.has("prompt") || scopes.has("approve") || scopes.has("manage");
169
+ }
170
+
171
+ export function assertCanAnswerInteraction(envelope = {}) {
172
+ if (canAnswerInteraction(envelope)) return;
173
+ const who = envelope.origin || "unknown";
174
+ throw new Error(
175
+ `origin "${who}" is not authorized to answer interaction requests`,
176
+ );
177
+ }
178
+
157
179
  /**
158
180
  * Throw a clear, log-safe error when an envelope is NOT allowed to approve.
159
181
  * Callers gate every "resolve a permission" seam through this so the rule
@@ -12,6 +12,7 @@ export {
12
12
  getAgentToolDefinitions,
13
13
  getAgentToolDescriptors,
14
14
  getCachedPython,
15
+ _resetCachedPythonForTests,
15
16
  getEnvironmentInfo,
16
17
  _environmentProcessDeps,
17
18
  _agentToolProcessDeps,
@@ -51,5 +52,7 @@ export {
51
52
  _resetFileFreshness,
52
53
  _getSharedCodeIntel,
53
54
  disposeSharedCodeIntel,
55
+ emitToolHookLifecycle,
56
+ emitToolBatchHookLifecycle,
54
57
  _resetSubtreeInstructionLoaders,
55
58
  } from "../runtime/agent-core.js";
@@ -1,4 +1,5 @@
1
1
  /** OS-isolated shell execution for the coding agent. */
2
+ import fs from "node:fs";
2
3
  import path from "node:path";
3
4
  import { proxyEnv } from "./sandbox-egress-proxy.js";
4
5
  import executionBroker from "./process-execution-broker/index.js";
@@ -29,6 +30,166 @@ function resolvePolicyPaths(entries, cwd) {
29
30
  });
30
31
  }
31
32
 
33
+ function pathEntryExists(candidate, fsImpl) {
34
+ try {
35
+ fsImpl.lstatSync(candidate);
36
+ return true;
37
+ } catch (error) {
38
+ if (error?.code === "ENOENT" || error?.code === "ENOTDIR") return false;
39
+ throw error;
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Resolve a path for policy comparison without requiring the final target to
45
+ * exist. Existing ancestors are resolved through symlinks/junctions before the
46
+ * missing suffix is appended. This is important for writes: checking only the
47
+ * lexical target lets `workspace/link/new-file` escape when `link` points
48
+ * outside the workspace.
49
+ */
50
+ function canonicalPolicyPath(candidate, fsImpl) {
51
+ const absolute = path.resolve(candidate);
52
+ let existing = absolute;
53
+ const missing = [];
54
+
55
+ while (!pathEntryExists(existing, fsImpl)) {
56
+ const parent = path.dirname(existing);
57
+ if (parent === existing) {
58
+ throw new Error(`No existing ancestor for path: ${absolute}`);
59
+ }
60
+ missing.unshift(path.basename(existing));
61
+ existing = parent;
62
+ }
63
+
64
+ const realpath =
65
+ typeof fsImpl.realpathSync?.native === "function"
66
+ ? fsImpl.realpathSync.native
67
+ : fsImpl.realpathSync;
68
+ if (typeof realpath !== "function") {
69
+ throw new Error("Filesystem realpath support is unavailable");
70
+ }
71
+ return path.resolve(realpath(existing), ...missing);
72
+ }
73
+
74
+ function pathIsWithin(candidate, root) {
75
+ const relative = path.relative(root, candidate);
76
+ return (
77
+ relative === "" ||
78
+ (relative !== ".." &&
79
+ !relative.startsWith(`..${path.sep}`) &&
80
+ !path.isAbsolute(relative))
81
+ );
82
+ }
83
+
84
+ function normalizeWorkspaceRoots(entries, cwd) {
85
+ const roots =
86
+ Array.isArray(entries) && entries.length > 0 ? entries : [cwd];
87
+ return stringList(roots).map((entry) => path.resolve(cwd, entry));
88
+ }
89
+
90
+ /**
91
+ * Resolve and authorize one built-in agent file-tool path.
92
+ *
93
+ * The workspace roots are always allowed. A normalized sandbox policy may add
94
+ * explicit read/write roots and may deny narrower paths. Both existing targets
95
+ * and the nearest existing ancestor are realpath-resolved, so an in-workspace
96
+ * symlink/junction cannot redirect a read or write outside the declared roots.
97
+ *
98
+ * @returns {{
99
+ * ok:boolean,
100
+ * path?:string,
101
+ * canonicalPath?:string,
102
+ * reason?:string,
103
+ * error?:string
104
+ * }}
105
+ */
106
+ export function resolveSandboxPolicyPath(
107
+ requestedPath,
108
+ {
109
+ access = "read",
110
+ cwd = process.cwd(),
111
+ workspaceRoots = null,
112
+ sandbox = null,
113
+ policy = sandbox?.policy || null,
114
+ fsImpl = null,
115
+ } = {},
116
+ ) {
117
+ if (access !== "read" && access !== "write") {
118
+ return {
119
+ ok: false,
120
+ reason: "invalid-access",
121
+ error: `Unsupported filesystem access mode: ${access}`,
122
+ };
123
+ }
124
+ if (
125
+ typeof requestedPath !== "string" ||
126
+ requestedPath.length === 0 ||
127
+ requestedPath.includes("\0")
128
+ ) {
129
+ return {
130
+ ok: false,
131
+ reason: "invalid-path",
132
+ error: "A non-empty filesystem path is required",
133
+ };
134
+ }
135
+
136
+ const resolvedCwd = path.resolve(cwd);
137
+ const resolvedPath = path.resolve(resolvedCwd, requestedPath);
138
+ const effectiveFs = fsImpl || fs;
139
+ const normalizedPolicy = policy || {};
140
+ const policyAllows =
141
+ access === "write"
142
+ ? normalizedPolicy.allowWrite
143
+ : normalizedPolicy.allowRead;
144
+ const policyDenies =
145
+ access === "write"
146
+ ? normalizedPolicy.denyWrite
147
+ : normalizedPolicy.denyRead;
148
+ const allowedInputs = [
149
+ ...normalizeWorkspaceRoots(workspaceRoots, resolvedCwd),
150
+ ...resolvePolicyPaths(policyAllows, resolvedCwd),
151
+ ];
152
+ const deniedInputs = resolvePolicyPaths(policyDenies, resolvedCwd);
153
+
154
+ try {
155
+ const canonicalPath = canonicalPolicyPath(resolvedPath, effectiveFs);
156
+ const allowedRoots = allowedInputs.map((root) =>
157
+ canonicalPolicyPath(root, effectiveFs),
158
+ );
159
+ if (!allowedRoots.some((root) => pathIsWithin(canonicalPath, root))) {
160
+ return {
161
+ ok: false,
162
+ path: resolvedPath,
163
+ canonicalPath,
164
+ reason: "outside-workspace",
165
+ error: `${access} path resolves outside the allowed workspace roots`,
166
+ };
167
+ }
168
+
169
+ const deniedRoots = deniedInputs.map((root) =>
170
+ canonicalPolicyPath(root, effectiveFs),
171
+ );
172
+ if (deniedRoots.some((root) => pathIsWithin(canonicalPath, root))) {
173
+ return {
174
+ ok: false,
175
+ path: resolvedPath,
176
+ canonicalPath,
177
+ reason: "denied-by-policy",
178
+ error: `${access} path is denied by the sandbox filesystem policy`,
179
+ };
180
+ }
181
+
182
+ return { ok: true, path: resolvedPath, canonicalPath };
183
+ } catch (error) {
184
+ return {
185
+ ok: false,
186
+ path: resolvedPath,
187
+ reason: "realpath-failed",
188
+ error: `Unable to safely resolve filesystem path: ${error.message}`,
189
+ };
190
+ }
191
+ }
192
+
32
193
  export function normalizeSandboxPolicy(settings = {}, cwd = process.cwd()) {
33
194
  const filesystem = settings.filesystem || {};
34
195
  const network = settings.network || {};
@@ -48,6 +48,14 @@ function normalizeJitterMs(v) {
48
48
  return Number.isFinite(n) && n > 0 ? n : 0;
49
49
  }
50
50
 
51
+ function normalizeMonitorWorkspaceCwd(value) {
52
+ if (value == null) return null;
53
+ if (typeof value !== "string" || value.length === 0) {
54
+ throw new Error("monitor workspaceCwd must be a non-empty string");
55
+ }
56
+ return path.resolve(value);
57
+ }
58
+
51
59
  /**
52
60
  * A per-task execution policy for wakeup/cron entries — how the spawned
53
61
  * `cc agent` run should behave when this entry fires. Each field maps to a real
@@ -388,6 +396,7 @@ export class AgentScheduleStore {
388
396
 
389
397
  createMonitor({
390
398
  command,
399
+ workspaceCwd = null,
391
400
  watchFile = null,
392
401
  watchUrl = null,
393
402
  watchChange = false,
@@ -443,16 +452,22 @@ export class AgentScheduleStore {
443
452
  if (stopWhen != null) {
444
453
  // Validate the regex up-front so a bad pattern errors at creation, not
445
454
  // silently at the first check.
446
- // eslint-disable-next-line no-new
455
+
447
456
  new RegExp(stopWhen);
448
457
  }
449
458
  const now = this._now();
450
459
  const source = hasFile ? "file" : hasUrl ? "http" : "command";
460
+ const normalizedWorkspaceCwd = hasCommand
461
+ ? normalizeMonitorWorkspaceCwd(workspaceCwd)
462
+ : null;
451
463
  const entry = {
452
464
  id: randomUUID(),
453
465
  kind: "monitor",
454
466
  source,
455
467
  command: hasCommand ? command : null,
468
+ ...(normalizedWorkspaceCwd
469
+ ? { workspaceCwd: normalizedWorkspaceCwd }
470
+ : {}),
456
471
  watchFile: hasFile ? watchFile : null,
457
472
  watchUrl: hasUrl ? watchUrl : null,
458
473
  watchChange: hasFile ? Boolean(watchChange) : false,
@@ -513,28 +528,36 @@ export class AgentScheduleStore {
513
528
  const now = atMs != null ? Number(atMs) : this._now();
514
529
  const ttl = Math.max(1000, Number(leaseMs) || 120000);
515
530
  this._ensureDir();
516
- return withFileLock(path.join(this.dir, ".agenda-claims"), () => {
517
- const claimed = [];
518
- for (const kind of SCHEDULE_KINDS) {
519
- const entries = this._readAll(kind);
520
- let changed = false;
521
- for (const entry of entries) {
522
- if (!isSchedulableStatus(entry) || isEntryExpired(entry, now)) continue;
523
- if (hasLiveExecutionLease(entry, now)) continue;
524
- const fireAt = effectiveFireAt(entry);
525
- if (fireAt == null || fireAt > now) continue;
526
- entry.executionLease = {
527
- owner: `${process.pid}:${randomUUID()}`,
528
- claimedAt: now,
529
- expiresAt: now + ttl,
530
- };
531
- claimed.push({ ...entry, executionLease: { ...entry.executionLease } });
532
- changed = true;
531
+ return withFileLock(
532
+ path.join(this.dir, ".agenda-claims"),
533
+ () => {
534
+ const claimed = [];
535
+ for (const kind of SCHEDULE_KINDS) {
536
+ const entries = this._readAll(kind);
537
+ let changed = false;
538
+ for (const entry of entries) {
539
+ if (!isSchedulableStatus(entry) || isEntryExpired(entry, now))
540
+ continue;
541
+ if (hasLiveExecutionLease(entry, now)) continue;
542
+ const fireAt = effectiveFireAt(entry);
543
+ if (fireAt == null || fireAt > now) continue;
544
+ entry.executionLease = {
545
+ owner: `${process.pid}:${randomUUID()}`,
546
+ claimedAt: now,
547
+ expiresAt: now + ttl,
548
+ };
549
+ claimed.push({
550
+ ...entry,
551
+ executionLease: { ...entry.executionLease },
552
+ });
553
+ changed = true;
554
+ }
555
+ if (changed) this._writeAll(kind, entries);
533
556
  }
534
- if (changed) this._writeAll(kind, entries);
535
- }
536
- return claimed;
537
- }, { failIfUnavailable: true });
557
+ return claimed;
558
+ },
559
+ { failIfUnavailable: true },
560
+ );
538
561
  }
539
562
 
540
563
  /** Release a failed/aborted claim so a later runner can retry it. */
@@ -14,6 +14,8 @@
14
14
  * status panel. A total-time / total-task budget bounds a runaway graph.
15
15
  */
16
16
 
17
+ import { emitHooksV2Event } from "../hooks-v2-producers.js";
18
+
17
19
  export class TeamRunner {
18
20
  /**
19
21
  * @param {TaskLeaseRegistry} registry
@@ -33,6 +35,8 @@ export class TeamRunner {
33
35
  // Lease-renewal heartbeat cadence while a task runs (default ttl/3).
34
36
  this.renewEveryMs = opts.renewEveryMs;
35
37
  this.onEvent = typeof opts.onEvent === "function" ? opts.onEvent : () => {};
38
+ this.emitHook =
39
+ typeof opts.emitHook === "function" ? opts.emitHook : emitHooksV2Event;
36
40
  this.maxTasks = opts.maxTasks > 0 ? opts.maxTasks : 1000;
37
41
  this._now = opts.now || registry._now || (() => Date.now());
38
42
  // Team-wide token/USD/time/task budget (null → unbounded). Consulted before
@@ -80,8 +84,26 @@ export class TeamRunner {
80
84
  return m;
81
85
  }
82
86
  if (m.state === state) return m; // no transition
87
+ const previousState = m.state;
83
88
  m.state = state;
84
89
  this._emit("teammate:state", { holder, state, ...extra });
90
+ // Initial registration starts in `idle`; the hook is reserved for a real
91
+ // transition back to idle after a teammate has participated in the run.
92
+ if (state === "idle" && previousState !== null) {
93
+ try {
94
+ this.emitHook("TeammateIdle", {
95
+ schema_version: 1,
96
+ holder,
97
+ state,
98
+ previous_state: previousState,
99
+ completed: m.completed,
100
+ failed: m.failed,
101
+ ...extra,
102
+ });
103
+ } catch {
104
+ /* hook observer is best-effort */
105
+ }
106
+ }
85
107
  return m;
86
108
  }
87
109
 
@@ -40,6 +40,41 @@ export const MAX_ARTIFACT_BYTES = 100 * 1024 * 1024; // 100 MB
40
40
  /** Default retention before `clean` removes an artifact. */
41
41
  export const DEFAULT_TTL_DAYS = 30;
42
42
 
43
+ /**
44
+ * Metadata safe to return across the agent/session protocol boundary.
45
+ *
46
+ * The persisted index deliberately retains sourcePath for local artifact
47
+ * management, but absolute source paths are host details and must not enter
48
+ * model transcripts or remote-session payloads.
49
+ */
50
+ export function publicArtifactMetadata(entry) {
51
+ if (!entry || typeof entry !== "object") return null;
52
+ const {
53
+ id,
54
+ title,
55
+ kind,
56
+ mime,
57
+ size,
58
+ sha256,
59
+ file,
60
+ sessionId,
61
+ createdAt,
62
+ expiresAt,
63
+ } = entry;
64
+ return {
65
+ id,
66
+ title,
67
+ kind,
68
+ mime,
69
+ size,
70
+ sha256,
71
+ file,
72
+ sessionId,
73
+ createdAt,
74
+ expiresAt,
75
+ };
76
+ }
77
+
43
78
  const MIME_BY_EXT = Object.freeze({
44
79
  ".md": "text/markdown",
45
80
  ".markdown": "text/markdown",
@@ -32,7 +32,10 @@
32
32
  * testable with fake child processes (no real shell).
33
33
  */
34
34
 
35
- const { tryParseDecision } = require("./hook-runner.cjs");
35
+ const {
36
+ tryParseDecision,
37
+ resolveHookSandboxPolicy,
38
+ } = require("./hook-runner.cjs");
36
39
 
37
40
  const DEFAULT_TIMEOUT_MS = 60000;
38
41
  const MAX_TIMEOUT_MS = 600000;
@@ -359,6 +362,7 @@ class AsyncHookSupervisor {
359
362
 
360
363
  let child;
361
364
  try {
365
+ const sandboxPolicy = resolveHookSandboxPolicy(hook, opts);
362
366
  const spawnOptions = {
363
367
  cwd: opts.cwd || process.cwd(),
364
368
  shell: true,
@@ -370,6 +374,7 @@ class AsyncHookSupervisor {
370
374
  ...process.env,
371
375
  CLAUDE_HOOK_EVENT: hook.event || payload.hook_event_name || "",
372
376
  },
377
+ ...(sandboxPolicy ? { sandboxPolicy } : {}),
373
378
  };
374
379
  if (typeof this._deps.run !== "function") {
375
380
  throw new Error("async hook process runner unavailable");
@@ -384,10 +389,15 @@ class AsyncHookSupervisor {
384
389
  pluginSource: hook.pluginSource || null,
385
390
  });
386
391
  } catch (err) {
392
+ const sandboxDenied =
393
+ err?.code === "ERR_PROCESS_SANDBOX_BOUNDARY_UNSATISFIED";
387
394
  this._record(hook, {
388
395
  ok: false,
389
396
  exitCode: null,
390
- error: `hook spawn failed: ${err.message}`,
397
+ error: sandboxDenied
398
+ ? `hook sandbox denied: ${err.message}`
399
+ : `hook spawn failed: ${err.message}`,
400
+ sandboxDenied,
391
401
  started,
392
402
  });
393
403
  return;
@@ -483,6 +493,7 @@ class AsyncHookSupervisor {
483
493
  error: fields.error || null,
484
494
  additionalContext: fields.additionalContext || null,
485
495
  blocked: !!fields.blocked,
496
+ ...(fields.sandboxDenied === true ? { sandboxDenied: true } : {}),
486
497
  asyncRewake: hook.asyncRewake === true,
487
498
  ts: now,
488
499
  ms: fields.started != null ? now - fields.started : 0,
@@ -322,11 +322,12 @@ export function closeBatch(dir, opts = {}) {
322
322
  // across processes. Without it, two concurrent closes (e.g. overlapping
323
323
  // `cc audit mtc reconcile` runs) both scan the same staging events, allocate
324
324
  // the same batch id, and the defensive rmSync(finalDir) lets the second
325
- // silently overwrite the first's audit batch. Best-effort lock (never hangs);
326
- // generous timeout since the section includes Merkle assembly + signing.
325
+ // silently overwrite the first's audit batch. Audit ledger state is critical:
326
+ // bounded contention must fail closed rather than assemble an unlocked batch.
327
327
  ensureDirs(dir);
328
328
  return withFileLock(batchesDir(dir), () => _closeBatchImpl(dir, opts), {
329
329
  timeoutMs: 15000,
330
+ failIfUnavailable: true,
330
331
  });
331
332
  }
332
333