chainlesschain 0.165.6 → 0.165.8

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 (238) hide show
  1. package/package.json +2 -1
  2. package/src/assets/web-panel/assets/{AIOps-vfoDb6HZ.js → AIOps-B3gWmXjo.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-Cm5f7p93.js → ActionButton-G9pdT-0e.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-yRuvgWxa.js → Analytics-Ca30J7m2.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-BROsC4h1.js → AppLayout-BtVTm8PU.js} +5 -5
  6. package/src/assets/web-panel/assets/{Artifacts-CimHApb1.js → Artifacts-BhViNa6u.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-DI8kr8zI.js → Audit-DhKq-FnY.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-DSLzKy-n.js → BackgroundAgents-BL0SVbnE.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-DkH_n2r1.js → Backup-BWkblnFi.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-CKSrUoRA.js → BaseInput-ClaRNrF8.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-ClwfMXUS.js → Chat-sZE2Z77o.js} +4 -4
  12. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CjMaqfL7.js → ChatBubbleRenderer-BAfKOnRe.js} +1 -1
  13. package/src/assets/web-panel/assets/{Checkbox-BYTehcQG.js → Checkbox-Cvhay5WM.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-B8AMcp6J.js → Codegen-BpejL-4N.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-BNSogPo3.js → Col-g2Ki6g_1.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-JxPvGb8O.js → Community-D2xKbNo9.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-DF7bFAgE.js → Compact-DbL1Pds3.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-Bvhqnwrq.js → Compliance-DGtZCV4c.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-BDS0CJvM.js → Cowork-4kQpoNsI.js} +3 -3
  20. package/src/assets/web-panel/assets/{Cron-DqvRfxoQ.js → Cron-BxTYXXAN.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-CDcIvnqS.js → Crosschain-k0J0LT2N.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-D7jaUxU3.js → DID-BaqhoPgN.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-B5A18wEV.js → Dashboard-T4RVPIM1.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-_6IVkGag.js → Dropdown-DszOToWq.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-C9PeiKCG.js → EmailListRenderer-C9KJU7HF.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DXjuEHrX.js → FamilyGuardDashboard-Cmr0JnsA.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-B4IAR9zv.js → Federation-BI-_2xZX.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-CxQeSNx1.js → FormItemContext-DsnDEPsl.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-B8GS-Y3N.js → GenericCardRenderer-BLncAKKK.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-BS8SouUX.js → Git-BPQhGXDn.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-Dq9aYb5Q.js → Governance-CyElbUQW.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-BrCEe9AJ.js → Inference-CcSntBQD.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-DybOpiY2.js → KnowledgeGraph-p6e7HZ2r.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-DBpzbRfx.js → Logs-CNEtr-wz.js} +2 -2
  35. package/src/assets/web-panel/assets/MarkdownRenderer-Bj9xI0YH.js +1 -0
  36. package/src/assets/web-panel/assets/{Marketplace-Cc7CCSCu.js → Marketplace-Dd2notAJ.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-DFaIhOfu.js → McpTools-BBsN2CSW.js} +4 -4
  38. package/src/assets/web-panel/assets/{Memory-KCqlp9ol.js → Memory-Dg2uTvwx.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-Bys84ySN.js → MobileBridge-r1YMRiJV.js} +1 -1
  40. package/src/assets/web-panel/assets/{MobileProjects-B-6qU-je.js → MobileProjects-C-89kSm4.js} +1 -1
  41. package/src/assets/web-panel/assets/{Mtc-BgY-fvCq.js → Mtc-CrPZcVgf.js} +5 -5
  42. package/src/assets/web-panel/assets/{MtcAudit-B8pCmqQJ.js → MtcAudit-sxi7hqJb.js} +4 -4
  43. package/src/assets/web-panel/assets/{Multisig-BbOmYutA.js → Multisig-CAgOMfF1.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-BocLQz_M.js → NLProgramming-DafaPts3.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-CSwbxEop.js → Notes-CJM-xUW_.js} +3 -3
  46. package/src/assets/web-panel/assets/{NotificationSettings-CqFNSYG3.js → NotificationSettings-L0ZjfAh_.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-C6gMfAk7.js → OrderTableRenderer-BB1CvCK0.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-QrDXVdMJ.js → Organization-DeLtgAD8.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-Cxntotjt.js → Overflow-CKC2b10z.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-CIdBOwNq.js → P2P-eyf2rzY1.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-CT5aP8rD.js → PdhVaultBrowser-5upNIOW8.js} +3 -3
  52. package/src/assets/web-panel/assets/{Permissions-DH7OM8XU.js → Permissions-B8p3W6JK.js} +4 -4
  53. package/src/assets/web-panel/assets/{PersonalDataHub-CnJqbWce.js → PersonalDataHub-BnRMxTq3.js} +5 -5
  54. package/src/assets/web-panel/assets/{Pipeline-5C3HG1kH.js → Pipeline-DjCNI1li.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-B4yIp7xK.js → Privacy-u6gXLbWT.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-BMvt-2M0.js → ProjectInit-BZAw4tkM.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-CvSTEMRG.js → ProjectSettings-B1Tr72q7.js} +2 -2
  58. package/src/assets/web-panel/assets/{Projects-BKBJxEek.js → Projects-DO7HFuBQ.js} +1 -1
  59. package/src/assets/web-panel/assets/{Providers-BdwUqFWN.js → Providers-BjCztyhj.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-DtnCKlTm.js → QrScannerModal-ZWyCUbR1.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-sTbgwyNr.js → QuickAsk-DhDjeW4G.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-Bzr14gSb.js → Recommend-R_CN2MuU.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-C_TF5IaJ.js → RemoteSession-uxFcujeu.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-GCAM4H2K.js → Reputation-DX8D7rks.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-Dir0r6OQ.js → Row-BYahQILD.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-CpGnlecX.js → RssFeed-CUSQ2tm-.js} +3 -3
  67. package/src/assets/web-panel/assets/{Search-DMMamC6u.js → Search-CnN_S8Cs.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-yqay5yG-.js → Security-DcZlh-O4.js} +4 -4
  69. package/src/assets/web-panel/assets/{Services-C5i2wh9G.js → Services-ZhBOjzIX.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-vUqk35yj.js → Skeleton-D5Qnq_lI.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-DzcSkhot.js → Skills-BC9cZ3Be.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-CB6qbYNr.js → Sla-DauJ3E8_.js} +1 -1
  73. package/src/assets/web-panel/assets/SpeechSettings-DbNeZ_fh.js +1 -0
  74. package/src/assets/web-panel/assets/{SyncSettings-D-RrsxTJ.js → SyncSettings-DUvJbSct.js} +2 -2
  75. package/src/assets/web-panel/assets/{Tasks-DFxdOJiq.js → Tasks-BXa-5noQ.js} +1 -1
  76. package/src/assets/web-panel/assets/{Templates-SKAob_Aq.js → Templates-JxaiUt_3.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-BPfsfHQ-.js → Tenant-BW4ERQN8.js} +1 -1
  78. package/src/assets/web-panel/assets/{Terminal-8iw7FpUf.js → Terminal-DltUbdtv.js} +2 -2
  79. package/src/assets/web-panel/assets/{TimelineRenderer-C4Gjj5Su.js → TimelineRenderer-CMoZz0Tc.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-COYhN18e.js → Tokens-D_VEV60K.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-B-JzXcf6.js → Trigger-CCXTCs0R.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-BJ5bg0nI.js → Trust-lkGRIPcG.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-BG_ByRMf.js → UkeySign-BfGeQ9HX.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-B3kOnSiU.js → VideoEditing-BEC7pYvc.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-CcoGFnK7.js → Wallet-BZdG24o0.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-DdT8vRC_.js → WebAuthn-yoEddedp.js} +4 -4
  87. package/src/assets/web-panel/assets/{WorkflowEditor-CZu3M9N8.js → WorkflowEditor-BXZEprOW.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-DxJt3Qba.js → chat-gg0bzZal.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-DdYfwJaB.js → colors-DjRVRuin.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-BG3SUzwj.js → compact-item-su-dieAc.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-By51z2-1.js → createContext-Ci3S8oKF.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-CxbFX9uH.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-B0apZ3KJ.js → hasIn-D8F10heH.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-DE76D-kA.js → index-11wtYQiF.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-BkvcEo4p.js → index-1IgxgALJ.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-Bos5_aMV.js → index-1agckWSq.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BfWYsB9t.js → index-5JqhujnR.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CAhHirVH.js → index-6Tniqk1s.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BYINoRLK.js → index-8Z-8BIlN.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-B5rLiEo0.js → index-BCI5v0yB.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BZ_0qm4g.js → index-BDJntYmJ.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CWEuZWCK.js → index-BGzixOGZ.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BLIbGOLX.js → index-BMMOVoLD.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-bP_VlDb4.js → index-BTFpdBtt.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-B3rWuPMW.js → index-Ba_HyPnE.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-Da_WBdLX.js → index-BbF1IHof.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-RD6O-0C6.js → index-BgT9su_e.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-CpjZhgNd.js → index-BzPB6kGZ.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Q2SCX-MI.js → index-C6ygzplr.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-BIrJfqO4.js → index-CC3ZDjzY.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BBPf3TpM.js → index-CEmXRhAE.js} +1 -1
  112. package/src/assets/web-panel/assets/index-CJGOlduY.js +1 -0
  113. package/src/assets/web-panel/assets/{index-Cp6e-hGw.js → index-CMPqd5Cv.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-kf57LJ93.js → index-COWd8uGx.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CW93tZDv.js → index-CPIYSp4H.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-BewKYrX9.js → index-CR0h6seT.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-p1_8SbI1.js → index-CUmDhC4j.js} +1 -1
  118. package/src/assets/web-panel/assets/index-CkBCN5yH.js +1 -0
  119. package/src/assets/web-panel/assets/{index-ZxtP8jG7.js → index-CusgZPtc.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BWF8_mkx.js → index-DBAETXft.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-BP94CrBV.js → index-DIJ2qFOC.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-CNIxXMmN.js → index-Dbq4NMET.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CzmQElZy.js → index-DkMEF5VT.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-ZFbps9po.js → index-DkfQR3hM.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-Dz49VOyQ.js → index-DnLucOn9.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-oxRrmFO9.js → index-DugB_aKa.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-Bissefox.js → index-DyLUarhZ.js} +3 -3
  128. package/src/assets/web-panel/assets/{index-DaIz0NAW.js → index-T6_6ygJZ.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-SQqOlR3d.js → index-Tu8eWqh-.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-DCn8IcxV.js → index-W7XUgdVL.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-3jWkIu5j.js → index-dHZinfko.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-C1C9i79A.js → index-jyNgp5FI.js} +1 -1
  133. package/src/assets/web-panel/assets/{initDefaultProps-BWJktcg8.js → initDefaultProps-Cv4p8e4w.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-BEXBzUFV.js → motion-B8EwmMOw.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-BUKwn2sx.js → move-B8R9F8TK.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-FTI7btqQ.js → mtc-parser-DoFYz5Bp.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-CsLtSPH3.js → omit-CHWYLBjI.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-DWZxsT_S.js → pickAttrs-CXuPDO77.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-Bcfs43CX.js → placementArrow-BaAtUUon.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-a9bcC1p-.js → responsiveObserve-DCc4zcDD.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-BDTzgOXN.js → slide-B_lx89oZ.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-Iq1j_HUg.js → statusUtils-DE8DPmR0.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-DAZEYxeh.js → styleChecker-1ktXOsL_.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-DVkjyDrh.js → useFlexGapSupport-xH89-wjh.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-wXTpNTHt.js → useFs-DscvfW5p.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-CtQM_aZr.js → usePersonalDataHub-RdMKQta7.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-hjEoG85v.js → vnode-Z3wTni2T.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-BHVpyKg_.js → zoom-B0iChCsm.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/command-help-index.json +3 -3
  151. package/src/commands/agent.js +91 -60
  152. package/src/commands/git.js +39 -0
  153. package/src/commands/plugin.js +17 -2
  154. package/src/commands/session-group.js +131 -0
  155. package/src/commands/session-location.js +48 -0
  156. package/src/commands/session.js +11 -0
  157. package/src/commands/sync-providers.js +4 -1
  158. package/src/commands/update.js +1 -0
  159. package/src/data/changelog.json +27 -1
  160. package/src/gateways/ws/ws-agent-handler.js +20 -12
  161. package/src/harness/jsonl-session-store.js +279 -37
  162. package/src/harness/mcp-client.js +701 -91
  163. package/src/harness/session-index.js +15 -4
  164. package/src/lib/agent-worktree.js +8 -1
  165. package/src/lib/auto-mode-safety-classifier.js +3 -17
  166. package/src/lib/background-agent-keeper-protocol.js +26 -6
  167. package/src/lib/background-agent-supervisor.js +17 -1
  168. package/src/lib/browser-evidence.js +1405 -0
  169. package/src/lib/chrome-connector.js +465 -79
  170. package/src/lib/claude-project-auto-memory.js +481 -0
  171. package/src/lib/claude-project-storage-layout.js +104 -0
  172. package/src/lib/cloud/cloud-client.js +40 -0
  173. package/src/lib/execution-location-local-supervisor.mjs +226 -0
  174. package/src/lib/execution-location-runner-lifecycle.js +991 -0
  175. package/src/lib/execution-location-target-preflight.js +333 -0
  176. package/src/lib/execution-location-target.js +783 -13
  177. package/src/lib/file-lines.js +6 -1
  178. package/src/lib/gateway-client-resilience.js +571 -0
  179. package/src/lib/gitlab-mr-worktree.js +176 -0
  180. package/src/lib/hooks-v2-producers.js +119 -15
  181. package/src/lib/hooks-v2-workspace-context.js +44 -1
  182. package/src/lib/host-resource-budget.js +295 -0
  183. package/src/lib/ide-context.js +15 -2
  184. package/src/lib/llm-config-defaults.js +43 -0
  185. package/src/lib/mcp-lifecycle-authority.js +887 -0
  186. package/src/lib/mcp-oauth.js +101 -20
  187. package/src/lib/mcp-tls.js +103 -3
  188. package/src/lib/paths.js +260 -32
  189. package/src/lib/permission-request.js +48 -0
  190. package/src/lib/plugin-runtime/bin.js +3 -1
  191. package/src/lib/plugin-runtime/hooks.js +3 -1
  192. package/src/lib/plugin-runtime/install.js +117 -1
  193. package/src/lib/plugin-runtime/lsp.js +4 -4
  194. package/src/lib/plugin-runtime/marketplace-archive-source.js +40 -5
  195. package/src/lib/plugin-runtime/marketplace-catalog.js +13 -2
  196. package/src/lib/plugin-runtime/marketplace-command-descriptor.js +343 -0
  197. package/src/lib/plugin-runtime/marketplace-command-source.js +580 -0
  198. package/src/lib/plugin-runtime/marketplace-source-adapter.js +33 -8
  199. package/src/lib/plugin-runtime/mcp.js +3 -1
  200. package/src/lib/plugin-runtime/monitors.js +3 -1
  201. package/src/lib/plugin-runtime/remote-source.js +151 -6
  202. package/src/lib/plugin-runtime/settings.js +3 -1
  203. package/src/lib/plugin-runtime/trust.js +274 -13
  204. package/src/lib/process-execution-broker/credential-agent.js +210 -41
  205. package/src/lib/process-execution-broker/index.js +15 -1
  206. package/src/lib/process-execution-broker/linux-cgroup-v2.js +391 -0
  207. package/src/lib/process-execution-broker/platform-sandbox.js +50 -28
  208. package/src/lib/project-mcp-trust.js +165 -10
  209. package/src/lib/resume-session.js +9 -6
  210. package/src/lib/session-core-singletons.js +26 -11
  211. package/src/lib/session-host-lease.js +52 -16
  212. package/src/lib/session-lifecycle-scope.js +153 -0
  213. package/src/lib/session-message-fabric.js +168 -21
  214. package/src/lib/session-projection.js +244 -4
  215. package/src/lib/session-store-guard.js +3 -1
  216. package/src/lib/session-workbench-store.js +466 -0
  217. package/src/lib/spellcheck.js +211 -0
  218. package/src/lib/sub-agent-context.js +9 -9
  219. package/src/lib/sync-cli-db.js +485 -129
  220. package/src/lib/sync-credentials.js +31 -20
  221. package/src/lib/web-fetch.js +112 -40
  222. package/src/lib/web-search.js +127 -61
  223. package/src/lib/workspace-trust.js +793 -0
  224. package/src/repl/agent-repl.js +124 -5
  225. package/src/repl/permission-prompt.js +10 -12
  226. package/src/runtime/agent-core.js +311 -18
  227. package/src/runtime/bootstrap.js +37 -13
  228. package/src/runtime/coding-agent-contract-shared.cjs +11 -4
  229. package/src/runtime/headless-runner.js +234 -36
  230. package/src/runtime/headless-stream.js +181 -6
  231. package/src/runtime/mcp-config.js +298 -8
  232. package/src/runtime/policies/agent-policy.js +8 -0
  233. package/src/runtime/status-diagnostics-lite.js +9 -1
  234. package/src/assets/web-panel/assets/MarkdownRenderer-CFyt8iUd.js +0 -1
  235. package/src/assets/web-panel/assets/SpeechSettings-BHUI7cox.js +0 -1
  236. package/src/assets/web-panel/assets/devWarning-DorRZcI9.js +0 -1
  237. package/src/assets/web-panel/assets/index-BETiL0a3.js +0 -1
  238. package/src/assets/web-panel/assets/index-BhAVHuW8.js +0 -1
@@ -119,6 +119,7 @@ import {
119
119
  } from "../lib/task-model-selector.js";
120
120
  import { runnableTaskModel, hasUsableKey } from "../lib/runnable-provider.js";
121
121
  import { CLIPermanentMemory } from "../lib/permanent-memory.js";
122
+ import { resolveClaudeProjectAutoMemory } from "../lib/claude-project-auto-memory.js";
122
123
  import { CLIAutonomousAgent, GoalStatus } from "../lib/autonomous-agent.js";
123
124
  import {
124
125
  estimateMessagesTokens,
@@ -2845,6 +2846,46 @@ export function startReplJsonlSession(
2845
2846
  }
2846
2847
  }
2847
2848
 
2849
+ /**
2850
+ * Resolve the automatic-memory location at the same lifecycle boundary that
2851
+ * opens the durable REPL session. This is intentionally exported as a narrow
2852
+ * test seam; startAgentReplInWorkspaceOwned consumes it below rather than
2853
+ * letting a standalone helper drift away from real session behavior.
2854
+ */
2855
+ export function resolveReplAutomaticMemoryPlan(
2856
+ options = {},
2857
+ cwd = process.cwd(),
2858
+ ) {
2859
+ return resolveClaudeProjectAutoMemory({
2860
+ cwd,
2861
+ launchEnv: options.claudeStorageLaunchEnv || undefined,
2862
+ });
2863
+ }
2864
+
2865
+ /**
2866
+ * Resolve the concrete permanent-memory backend used by the live REPL. Claude
2867
+ * project mode is deliberately file-only: the legacy bootstrap SQLite DB is
2868
+ * process/global state and would otherwise let project A retrieve facts that
2869
+ * project B summarized. Legacy mode retains its historical DB behavior.
2870
+ */
2871
+ export function resolveReplPermanentMemoryStorage(
2872
+ options = {},
2873
+ db = null,
2874
+ cwd = process.cwd(),
2875
+ ) {
2876
+ const automaticMemory = resolveReplAutomaticMemoryPlan(options, cwd);
2877
+ if (!automaticMemory.enabled) return null;
2878
+ const dataDir = process.env.CHAINLESSCHAIN_DATA_DIR || cwd;
2879
+ return Object.freeze({
2880
+ db: automaticMemory.mode === "project" ? null : db,
2881
+ memoryDir:
2882
+ automaticMemory.mode === "project"
2883
+ ? automaticMemory.memoryDir
2884
+ : path.join(dataDir, "memory"),
2885
+ automaticMemory,
2886
+ });
2887
+ }
2888
+
2848
2889
  /** Start the agentic REPL with non-overridable production bindings. */
2849
2890
  export async function startAgentRepl(options = {}) {
2850
2891
  const sessionHostLeaseScope = { lease: null };
@@ -3344,10 +3385,15 @@ async function startAgentReplInWorkspaceOwned(
3344
3385
  // Initialize permanent memory
3345
3386
  let permanentMemory = null;
3346
3387
  try {
3347
- const dataDir = process.env.CHAINLESSCHAIN_DATA_DIR || process.cwd();
3348
- const memoryDir = path.join(dataDir, "memory");
3349
- permanentMemory = new CLIPermanentMemory({ db, memoryDir });
3350
- permanentMemory.initialize();
3388
+ const permanentMemoryStorage = resolveReplPermanentMemoryStorage(
3389
+ options,
3390
+ db,
3391
+ process.cwd(),
3392
+ );
3393
+ if (permanentMemoryStorage) {
3394
+ permanentMemory = new CLIPermanentMemory(permanentMemoryStorage);
3395
+ permanentMemory.initialize();
3396
+ }
3351
3397
  } catch (_err) {
3352
3398
  // Non-critical
3353
3399
  }
@@ -3783,7 +3829,13 @@ async function startAgentReplInWorkspaceOwned(
3783
3829
  try {
3784
3830
  const { getSessionManager } =
3785
3831
  await import("../lib/session-core-singletons.js");
3786
- _sessionMgr = getSessionManager();
3832
+ // Keep durable lifecycle sidecars on the same launch-authoritative Claude
3833
+ // project bucket as the JSONL transcript. Project settings may not switch
3834
+ // this map/path after the REPL has admitted its launch environment.
3835
+ _sessionMgr = getSessionManager({
3836
+ launchEnv: options.claudeStorageLaunchEnv || undefined,
3837
+ cwd: process.cwd(),
3838
+ });
3787
3839
  if (sessionId) {
3788
3840
  if (options.sessionId && !_sessionMgr.has(sessionId)) {
3789
3841
  // Try unparking; no-op if nothing parked with that id
@@ -6312,6 +6364,73 @@ async function startAgentReplInWorkspaceOwned(
6312
6364
  return;
6313
6365
  }
6314
6366
 
6367
+ // `/spellcheck` uses an installed local dictionary only. It never sends
6368
+ // prompt text to a provider, and fenced code is suppressed by the adapter
6369
+ // before the executable receives it.
6370
+ {
6371
+ const {
6372
+ parseSpellcheckCommand,
6373
+ resolveSpellcheckEnabled,
6374
+ spellcheckText,
6375
+ } = await import("../lib/spellcheck.js");
6376
+ const spellcheck = parseSpellcheckCommand(trimmed);
6377
+ if (spellcheck) {
6378
+ let configured;
6379
+ try {
6380
+ const { getConfigValue } = await import("../lib/config-manager.js");
6381
+ configured = getConfigValue("cli.spellcheck");
6382
+ } catch {
6383
+ configured = undefined;
6384
+ }
6385
+ if (spellcheck.action === "on" || spellcheck.action === "off") {
6386
+ try {
6387
+ const { setConfigValue } = await import("../lib/config-manager.js");
6388
+ setConfigValue("cli.spellcheck", spellcheck.action === "on");
6389
+ } catch {
6390
+ // The current-session diagnostic remains useful if config storage
6391
+ // is unavailable; don't turn a local optional feature into a
6392
+ // REPL failure.
6393
+ }
6394
+ logger.info(
6395
+ `Spellcheck: ${spellcheck.action === "on" ? "enabled" : "disabled"}.`,
6396
+ );
6397
+ } else if (spellcheck.action === "status") {
6398
+ logger.info(
6399
+ `Spellcheck: ${
6400
+ resolveSpellcheckEnabled({
6401
+ config: { cli: { spellcheck: configured } },
6402
+ })
6403
+ ? "enabled"
6404
+ : "disabled"
6405
+ }. ` + "Use /spellcheck <text> to check local prose.",
6406
+ );
6407
+ } else {
6408
+ try {
6409
+ const result = spellcheckText(spellcheck.text, {
6410
+ config: { cli: { spellcheck: configured } },
6411
+ });
6412
+ if (!result.enabled) {
6413
+ logger.info("Spellcheck is disabled.");
6414
+ } else if (!result.available) {
6415
+ logger.info(
6416
+ "No local spellchecker found (aspell, hunspell, or ispell).",
6417
+ );
6418
+ } else if (result.words.length === 0) {
6419
+ logger.info("Spellcheck: no unknown prose words.");
6420
+ } else {
6421
+ logger.info(
6422
+ `Spellcheck (${result.adapter}): ${result.words.join(", ")}`,
6423
+ );
6424
+ }
6425
+ } catch (error) {
6426
+ logger.error(`/spellcheck failed: ${error.message}`);
6427
+ }
6428
+ }
6429
+ prompt();
6430
+ return;
6431
+ }
6432
+ }
6433
+
6315
6434
  // `/tui` — fullscreen no-flicker view (Claude-Code parity). `fullscreen`
6316
6435
  // enters the alternate screen buffer; `default` returns to streaming
6317
6436
  // scrollback. No arg prints the current mode. Persisted to `cli.tuiMode`.
@@ -14,6 +14,9 @@
14
14
  *
15
15
  * @returns {string} the prompt header (no styling, no trailing "Proceed?")
16
16
  */
17
+ import { normalizePermissionRequest } from "../lib/permission-request.js";
18
+ import { redactSecrets } from "../lib/secret-scan.js";
19
+
17
20
  export function visualizePermissionText(value) {
18
21
  return String(value ?? "").replace(
19
22
  /[\u0000-\u001f\u007f-\u009f\u00ad\u034f\u061c\u115f\u1160\u17b4\u17b5\u180b-\u180f\u200b-\u200f\u202a-\u202e\u2060-\u206f\u3164\ufeff\uffa0]/gu,
@@ -27,23 +30,18 @@ export function visualizePermissionText(value) {
27
30
  }
28
31
 
29
32
  export function buildPermissionPrompt({ tool, args, rule, reason } = {}) {
30
- const visibleTool = visualizePermissionText(tool);
31
- const command = typeof args?.command === "string" ? args.command : "";
32
- const source = args?.path ?? args?.file_path ?? args?.source ?? "";
33
- const destination = args?.destination ?? args?.new_path ?? args?.to ?? "";
34
- const rawDetail = command
35
- ? command
36
- : source && destination
37
- ? `${source} -> ${destination}`
38
- : source || destination;
39
- const detail = rawDetail ? ` ${visualizePermissionText(rawDetail)}` : "";
33
+ const request = normalizePermissionRequest({ tool, args });
34
+ const visibleTool = visualizePermissionText(request.tool);
35
+ const rawDetail = request.detail;
36
+ const visibleDetail = visualizePermissionText(redactSecrets(rawDetail));
37
+ const detail = rawDetail ? ` ${visibleDetail}` : "";
40
38
  if (rule) {
41
- return `[Permission] rule "${visualizePermissionText(rule)}" asks before ${visibleTool}:${detail}`;
39
+ return `[Permission] rule "${visualizePermissionText(redactSecrets(String(rule)))}" asks before ${visibleTool}:${detail}`;
42
40
  }
43
41
  if (reason) {
44
42
  const reasonText = String(reason);
45
43
  const missingTarget = rawDetail && !reasonText.includes(String(rawDetail));
46
- return `[Permission] ${visualizePermissionText(reasonText)}${missingTarget ? `:${detail}` : ""}`;
44
+ return `[Permission] ${visualizePermissionText(redactSecrets(reasonText))}${missingTarget ? `:${detail}` : ""}`;
47
45
  }
48
46
  return `[Permission] confirm ${visibleTool}:${detail}`;
49
47
  }
@@ -516,6 +516,45 @@ export const _gitProcessDeps = {
516
516
  run: gitProcessRunner,
517
517
  };
518
518
 
519
+ function canonicalGitMetadataPath(value) {
520
+ const resolved = path.resolve(String(value || "").trim());
521
+ try {
522
+ const real = fs.realpathSync.native(resolved);
523
+ return process.platform === "win32" ? real.toLowerCase() : real;
524
+ } catch {
525
+ return null;
526
+ }
527
+ }
528
+
529
+ /**
530
+ * Distinguish the primary checkout from a linked worktree using Git's own
531
+ * metadata paths. Unknown/non-repository locations are deliberately not
532
+ * treated as linked worktrees.
533
+ */
534
+ export function classifyGitCheckout(cwd) {
535
+ const query = (argument) => {
536
+ const result = _gitProcessDeps.run(
537
+ "git",
538
+ ["rev-parse", "--path-format=absolute", argument],
539
+ {
540
+ cwd,
541
+ encoding: "utf8",
542
+ timeout: 10000,
543
+ windowsHide: true,
544
+ origin: "agent-core:git-checkout-authority",
545
+ policy: "allow",
546
+ scope: "agent-core",
547
+ },
548
+ );
549
+ if (result?.error || result?.status !== 0) return null;
550
+ return canonicalGitMetadataPath(result.stdout);
551
+ };
552
+ const gitDirectory = query("--git-dir");
553
+ const commonDirectory = query("--git-common-dir");
554
+ if (!gitDirectory || !commonDirectory) return "unknown";
555
+ return gitDirectory === commonDirectory ? "primary" : "linked";
556
+ }
557
+
519
558
  function _killTask(task) {
520
559
  const child = task?.child;
521
560
  if (!child || child.killed || task?.status !== "running") return false;
@@ -919,6 +958,8 @@ async function requestInteractivePermission(
919
958
  args && typeof args === "object" ? Object.keys(args).sort() : [],
920
959
  reason: confirmArgs?.reason || null,
921
960
  cwd,
961
+ trace_id: context.hookTraceId || null,
962
+ parent_id: context.hookParentId || null,
922
963
  },
923
964
  { failClosed: true },
924
965
  );
@@ -3253,25 +3294,35 @@ export async function executeTool(name, args, context = {}) {
3253
3294
  // command unguarded in auto mode — including `reset --hard`, `clean -fd`,
3254
3295
  // `restore .`, `push --force`, `branch -D`, `rebase`, `reflog expire` —
3255
3296
  // which irrecoverably discard work. An explicit settings `allow`/confirmed
3256
- // `ask` (ruleAllowed) pre-authorizes; headless without a confirmer fails
3257
- // closed. Plan mode already blocks non-read-only git below.
3297
+ // A confirmed `ask` pre-authorizes. A static `allow` only pre-authorizes a
3298
+ // linked worktree; primary/unknown checkout identity still needs a live
3299
+ // confirmation. Plan mode already blocks non-read-only git below.
3258
3300
  if (
3259
3301
  name === "git" &&
3260
- !ruleAllowed &&
3261
3302
  !planManager.isActive() &&
3262
3303
  isDangerousGitCommand(args?.command)
3263
3304
  ) {
3264
- const ok = await requestInteractivePermission(name, args, context, cwd, {
3265
- tool: name,
3266
- args,
3267
- rule: null,
3268
- reason: `destructive git command: git ${normalizeGitCommand(args.command)}`,
3269
- });
3270
- if (!ok) {
3271
- return {
3272
- error: `[Destructive Git] "git ${normalizeGitCommand(args.command)}" discards work irrecoverably and requires confirmation — denied. Add a settings allow rule to pre-authorize.`,
3273
- policy: { decision: "ask", via: "destructive-git" },
3274
- };
3305
+ const checkout = classifyGitCheckout(args?.cwd || cwd);
3306
+ const settingsAskWasConfirmed =
3307
+ settingsVerdict.decision === "ask" && ruleAllowed;
3308
+ const linkedWorktreeWasAllowed = checkout === "linked" && ruleAllowed;
3309
+ if (!settingsAskWasConfirmed && !linkedWorktreeWasAllowed) {
3310
+ const ok = await requestInteractivePermission(name, args, context, cwd, {
3311
+ tool: name,
3312
+ args,
3313
+ rule: null,
3314
+ reason: `destructive git command in ${checkout} checkout: git ${normalizeGitCommand(args.command)}`,
3315
+ });
3316
+ if (!ok) {
3317
+ return {
3318
+ error: `[Destructive Git] "git ${normalizeGitCommand(args.command)}" targets the ${checkout} checkout, discards work irrecoverably, and requires live confirmation — denied.`,
3319
+ policy: {
3320
+ decision: "ask",
3321
+ via: "destructive-git",
3322
+ checkout,
3323
+ },
3324
+ };
3325
+ }
3275
3326
  }
3276
3327
  }
3277
3328
 
@@ -3509,6 +3560,8 @@ export async function executeTool(name, args, context = {}) {
3509
3560
  input_keys:
3510
3561
  args && typeof args === "object" ? Object.keys(args).sort() : [],
3511
3562
  cwd,
3563
+ trace_id: context.hookTraceId || null,
3564
+ parent_id: context.hookParentId || null,
3512
3565
  },
3513
3566
  { failClosed: true },
3514
3567
  );
@@ -3660,6 +3713,7 @@ export async function executeTool(name, args, context = {}) {
3660
3713
  subAgentDepth: context.subAgentDepth || 0,
3661
3714
  subAgentBudget: context.subAgentBudget || null,
3662
3715
  sessionBudget: context.sessionBudget || null,
3716
+ hostResourceBudget: context.hostResourceBudget || null,
3663
3717
  // Effective contract of THIS loop (parent ceiling for a nested spawn) +
3664
3718
  // the MCP tool definitions this loop exposes (inheritable by a spawn).
3665
3719
  subAgentContract: context.subAgentContract || null,
@@ -3676,6 +3730,15 @@ export async function executeTool(name, args, context = {}) {
3676
3730
  managedCheckpoint: context.managedCheckpoint === true,
3677
3731
  fileMutationScope: context.fileMutationScope || null,
3678
3732
  hermeticExecution: context.hermeticExecution === true,
3733
+ browserEvidenceBinding: context.browserEvidenceBinding || null,
3734
+ browserOriginGrants: context.browserOriginGrants || null,
3735
+ browserExpectedGrantRevisions:
3736
+ context.browserExpectedGrantRevisions || null,
3737
+ browserReplaySourceEnvelope: context.browserReplaySourceEnvelope || null,
3738
+ browserReplayAllowSideEffects:
3739
+ context.browserReplayAllowSideEffects === true,
3740
+ browserReplayAllowCredentials:
3741
+ context.browserReplayAllowCredentials === true,
3679
3742
  });
3680
3743
  } catch (err) {
3681
3744
  if (
@@ -4757,9 +4820,9 @@ async function filterSkillsByCwd(skills, cwd) {
4757
4820
  }
4758
4821
  }
4759
4822
 
4760
- async function promoteBrowserScreenshot(
4823
+ async function promoteBrowserGeneratedArtifact(
4761
4824
  filePath,
4762
- { sessionId = null, title = "Browser screenshot" } = {},
4825
+ { sessionId = null, title, kind, failureLabel } = {},
4763
4826
  ) {
4764
4827
  if (!filePath) return { artifact: null, error: null };
4765
4828
  try {
@@ -4768,7 +4831,7 @@ async function promoteBrowserScreenshot(
4768
4831
  const entry = new ArtifactStore().publish({
4769
4832
  filePath,
4770
4833
  title,
4771
- kind: "screenshot",
4834
+ kind,
4772
4835
  sessionId: sessionId ? String(sessionId) : null,
4773
4836
  });
4774
4837
  return { artifact: publicArtifactMetadata(entry), error: null };
@@ -4779,7 +4842,7 @@ async function promoteBrowserScreenshot(
4779
4842
  : "";
4780
4843
  return {
4781
4844
  artifact: null,
4782
- error: `browser screenshot artifact publication failed${code ? ` (${code})` : ""}`,
4845
+ error: `${failureLabel} artifact publication failed${code ? ` (${code})` : ""}`,
4783
4846
  };
4784
4847
  } finally {
4785
4848
  try {
@@ -4790,6 +4853,155 @@ async function promoteBrowserScreenshot(
4790
4853
  }
4791
4854
  }
4792
4855
 
4856
+ async function promoteBrowserScreenshot(
4857
+ filePath,
4858
+ { sessionId = null, title = "Browser screenshot" } = {},
4859
+ ) {
4860
+ return promoteBrowserGeneratedArtifact(filePath, {
4861
+ sessionId,
4862
+ title,
4863
+ kind: "screenshot",
4864
+ failureLabel: "browser screenshot",
4865
+ });
4866
+ }
4867
+
4868
+ async function promoteBrowserDownload(
4869
+ filePath,
4870
+ { sessionId = null, title = "Browser download" } = {},
4871
+ ) {
4872
+ return promoteBrowserGeneratedArtifact(filePath, {
4873
+ sessionId,
4874
+ title,
4875
+ kind: "data",
4876
+ failureLabel: "browser download",
4877
+ });
4878
+ }
4879
+
4880
+ async function publishBrowserEvidence(envelope, sessionId) {
4881
+ if (!envelope?.envelopeDigest) return { artifact: null, error: null };
4882
+ try {
4883
+ const { ArtifactStore, publicArtifactMetadata } =
4884
+ await import("../lib/artifact-store.js");
4885
+ const {
4886
+ browserEvidenceDigest,
4887
+ canonicalBrowserEvidenceJson,
4888
+ verifyBrowserEvidenceEnvelope,
4889
+ } = await import("../lib/browser-evidence.js");
4890
+ verifyBrowserEvidenceEnvelope(envelope);
4891
+ if (!sessionId || String(sessionId) !== envelope.binding.session.id) {
4892
+ throw new Error("browser evidence is not bound to the active session");
4893
+ }
4894
+ const data = `${canonicalBrowserEvidenceJson(envelope)}\n`;
4895
+ const expectedFileDigest = browserEvidenceDigest(data).slice(
4896
+ "sha256:".length,
4897
+ );
4898
+ const expectedLineage = {
4899
+ schema: envelope.schema,
4900
+ sessionId: envelope.binding.session.id,
4901
+ sessionRevision: envelope.binding.session.revision,
4902
+ diffDigest: envelope.binding.diff.digest,
4903
+ testRunId: envelope.binding.testRun.id,
4904
+ };
4905
+ const store = new ArtifactStore();
4906
+ const published = store.publishDataOnce({
4907
+ data,
4908
+ fileName: "browser-evidence-envelope.json",
4909
+ title: `Browser evidence ${envelope.binding.session.id}@${envelope.binding.session.revision}`,
4910
+ kind: "data",
4911
+ mime: "application/json",
4912
+ sessionId: String(sessionId),
4913
+ immutable: true,
4914
+ recordDigest: envelope.envelopeDigest,
4915
+ lineage: expectedLineage,
4916
+ });
4917
+ const entry = published.entry;
4918
+ const integrity = store.verifyIntegrity(entry);
4919
+ if (
4920
+ !integrity.ok ||
4921
+ entry.sessionId !== String(sessionId) ||
4922
+ entry.immutable !== true ||
4923
+ entry.recordDigest !== envelope.envelopeDigest ||
4924
+ entry.sha256 !== expectedFileDigest ||
4925
+ canonicalBrowserEvidenceJson(entry.lineage) !==
4926
+ canonicalBrowserEvidenceJson(expectedLineage)
4927
+ ) {
4928
+ throw new Error("persisted evidence authority failed verification");
4929
+ }
4930
+ return {
4931
+ artifact: publicArtifactMetadata(entry),
4932
+ error: null,
4933
+ };
4934
+ } catch (error) {
4935
+ const code =
4936
+ typeof error?.code === "string"
4937
+ ? error.code.replace(/[^A-Z0-9_-]/giu, "").slice(0, 40)
4938
+ : "";
4939
+ return {
4940
+ artifact: null,
4941
+ error: `browser evidence artifact publication failed${code ? ` (${code})` : ""}`,
4942
+ };
4943
+ }
4944
+ }
4945
+
4946
+ async function resolveBrowserUploadArtifact(artifactId, sessionId) {
4947
+ const { ArtifactStore, publicArtifactMetadata } =
4948
+ await import("../lib/artifact-store.js");
4949
+ const store = new ArtifactStore();
4950
+ return store.withIndexSnapshot((entries) => {
4951
+ const matches = entries.filter((entry) => entry.id === artifactId);
4952
+ if (matches.length !== 1) {
4953
+ throw new Error(
4954
+ matches.length === 0
4955
+ ? "upload artifact was not found"
4956
+ : "upload artifact authority is ambiguous",
4957
+ );
4958
+ }
4959
+ const entry = matches[0];
4960
+ if (!sessionId || entry.sessionId !== String(sessionId)) {
4961
+ throw new Error("upload artifact is not bound to the active session");
4962
+ }
4963
+ if (
4964
+ typeof entry.file !== "string" ||
4965
+ path.basename(entry.file) !== entry.file ||
4966
+ !(entry.file === entry.id || entry.file.startsWith(`${entry.id}.`)) ||
4967
+ !/^[a-f0-9]{64}$/u.test(String(entry.sha256 || ""))
4968
+ ) {
4969
+ throw new Error("upload artifact storage authority is invalid");
4970
+ }
4971
+ const integrity = store.verifyIntegrity(entry);
4972
+ if (!integrity.ok) {
4973
+ throw new Error("upload artifact failed digest verification");
4974
+ }
4975
+ const storedPath = store.storedPath(entry);
4976
+ if (fs.statSync(storedPath).size !== Number(entry.size)) {
4977
+ throw new Error("upload artifact size authority mismatch");
4978
+ }
4979
+ const temporaryDirectory = fs.mkdtempSync(
4980
+ path.join(os.tmpdir(), "cc-browser-upload-"),
4981
+ );
4982
+ const temporaryPath = path.join(
4983
+ temporaryDirectory,
4984
+ path.basename(entry.file || "upload.bin"),
4985
+ );
4986
+ try {
4987
+ fs.writeFileSync(temporaryPath, fs.readFileSync(storedPath), {
4988
+ flag: "wx",
4989
+ mode: 0o600,
4990
+ flush: true,
4991
+ });
4992
+ } catch (error) {
4993
+ fs.rmSync(temporaryDirectory, { recursive: true, force: true });
4994
+ throw error;
4995
+ }
4996
+ return {
4997
+ path: temporaryPath,
4998
+ metadata: publicArtifactMetadata(entry),
4999
+ cleanup: () =>
5000
+ fs.rmSync(temporaryDirectory, { recursive: true, force: true }),
5001
+ };
5002
+ });
5003
+ }
5004
+
4793
5005
  const MCP_LEDGER_EFFECTS = new Set(["read", "unknown", "write", "destructive"]);
4794
5006
 
4795
5007
  /**
@@ -5054,10 +5266,17 @@ async function executeToolInner(
5054
5266
  onToolCallSettlement = null,
5055
5267
  backgroundUsageFailureState = null,
5056
5268
  toolAdmission = null,
5269
+ hostResourceBudget = null,
5057
5270
  unattendedActionPolicy = null,
5058
5271
  managedCheckpoint = false,
5059
5272
  fileMutationScope = null,
5060
5273
  hermeticExecution = false,
5274
+ browserEvidenceBinding = null,
5275
+ browserOriginGrants = null,
5276
+ browserExpectedGrantRevisions = null,
5277
+ browserReplaySourceEnvelope = null,
5278
+ browserReplayAllowSideEffects = false,
5279
+ browserReplayAllowCredentials = false,
5061
5280
  // Hook-envelope tracing: this run's trace id, threaded into child loops
5062
5281
  // (spawn_sub_agent / isolated run_skill) as their parent_id.
5063
5282
  hookTraceId = null,
@@ -6776,6 +6995,7 @@ async function executeToolInner(
6776
6995
  subAgentDepth,
6777
6996
  subAgentBudget,
6778
6997
  sessionBudget,
6998
+ hostResourceBudget,
6779
6999
  subAgentContract,
6780
7000
  settingsHooks,
6781
7001
  // Immutable parent execution authority. The child may only tighten
@@ -6840,6 +7060,7 @@ async function executeToolInner(
6840
7060
  maxBytes: args.maxBytes,
6841
7061
  timeout: args.timeout,
6842
7062
  config: webFetchConfig,
7063
+ hostResourceBudget,
6843
7064
  });
6844
7065
  return attachDescriptor(result);
6845
7066
  } catch (err) {
@@ -6867,6 +7088,7 @@ async function executeToolInner(
6867
7088
  maxResults: args.maxResults,
6868
7089
  timeout: args.timeout,
6869
7090
  config: webSearchConfig,
7091
+ hostResourceBudget,
6870
7092
  });
6871
7093
  return attachDescriptor(result);
6872
7094
  } catch (err) {
@@ -7332,6 +7554,14 @@ async function executeToolInner(
7332
7554
  tab: args.tab != null ? Number(args.tab) : undefined,
7333
7555
  continueOnError: args.continue_on_error === true,
7334
7556
  sessionId: sessionId ? String(sessionId) : null,
7557
+ evidenceBinding: browserEvidenceBinding,
7558
+ originGrants: browserOriginGrants,
7559
+ expectedGrantRevisions: browserExpectedGrantRevisions,
7560
+ replaySourceEnvelope: browserReplaySourceEnvelope,
7561
+ replayAllowSideEffects: browserReplayAllowSideEffects,
7562
+ replayAllowCredentials: browserReplayAllowCredentials,
7563
+ resolveUploadArtifact: (artifactId) =>
7564
+ resolveBrowserUploadArtifact(artifactId, sessionId),
7335
7565
  });
7336
7566
  if (!result.ok && result.error) {
7337
7567
  // Nothing ran (validation / attach failure) — surface as an error.
@@ -7364,8 +7594,45 @@ async function executeToolInner(
7364
7594
  step.detail = promoted.error;
7365
7595
  }
7366
7596
  }
7597
+ if (originalStep.downloadPath) {
7598
+ const promoted = await promoteBrowserDownload(
7599
+ originalStep.downloadPath,
7600
+ {
7601
+ sessionId,
7602
+ title: `Browser download ${i + 1} — ${originalStep.downloadSuggestedName || "file"}`,
7603
+ },
7604
+ );
7605
+ delete step.downloadPath;
7606
+ delete step.downloadRef;
7607
+ if (promoted.artifact) {
7608
+ step.downloadArtifact = promoted.artifact;
7609
+ step.downloadRef = promoted.artifact.id;
7610
+ step.detail = `download artifact: ${promoted.artifact.id}`;
7611
+ } else {
7612
+ step.downloadArtifactError = promoted.error;
7613
+ step.detail = promoted.error;
7614
+ }
7615
+ }
7367
7616
  safeResult.steps.push(step);
7368
7617
  }
7618
+ if (result.evidence) {
7619
+ const publishedEvidence = await publishBrowserEvidence(
7620
+ result.evidence,
7621
+ sessionId,
7622
+ );
7623
+ safeResult.evidence = result.evidence;
7624
+ if (publishedEvidence.artifact) {
7625
+ safeResult.evidenceArtifact = publishedEvidence.artifact;
7626
+ safeResult.evidenceRef = publishedEvidence.artifact.id;
7627
+ } else {
7628
+ safeResult.evidenceArtifactError = publishedEvidence.error;
7629
+ safeResult.evidencePublicationFailed = true;
7630
+ safeResult.ok = false;
7631
+ safeResult.retrySafe = false;
7632
+ safeResult.recovery =
7633
+ "Browser actions may have completed, but canonical evidence publication failed; do not retry side effects automatically.";
7634
+ }
7635
+ }
7369
7636
  return attachDescriptor(safeResult);
7370
7637
  } catch (err) {
7371
7638
  return attachDescriptor({
@@ -7798,6 +8065,7 @@ async function executeToolInner(
7798
8065
  ? { workflowEffectId: workflowChildEffectId }
7799
8066
  : {}),
7800
8067
  ...(sessionBudget ? { sessionBudget } : {}),
8068
+ ...(hostResourceBudget ? { hostResourceBudget } : {}),
7801
8069
  ...(permissionRules ? { permissionRules } : {}),
7802
8070
  ...(hostManagedToolPolicy
7803
8071
  ? {
@@ -9613,6 +9881,10 @@ async function _executeSpawnSubAgent(args, ctx) {
9613
9881
  const subLlmOptions = {
9614
9882
  ...parentLlm,
9615
9883
  model: mdModel || parentLlm.model || undefined,
9884
+ // Preserve the host's optional event channel across every nesting level.
9885
+ // It is observational only: child hooks/tools must never depend on a
9886
+ // headless consumer being connected.
9887
+ ...(interaction ? { interaction } : {}),
9616
9888
  // Contract `effort` is a compute hint (reasoning level), not authority —
9617
9889
  // forwarded to the child loop; harmless if the provider ignores it.
9618
9890
  ...(effectiveContract?.effort ? { effort: effectiveContract.effort } : {}),
@@ -9820,7 +10092,21 @@ async function _executeSpawnSubAgent(args, ctx) {
9820
10092
  // single total-sub-agent pool (breadth cap spans the whole tree).
9821
10093
  subAgentBudget: ctx.subAgentBudget || null,
9822
10094
  ...(ctx.sessionBudget ? { sessionBudget: ctx.sessionBudget } : {}),
10095
+ ...(ctx.hostResourceBudget
10096
+ ? { hostResourceBudget: ctx.hostResourceBudget }
10097
+ : {}),
9823
10098
  onUsage,
10099
+ ...(interaction && typeof interaction.emit === "function"
10100
+ ? {
10101
+ onProgress: (progress) =>
10102
+ emit("sub-agent.progress", {
10103
+ event_type: progress?.type || "unknown",
10104
+ tool: progress?.tool || null,
10105
+ iteration_count: progress?.iterationCount || 0,
10106
+ token_count: progress?.tokenCount || 0,
10107
+ }),
10108
+ }
10109
+ : {}),
9824
10110
  ...(ctx.strictUsageTelemetry === true
9825
10111
  ? {
9826
10112
  strictUsageTelemetry: true,
@@ -12730,6 +13016,9 @@ export async function* agentLoop(messages, options) {
12730
13016
  const { IterationBudget, WarningLevel } =
12731
13017
  await import("../lib/iteration-budget.js");
12732
13018
  const budget = options.iterationBudget || new IterationBudget();
13019
+ const { HostResourceBudget } = await import("../lib/host-resource-budget.js");
13020
+ const hostResourceBudget =
13021
+ options.hostResourceBudget || new HostResourceBudget();
12733
13022
  const signal = options.signal || null;
12734
13023
  const workflowEffectId = _normalizeWorkflowEffectId(options.workflowEffectId);
12735
13024
  // Optional OpenTelemetry recorder (TelemetryRecorder). When present, the loop
@@ -12943,6 +13232,10 @@ export async function* agentLoop(messages, options) {
12943
13232
  // CLI root does not create one yet; when supplied, every nested child sees
12944
13233
  // the same object and cannot reset concurrency/spawn/depth totals.
12945
13234
  sessionBudget: options.sessionBudget || null,
13235
+ // Share bounded WebFetch cache and renderer/tool/event admission across
13236
+ // the main loop and every nested subagent. A host can tighten these limits
13237
+ // by supplying its own budget; otherwise the conservative defaults apply.
13238
+ hostResourceBudget,
12946
13239
  // This loop's EFFECTIVE subagent contract (set when this loop IS a spawned
12947
13240
  // sub-agent). Threaded so a nested spawn_sub_agent sees it as the parent
12948
13241
  // ceiling (tighten-only). null at the top level (no ceiling).