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
@@ -23,6 +23,7 @@ import { MCPClient, MCPServerConfig } from "../harness/mcp-client.js";
23
23
  import sharedManagedToolPolicy from "./coding-agent-managed-tool-policy.cjs";
24
24
  import { findProjectRoot, loadProjectConfig } from "../lib/project-detector.js";
25
25
  import { loadConfig } from "../lib/config-manager.js";
26
+ import { collectWorkspacePluginBinSandboxPolicy } from "../lib/plugin-runtime/bin.js";
26
27
 
27
28
  const {
28
29
  DEFAULT_ALLOWED_MCP_SERVER_NAMES,
@@ -63,6 +64,8 @@ export class AgentRuntime {
63
64
  createSessionManager:
64
65
  deps.createSessionManager ||
65
66
  ((options) => new WSSessionManager(options)),
67
+ createPtyManager:
68
+ deps.createPtyManager || ((options) => new PtyManager(options)),
66
69
  createMcpClient: deps.createMcpClient || (() => new MCPClient()),
67
70
  createMcpServerConfig:
68
71
  deps.createMcpServerConfig || ((db) => new MCPServerConfig(db)),
@@ -449,6 +452,7 @@ export class AgentRuntime {
449
452
  const projectName =
450
453
  projectConfig?.name || (projectRoot ? path.basename(projectRoot) : null);
451
454
  const mode = projectRoot ? "project" : "global";
455
+ const workspacePolicyCwd = path.resolve(projectRoot || process.cwd());
452
456
 
453
457
  let db = null;
454
458
  let rawDb = null;
@@ -492,6 +496,7 @@ export class AgentRuntime {
492
496
  maxConnections: 20,
493
497
  timeout: 60000,
494
498
  sessionManager,
499
+ projectRoot: workspacePolicyCwd,
495
500
  });
496
501
  // ChainlessChainWSServer extends EventEmitter and emits "error"
497
502
  // synchronously on bind failure (in addition to rejecting start()).
@@ -530,7 +535,14 @@ export class AgentRuntime {
530
535
  // matching topics through `terminalHandlers.handlers`, falling back to
531
536
  // the original CLI dispatcher for everything else.
532
537
  const wsBroadcastRef = { current: null };
533
- const ptyManager = new PtyManager();
538
+ const ptyManager = this.deps.createPtyManager({
539
+ policyCwd: workspacePolicyCwd,
540
+ resolveSandboxPolicy: ({ workspaceCwd, executionCwd }) =>
541
+ collectWorkspacePluginBinSandboxPolicy({
542
+ workspaceCwd,
543
+ executionCwd,
544
+ }),
545
+ });
534
546
  const terminal = createTerminalHandlers({
535
547
  ptyManager,
536
548
  broadcast: (frame) => wsBroadcastRef.current?.(frame),
@@ -1155,7 +1155,7 @@ const CODING_AGENT_TOOL_CONTRACTS = Object.freeze([
1155
1155
  kind: "browser",
1156
1156
  tier: "extension",
1157
1157
  description:
1158
- "Capture live state from the user's real Chrome over CDP: current URL/title, open tabs, console messages and failed/error network requests observed during a short watch window, a capped DOM snapshot, and optionally a screenshot (saved to a temp file whose path is returned). Requires a debuggable Chrome — the user starts one with `cc browse chrome launch`. Console/network capture starts at attach time (CDP keeps no history) — set reload=true to observe load-time errors. Use to verify web changes in the user's logged-in browser.",
1158
+ "Capture live state from the user's real Chrome over CDP: current URL/title, open tabs, console messages and failed/error network requests observed during a short watch window, a capped DOM snapshot, and optionally a screenshot (published as a session-bound Artifact; no host temp path enters the agent result). Requires a debuggable Chrome — the user starts one with `cc browse chrome launch`. Console/network capture starts at attach time (CDP keeps no history) — set reload=true to observe load-time errors. Use to verify web changes in the user's logged-in browser.",
1159
1159
  inputSchema: {
1160
1160
  type: "object",
1161
1161
  properties: {
@@ -1187,7 +1187,7 @@ const CODING_AGENT_TOOL_CONTRACTS = Object.freeze([
1187
1187
  screenshot: {
1188
1188
  type: "boolean",
1189
1189
  description:
1190
- "Save a screenshot to a generated temp file and return its path (default false)",
1190
+ "Capture a screenshot and return opaque, session-bound Artifact metadata (default false)",
1191
1191
  },
1192
1192
  },
1193
1193
  required: [],
@@ -1208,7 +1208,7 @@ const CODING_AGENT_TOOL_CONTRACTS = Object.freeze([
1208
1208
  kind: "browser",
1209
1209
  tier: "extension",
1210
1210
  description:
1211
- "Perform EXPLICIT actions in the user's connected Chrome over loopback CDP: click, type, press, navigate (http/https only), waitForSelector, screenshot (saved to a generated temp path — never a chosen one), assertText. Approval-gated (HIGH risk): use browser_state first to observe; only act when the task genuinely requires driving the browser. Steps run in order and fail fast unless continue_on_error; each returns {ok, action, detail, durationMs} and every executed step is audit-logged under ~/.chainlesschain/browser-actions/. Requires a debuggable Chrome (`cc browse chrome launch`).",
1211
+ "Perform EXPLICIT actions in the user's connected Chrome over loopback CDP: click, type, press, navigate (http/https only), waitForSelector, screenshot (published as a session-bound Artifact; never a caller-chosen path), assertText. Approval-gated (HIGH risk): use browser_state first to observe; only act when the task genuinely requires driving the browser. Steps run in order and fail fast unless continue_on_error; each returns {ok, action, detail, durationMs} and every executed step is audit-logged under ~/.chainlesschain/browser-actions/. Requires a debuggable Chrome (`cc browse chrome launch`).",
1212
1212
  inputSchema: {
1213
1213
  type: "object",
1214
1214
  properties: {
@@ -61,6 +61,11 @@ import { SIDE_EFFECT_LEDGER_EVENT } from "../lib/side-effect-ledger-store.js";
61
61
  import { TurnBindingLog, createTurnBindingFeed } from "../lib/turn-binding.js";
62
62
  import { TURN_BINDING_EVENT } from "../lib/turn-binding-store.js";
63
63
  import { operationIdempotencyKey } from "../lib/idempotency.js";
64
+ import {
65
+ emitHooksV2Event,
66
+ executeHooksV2Event,
67
+ resolvePromptExpansion,
68
+ } from "../lib/hooks-v2-producers.js";
64
69
  import { CLISkillLoader } from "../lib/skill-loader.js";
65
70
  import { expandFileRefsAsync } from "./file-ref-expander.js";
66
71
  import { composeSystemPrompt } from "./system-prompt.js";
@@ -367,6 +372,7 @@ export async function runAgentHeadless(options = {}, deps = {}) {
367
372
  // every existing risk-tier / shell-policy layer runs unchanged.
368
373
  let permissionRules = options.permissionRules || null;
369
374
  let managedSettings = null;
375
+ let settingsFiles = [];
370
376
  try {
371
377
  const { loadSettings, applyManagedPermissionPolicy } =
372
378
  await import("../lib/settings-loader.cjs");
@@ -376,6 +382,7 @@ export async function runAgentHeadless(options = {}, deps = {}) {
376
382
  managedSettingsFile: options.managedSettingsFile,
377
383
  });
378
384
  managedSettings = loaded.managed;
385
+ settingsFiles = Array.isArray(loaded.files) ? loaded.files : [];
379
386
  if (!permissionRules) {
380
387
  const total =
381
388
  loaded.rules.allow.length +
@@ -426,9 +433,10 @@ export async function runAgentHeadless(options = {}, deps = {}) {
426
433
  }
427
434
  }
428
435
 
429
- // Put trusted plugins' bin/ executables on PATH for this headless run (Phase
430
- // 3.3n) so run_shell can invoke them by name. Trust-gated. The process exits
431
- // at the end of the run, so no explicit restore is needed.
436
+ // Preserve PATH compatibility for trusted legacy bin components that have no
437
+ // sandboxPolicy. Policy-bearing bins are excluded here and resolved as exact
438
+ // direct Broker invocations by agent-core. The process exits at the end of
439
+ // the run, so no explicit restore is needed.
432
440
  try {
433
441
  const { applyPluginBinPath } = await import("../lib/plugin-runtime/bin.js");
434
442
  applyPluginBinPath({ cwd });
@@ -465,6 +473,7 @@ export async function runAgentHeadless(options = {}, deps = {}) {
465
473
 
466
474
  const runLoop = deps.agentLoop || coreAgentLoop;
467
475
  const doBootstrap = deps.bootstrap || bootstrap;
476
+ const executeLifecycleHooks = deps.executeHooksV2Event || executeHooksV2Event;
468
477
  const getApprovalGate =
469
478
  deps.getApprovalGate ||
470
479
  (async () => {
@@ -681,6 +690,48 @@ export async function runAgentHeadless(options = {}, deps = {}) {
681
690
  }
682
691
  };
683
692
 
693
+ const setupHooks = await executeLifecycleHooks(
694
+ "Setup",
695
+ {
696
+ schema_version: 1,
697
+ session_id: sessionId,
698
+ cwd,
699
+ database_available: db != null,
700
+ enabled_tools: enabledToolNames,
701
+ settings_files: settingsFiles,
702
+ },
703
+ { failClosed: true },
704
+ );
705
+ if (setupHooks.blocked || setupHooks.decision === "block") {
706
+ const reason =
707
+ setupHooks.blockingResult?.reason ||
708
+ setupHooks.error ||
709
+ "blocked by Setup hook";
710
+ writeErr(`[hook] ${reason}\n`);
711
+ emitHeadlessError(reason);
712
+ return { exitCode: 2, result: reason, isError: true };
713
+ }
714
+
715
+ const expansionHooks = await executeLifecycleHooks(
716
+ "UserPromptExpansion",
717
+ {
718
+ schema_version: 1,
719
+ session_id: sessionId,
720
+ cwd,
721
+ prompt: userContent,
722
+ original_prompt: prompt,
723
+ },
724
+ { failClosed: true },
725
+ );
726
+ const expansion = resolvePromptExpansion(userContent, expansionHooks);
727
+ if (expansion.blocked) {
728
+ const reason = expansion.reason || "blocked by UserPromptExpansion hook";
729
+ writeErr(`[hook] ${reason}\n`);
730
+ emitHeadlessError(reason);
731
+ return { exitCode: 2, result: reason, isError: true };
732
+ }
733
+ userContent = expansion.prompt;
734
+
684
735
  // Load prior conversation when resuming an existing session. The fresh
685
736
  // system prompt always leads; we drop any persisted system turns so it is
686
737
  // never duplicated.
@@ -1033,8 +1084,7 @@ export async function runAgentHeadless(options = {}, deps = {}) {
1033
1084
  let _loadedInstructions = null;
1034
1085
  let _loadedPersonaSkills = [];
1035
1086
  let _skillCacheLedger = null;
1036
- const _runtimeSkillLoader =
1037
- options.skillLoader || new CLISkillLoader();
1087
+ const _runtimeSkillLoader = options.skillLoader || new CLISkillLoader();
1038
1088
  const systemContent = composeSystemPrompt(
1039
1089
  buildSystemPrompt(cwd, {
1040
1090
  additionalDirectories,
@@ -1967,6 +2017,11 @@ export async function runAgentHeadless(options = {}, deps = {}) {
1967
2017
  // P0-2: settle the in-flight side-effect (commit on success, fail on
1968
2018
  // a clean error) and persist the updated ledger snapshot.
1969
2019
  if (persist && currentSideEffectOpId) {
2020
+ if (event.permission_decision) {
2021
+ sideEffectLedger.annotate(currentSideEffectOpId, {
2022
+ permissionDecision: event.permission_decision,
2023
+ });
2024
+ }
1970
2025
  if (event.result?._diffReviewAudit) {
1971
2026
  diffReviewFollowUps.observe(
1972
2027
  sideEffectLedger,
@@ -1991,6 +2046,12 @@ export async function runAgentHeadless(options = {}, deps = {}) {
1991
2046
  is_error: Boolean(err),
1992
2047
  error: err,
1993
2048
  result: event.result,
2049
+ ...(event.permission_decision_id
2050
+ ? { permission_decision_id: event.permission_decision_id }
2051
+ : {}),
2052
+ ...(event.permission_decision
2053
+ ? { permission_decision: event.permission_decision }
2054
+ : {}),
1994
2055
  });
1995
2056
  if (toolCalls.length > 0) {
1996
2057
  toolCalls[toolCalls.length - 1].is_error = Boolean(err);
@@ -2351,7 +2412,30 @@ export async function runAgentHeadless(options = {}, deps = {}) {
2351
2412
  const { runObserveHooks, dispatchAsyncHooks } =
2352
2413
  await import("../lib/settings-hook-events.js");
2353
2414
  const stopPayload = { reason: endReason, cwd, session_id: sessionId };
2354
- runObserveHooks(settingsHooks, "Stop", stopPayload, { cwd });
2415
+ const stopOutcome = runObserveHooks(
2416
+ settingsHooks,
2417
+ "Stop",
2418
+ stopPayload,
2419
+ { cwd },
2420
+ );
2421
+ const stopFailures = (stopOutcome?.results || []).filter(
2422
+ (result) =>
2423
+ result?.nonBlockingError === true ||
2424
+ result?.malformedDecision === true ||
2425
+ result?.breakerOpen === true,
2426
+ );
2427
+ if (stopFailures.length > 0) {
2428
+ emitHooksV2Event("StopFailure", {
2429
+ schema_version: 1,
2430
+ session_id: sessionId,
2431
+ phase: "stop-hook",
2432
+ failures: stopFailures.map((failure) => ({
2433
+ command: failure.command || null,
2434
+ exit_code: failure.exitCode ?? null,
2435
+ reason: failure.reason || failure.error || null,
2436
+ })),
2437
+ });
2438
+ }
2355
2439
  // Skip the async Stop dispatch/settle here if the auto-rewake re-drive
2356
2440
  // loop already fired + drained it this run (avoids double-execution).
2357
2441
  if (_hookSupervisor && !_asyncStopHandled) {
@@ -2377,6 +2461,14 @@ export async function runAgentHeadless(options = {}, deps = {}) {
2377
2461
  // re-engage the agent in an interactive session — flag it clearly so a
2378
2462
  // headless caller/CI can react.
2379
2463
  for (const rw of _hookSupervisor.drainRewakes()) {
2464
+ emitHooksV2Event("StopFailure", {
2465
+ schema_version: 1,
2466
+ session_id: sessionId,
2467
+ phase: "async-stop-hook",
2468
+ command: rw.command || null,
2469
+ exit_code: rw.exitCode ?? null,
2470
+ reason: rw.error || "async stop hook requested rewake",
2471
+ });
2380
2472
  writeErr(
2381
2473
  `[async-hook REWAKE] ${rw.command} failed` +
2382
2474
  `${rw.exitCode != null ? ` (exit ${rw.exitCode})` : ""}` +
@@ -2398,7 +2490,13 @@ export async function runAgentHeadless(options = {}, deps = {}) {
2398
2490
  { reason: "completed", cwd, session_id: sessionId },
2399
2491
  { cwd },
2400
2492
  );
2401
- } catch {
2493
+ } catch (error) {
2494
+ emitHooksV2Event("StopFailure", {
2495
+ schema_version: 1,
2496
+ session_id: sessionId,
2497
+ phase: "stop-hook-dispatch",
2498
+ reason: error?.message || String(error),
2499
+ });
2402
2500
  // observe-only + best-effort async surfacing
2403
2501
  }
2404
2502
  }
@@ -21,6 +21,15 @@ import {
21
21
  approvalBindingDigest,
22
22
  verifyApprovalBinding,
23
23
  } from "../lib/agent-authority.js";
24
+ import {
25
+ normalizeInteractionBinding,
26
+ sameInteractionBinding,
27
+ } from "../lib/interaction-binding.js";
28
+ import {
29
+ emitHooksV2Event,
30
+ executeHooksV2Event,
31
+ resolvePromptExpansion,
32
+ } from "../lib/hooks-v2-producers.js";
24
33
  import { bootstrap } from "./bootstrap.js";
25
34
  import { buildSystemPrompt, agentLoop as coreAgentLoop } from "./agent-core.js";
26
35
  import { composeSystemPrompt } from "./system-prompt.js";
@@ -183,6 +192,15 @@ export function createStreamCoalescer({
183
192
  const gateOn = (field) => !fieldGate || fieldGate[field] !== false;
184
193
  const rawEmit = (obj) => {
185
194
  let line = obj;
195
+ if (
196
+ !gateOn("permission_decision") &&
197
+ (Object.prototype.hasOwnProperty.call(line, "permission_decision") ||
198
+ Object.prototype.hasOwnProperty.call(line, "permission_decision_id"))
199
+ ) {
200
+ line = { ...line };
201
+ delete line.permission_decision;
202
+ delete line.permission_decision_id;
203
+ }
186
204
  if (traceId && gateOn("trace_id")) line = { ...line, trace_id: traceId };
187
205
  if (stampSeq && gateOn("seq")) line = { ...line, seq: ++seq };
188
206
  writeOut(JSON.stringify(line) + "\n");
@@ -488,6 +506,9 @@ export function parseInputEvent(line) {
488
506
  answer: {
489
507
  id: String(obj.id),
490
508
  value: obj.answer === undefined ? null : obj.answer,
509
+ ...(obj.binding && typeof obj.binding === "object"
510
+ ? { binding: normalizeInteractionBinding(obj.binding) }
511
+ : {}),
491
512
  },
492
513
  };
493
514
  }
@@ -761,8 +782,7 @@ async function runTurn(
761
782
  // agent-sdk docs/PROTOCOL.md §1.2.1): the matching tool_result below
762
783
  // echoes the same id so UIs can pair calls without adjacency.
763
784
  const toolUseId =
764
- event.tool_use_id ||
765
- (nextToolUseId ? nextToolUseId() : undefined);
785
+ event.tool_use_id || (nextToolUseId ? nextToolUseId() : undefined);
766
786
  const pm = getPlanModeManager();
767
787
  const planItem = pm.startPlanItemForTool(event.tool, {
768
788
  toolUseId,
@@ -822,6 +842,11 @@ async function runTurn(
822
842
  // P0-2: settle the in-flight side-effect (commit on success, fail on
823
843
  // a clean error) and persist the updated ledger snapshot.
824
844
  if (sideEffects && currentSideEffectOpId) {
845
+ if (event.permission_decision) {
846
+ sideEffects.ledger.annotate(currentSideEffectOpId, {
847
+ permissionDecision: event.permission_decision,
848
+ });
849
+ }
825
850
  if (event.result?._diffReviewAudit) {
826
851
  diffReviewFollowUps.observe(
827
852
  sideEffects.ledger,
@@ -866,6 +891,12 @@ async function runTurn(
866
891
  is_error: Boolean(err),
867
892
  error: err,
868
893
  result: event.result,
894
+ ...(event.permission_decision_id
895
+ ? { permission_decision_id: event.permission_decision_id }
896
+ : {}),
897
+ ...(event.permission_decision
898
+ ? { permission_decision: event.permission_decision }
899
+ : {}),
869
900
  });
870
901
  if (settledItem) {
871
902
  emit({ type: "plan_update", ...planSnapshot(pm) });
@@ -1046,6 +1077,7 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
1046
1077
  const input = deps.input || process.stdin;
1047
1078
  const runLoop = deps.agentLoop || coreAgentLoop;
1048
1079
  const doBootstrap = deps.bootstrap || bootstrap;
1080
+ const executeLifecycleHooks = deps.executeHooksV2Event || executeHooksV2Event;
1049
1081
  const doExpand = deps.expandFileRefs || expandFileRefsAsync;
1050
1082
  const runSessionSlashCommand =
1051
1083
  deps.executeSessionSlashCommand || executeSessionSlashCommand;
@@ -1068,7 +1100,12 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
1068
1100
  // client `hello` narrowing the wire features flips these to suppress the
1069
1101
  // additive fields it can't parse. All true by default = current behavior
1070
1102
  // byte-for-byte; the coalescer reads it per line.
1071
- const fieldGate = { seq: true, trace_id: true, tool_use_id: true };
1103
+ const fieldGate = {
1104
+ seq: true,
1105
+ trace_id: true,
1106
+ tool_use_id: true,
1107
+ permission_decision: true,
1108
+ };
1072
1109
  // Batch consecutive partial-message text/thinking deltas into one stream_event
1073
1110
  // line (Claude-Code 2.1.191 streaming-CPU optimization). `emit` flushes any
1074
1111
  // pending deltas before writing a non-delta line, so ordering is preserved;
@@ -1115,6 +1152,33 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
1115
1152
  const sessionId =
1116
1153
  options.sessionId || `headless-stream-${Date.now()}-${process.pid}`;
1117
1154
 
1155
+ const setupHooks = await executeLifecycleHooks(
1156
+ "Setup",
1157
+ {
1158
+ schema_version: 1,
1159
+ session_id: sessionId,
1160
+ cwd,
1161
+ database_available: db != null,
1162
+ enabled_tools: enabledToolNames,
1163
+ settings_files: settingsFiles,
1164
+ },
1165
+ { failClosed: true },
1166
+ );
1167
+ if (setupHooks.blocked || setupHooks.decision === "block") {
1168
+ const reason =
1169
+ setupHooks.blockingResult?.reason ||
1170
+ setupHooks.error ||
1171
+ "blocked by Setup hook";
1172
+ emit({
1173
+ type: "result",
1174
+ subtype: "blocked",
1175
+ is_error: true,
1176
+ result: reason,
1177
+ session_id: sessionId,
1178
+ });
1179
+ return { exitCode: 2, turns: 0 };
1180
+ }
1181
+
1118
1182
  // Session persistence + resume (chat-panel "session resume" / --resume):
1119
1183
  // an EXPLICIT session id (--session / --resume) opts into JSONL persistence —
1120
1184
  // prior history is rebuilt into the conversation and every new turn is
@@ -1434,17 +1498,29 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
1434
1498
  multiSelect,
1435
1499
  timeoutMs,
1436
1500
  metadata,
1501
+ sessionId: requestedSessionId,
1502
+ turnId,
1503
+ toolUseId,
1437
1504
  } = {}) =>
1438
1505
  new Promise((resolve, reject) => {
1439
1506
  const id = `q-${++questionSeq}`;
1507
+ const binding = normalizeInteractionBinding({
1508
+ sessionId: requestedSessionId ?? sessionId,
1509
+ turnId,
1510
+ toolUseId,
1511
+ sequence: questionSeq,
1512
+ });
1440
1513
  const ms = Number(timeoutMs) > 0 ? Number(timeoutMs) : questionTimeoutMs;
1441
1514
  const timer = setTimeout(() => failQuestion(id, "timeout"), ms);
1442
1515
  timer.unref?.();
1443
- pendingQuestions.set(id, { resolve, reject, timer });
1516
+ pendingQuestions.set(id, { resolve, reject, timer, binding });
1444
1517
  emit({
1445
1518
  type: "question_request",
1446
1519
  id,
1447
1520
  session_id: sessionId,
1521
+ binding,
1522
+ ...(binding.turnId ? { turn_id: binding.turnId } : {}),
1523
+ ...(binding.toolUseId ? { tool_use_id: binding.toolUseId } : {}),
1448
1524
  question: typeof question === "string" ? question : "",
1449
1525
  options: Array.isArray(qOptions) ? qOptions : null,
1450
1526
  multiSelect: multiSelect === true,
@@ -1491,7 +1567,10 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
1491
1567
  if (options.jsonSchema) {
1492
1568
  try {
1493
1569
  _jso = await import("../lib/json-schema-output.js");
1494
- _jsonSchema = _jso.loadSchemaFile(_jso._deps.fs, options.jsonSchema);
1570
+ _jsonSchema = await _jso.loadSchemaFileWithRefs(
1571
+ _jso._deps.fs,
1572
+ options.jsonSchema,
1573
+ );
1495
1574
  } catch (err) {
1496
1575
  // Fail-fast, exactly like `cc agent -p --json-schema` on a bad schema.
1497
1576
  writeErr(`Error: ${err.message}\n`);
@@ -1761,32 +1840,91 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
1761
1840
  // handler only after MCP resolution so the client is initialized before use.
1762
1841
  // Reuse the structured Desktop/headless question channel, while preserving
1763
1842
  // the MCP response shape (`action` + object `content`) at this boundary.
1843
+ if (mcp?.mcpClient?.on) {
1844
+ mcp.mcpClient.on("elicitation-deferred", (request) => {
1845
+ emit({
1846
+ type: "elicitation_deferred",
1847
+ session_id: sessionId,
1848
+ server: request.server || null,
1849
+ request_id: request.requestId ?? null,
1850
+ mode: request.mode || "form",
1851
+ message: request.message || "",
1852
+ requested_schema: request.requestedSchema || null,
1853
+ elicitation_id: request.elicitationId || null,
1854
+ url: request.url || null,
1855
+ url_host: request.urlHost || null,
1856
+ reason: request.reason || "no_interactive_host",
1857
+ wire_action: request.wireAction || "decline",
1858
+ });
1859
+ });
1860
+ mcp.mcpClient.on("elicitation-complete", (event) => {
1861
+ emit({
1862
+ type: "elicitation_complete",
1863
+ session_id: sessionId,
1864
+ server: event.server || null,
1865
+ elicitation_id: event.elicitationId || null,
1866
+ });
1867
+ });
1868
+ }
1764
1869
  if (mcp?.mcpClient?.setElicitationHandler && interactiveQuestions) {
1765
1870
  mcp.mcpClient.setElicitationHandler(async (request) => {
1766
- const { emitHooksV2Event } = await import("../lib/hooks-v2-producers.js");
1767
- emitHooksV2Event("MCPElicitation", {
1871
+ const hookContext = {
1872
+ schema_version: 1,
1768
1873
  server: request.server || null,
1769
1874
  request_id: request.requestId ?? null,
1770
1875
  message: request.message || "MCP server requests additional input",
1771
1876
  requested_schema: request.requestedSchema || null,
1877
+ mode: request.mode || "form",
1878
+ elicitation_id: request.elicitationId || null,
1879
+ url: request.url || null,
1880
+ url_host: request.urlHost || null,
1772
1881
  session_id: sessionId,
1773
- });
1774
- const answer = await interactionAskUser({
1775
- question: request.message || "MCP server requests additional input",
1776
- timeoutMs: request.timeoutMs,
1777
- metadata: {
1778
- kind: "mcp_elicitation",
1779
- server: request.server,
1780
- requestId: request.requestId,
1781
- requestedSchema: request.requestedSchema || null,
1782
- },
1783
- });
1784
- if (answer == null) return { action: "cancel" };
1785
- return {
1786
- action: "accept",
1787
- content:
1788
- answer && typeof answer === "object" ? answer : { value: answer },
1789
1882
  };
1883
+ emitHooksV2Event("MCPElicitation", hookContext);
1884
+ emitHooksV2Event("Elicitation", hookContext);
1885
+ try {
1886
+ const answer = await interactionAskUser({
1887
+ question:
1888
+ request.mode === "url"
1889
+ ? `${request.message || "MCP server requests an external interaction"}\nOpen secure URL on ${request.urlHost}?`
1890
+ : request.message || "MCP server requests additional input",
1891
+ timeoutMs: request.timeoutMs,
1892
+ metadata: {
1893
+ kind: "mcp_elicitation",
1894
+ server: request.server,
1895
+ requestId: request.requestId,
1896
+ mode: request.mode || "form",
1897
+ requestedSchema: request.requestedSchema || null,
1898
+ elicitationId: request.elicitationId || null,
1899
+ url: request.url || null,
1900
+ urlHost: request.urlHost || null,
1901
+ },
1902
+ });
1903
+ const response =
1904
+ answer == null
1905
+ ? { action: "cancel" }
1906
+ : request.mode === "url"
1907
+ ? { action: "accept" }
1908
+ : {
1909
+ action: "accept",
1910
+ content:
1911
+ answer && typeof answer === "object"
1912
+ ? answer
1913
+ : { value: answer },
1914
+ };
1915
+ emitHooksV2Event("ElicitationResult", {
1916
+ ...hookContext,
1917
+ action: response.action,
1918
+ });
1919
+ return response;
1920
+ } catch (error) {
1921
+ emitHooksV2Event("ElicitationResult", {
1922
+ ...hookContext,
1923
+ action: "cancel",
1924
+ reason: error?.code || error?.message || "interaction_failed",
1925
+ });
1926
+ throw error;
1927
+ }
1790
1928
  });
1791
1929
  }
1792
1930
 
@@ -2044,6 +2182,19 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
2044
2182
  if (parsed.answer) {
2045
2183
  // Answers settle a BLOCKED ask_user_question — never queued. A null
2046
2184
  // value (user cancelled the QuickPick) → user_timeout (model proceeds).
2185
+ const pending = pendingQuestions.get(parsed.answer.id);
2186
+ if (
2187
+ !pending ||
2188
+ !sameInteractionBinding(pending.binding, parsed.answer.binding)
2189
+ ) {
2190
+ emit({
2191
+ type: "question_response_rejected",
2192
+ id: parsed.answer.id,
2193
+ reason: "binding_mismatch",
2194
+ session_id: sessionId,
2195
+ });
2196
+ continue;
2197
+ }
2047
2198
  if (parsed.answer.value == null)
2048
2199
  failQuestion(parsed.answer.id, "cancelled");
2049
2200
  else
@@ -2196,6 +2347,15 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
2196
2347
  messages_before: before,
2197
2348
  messages_after: messages.length,
2198
2349
  });
2350
+ emitHooksV2Event("PostCompact", {
2351
+ schema_version: 1,
2352
+ trigger: "manual",
2353
+ session_id: sessionId,
2354
+ messages_before: before,
2355
+ messages_after: messages.length,
2356
+ stats,
2357
+ cwd,
2358
+ });
2199
2359
  continue;
2200
2360
  }
2201
2361
 
@@ -2439,6 +2599,32 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
2439
2599
  for (const w of expanded.warnings) writeErr(` @ref: ${w}\n`);
2440
2600
  }
2441
2601
 
2602
+ const expansionHooks = await executeLifecycleHooks(
2603
+ "UserPromptExpansion",
2604
+ {
2605
+ schema_version: 1,
2606
+ session_id: sessionId,
2607
+ turn: turns + 1,
2608
+ cwd,
2609
+ prompt: userContent,
2610
+ original_prompt: parsed.text,
2611
+ },
2612
+ { failClosed: true },
2613
+ );
2614
+ const expansion = resolvePromptExpansion(userContent, expansionHooks);
2615
+ if (expansion.blocked) {
2616
+ emit({
2617
+ type: "result",
2618
+ subtype: "blocked",
2619
+ is_error: true,
2620
+ result: expansion.reason || "blocked by UserPromptExpansion hook",
2621
+ session_id: sessionId,
2622
+ });
2623
+ sawError = true;
2624
+ continue;
2625
+ }
2626
+ userContent = expansion.prompt;
2627
+
2442
2628
  // settings.json UserPromptSubmit hooks. block → skip this turn; context → inject.
2443
2629
  if (settingsHooks) {
2444
2630
  try {
@@ -647,6 +647,12 @@ export async function loadProjectMcp(opts = {}, deps = {}) {
647
647
  const trust =
648
648
  deps.projectMcpTrust ||
649
649
  (await import("../lib/project-mcp-trust.js").catch(() => null));
650
+ if (!trust) {
651
+ writeErr(
652
+ " mcp: SKIPPING project .mcp.json — project trust service is unavailable.\n",
653
+ );
654
+ return deps.into || null;
655
+ }
650
656
 
651
657
  const servers = {};
652
658
  const seenFiles = [];
@@ -661,26 +667,32 @@ export async function loadProjectMcp(opts = {}, deps = {}) {
661
667
  writeErr(` mcp: ignoring malformed ${file} (${err.message})\n`);
662
668
  continue;
663
669
  }
664
- if (trust) {
665
- try {
666
- const check = trust.checkProjectMcpTrust(file, content);
667
- if (check.status === "changed") {
668
- if (trust.projectMcpRetrustRequested(env)) {
669
- trust.recordProjectMcpTrust(file, content);
670
- writeErr(` mcp: ${file} re-trusted (CC_PROJECT_MCP_TRUST).\n`);
671
- } else {
672
- writeErr(
673
- ` mcp: SKIPPING ${file} — its content changed since it was last trusted. ` +
674
- `Review the diff, then re-trust with CC_PROJECT_MCP_TRUST=1 or \`cc mcp trust-project\`.\n`,
675
- );
676
- continue;
670
+ try {
671
+ const check = trust.checkProjectMcpTrust(file, content);
672
+ if (check.status === "changed") {
673
+ if (trust.projectMcpRetrustRequested(env)) {
674
+ if (trust.recordProjectMcpTrust(file, content) !== true) {
675
+ throw new Error("project MCP trust record was not persisted");
677
676
  }
678
- } else if (check.status === "first-use") {
679
- trust.recordProjectMcpTrust(file, content);
677
+ writeErr(` mcp: ${file} re-trusted (CC_PROJECT_MCP_TRUST).\n`);
678
+ } else {
679
+ writeErr(
680
+ ` mcp: SKIPPING ${file} — its content changed since it was last trusted. ` +
681
+ `Review the diff, then re-trust with CC_PROJECT_MCP_TRUST=1 or \`cc mcp trust-project\`.\n`,
682
+ );
683
+ continue;
684
+ }
685
+ } else if (check.status === "first-use") {
686
+ if (trust.recordProjectMcpTrust(file, content) !== true) {
687
+ throw new Error("project MCP trust record was not persisted");
680
688
  }
681
- } catch {
682
- /* trust bookkeeping is best-effort; the opt-in gate above still holds */
683
689
  }
690
+ } catch (err) {
691
+ writeErr(
692
+ ` mcp: SKIPPING ${file} — project trust state is unavailable ` +
693
+ `(${err?.message || "unknown error"}).\n`,
694
+ );
695
+ continue;
684
696
  }
685
697
  const parsed = parseMcpServers(raw);
686
698
  if (Object.keys(parsed).length > 0) {