chainlesschain 0.165.2 → 0.165.4

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 (210) hide show
  1. package/README.md +151 -29
  2. package/package.json +2 -2
  3. package/src/assets/web-panel/assets/{AIOps-lS1R0Cza.js → AIOps-C__nnraW.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-BmlgBPsj.js → ActionButton-CsKWHEZ-.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-CNKczv1S.js → Analytics-BhIjfjWO.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-BuZGJARQ.js → AppLayout-BjuXFzWZ.js} +4 -4
  7. package/src/assets/web-panel/assets/{Artifacts-Dm73Sl-O.js → Artifacts-k6whDkZJ.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-BGMW7A5e.js → Audit-C4FBMYRh.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-BQ6M54JR.js → BackgroundAgents-C_vRrSXk.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-DBzGP0bR.js → Backup-CngFZeVp.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-D1mLCoOV.js → BaseInput-B_H9EBRm.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-BUfcN7p8.js → Chat-DLEC5kt7.js} +4 -4
  13. package/src/assets/web-panel/assets/ChatBubbleRenderer-xijcWkJe.js +1 -0
  14. package/src/assets/web-panel/assets/{Checkbox-Du0Yg5Pi.js → Checkbox-m3ClR4xh.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-B2RXziHW.js → Codegen-CmLSFrgp.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-DWhekOrR.js → Col-DFGQteHN.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-HQhrkon4.js → Community-EUUVORHE.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-izHNb4uz.js → Compact-2PSg0Yr7.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-BDwLy41-.js → Compliance-CcKur7gB.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-DFJhLa7K.js → Cowork-DK_Fezfa.js} +3 -3
  21. package/src/assets/web-panel/assets/{Cron-DYY9RG7-.js → Cron-Dbw89xl7.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-rr7tJTtv.js → Crosschain-CH66h_Ec.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-D2sfHRLi.js → DID-D1igRb17.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-q_eGdhha.js → Dashboard-DVAsrobk.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-Cufrh2Bz.js → Dropdown-Dl7W8AQs.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-B-kdv10f.js → EmailListRenderer-D5tpaEQC.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-D21XjgfG.js → FamilyGuardDashboard-O_VQf8gq.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-CAwRTLZH.js → Federation-BTVcgS9n.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-vx3daNDF.js → FormItemContext-BRnkJAIz.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-CRWY2wU4.js → GenericCardRenderer-8OWSCkDj.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-Q6SwauyD.js → Git-WXLYTQj2.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-BJ1q4IQZ.js → Governance-BezaUhtc.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-CSWjROgD.js → Inference-CuRay3Gu.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-fzuQsWuY.js → KnowledgeGraph-DfWLDW1m.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-DVF8Mnns.js → Logs-C55y2pPY.js} +2 -2
  36. package/src/assets/web-panel/assets/MarkdownRenderer-hDpWdiBc.js +1 -0
  37. package/src/assets/web-panel/assets/{Marketplace-BQP7LOA4.js → Marketplace-Dk08Uycg.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-BNlJCmNc.js → McpTools-C11fSB5V.js} +4 -4
  39. package/src/assets/web-panel/assets/{Memory-DLLg5WQ4.js → Memory-mr0eZc97.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-CR2skNAF.js → MobileBridge-C0iCSRbb.js} +1 -1
  41. package/src/assets/web-panel/assets/{MobileProjects-BxVavObl.js → MobileProjects-CY-xMG8Z.js} +1 -1
  42. package/src/assets/web-panel/assets/{Mtc-B17pgqMI.js → Mtc-Bplqc_Wc.js} +4 -4
  43. package/src/assets/web-panel/assets/{MtcAudit-4UmV5cIL.js → MtcAudit-BlzwsoSM.js} +2 -2
  44. package/src/assets/web-panel/assets/{Multisig-DoMEXEcU.js → Multisig-BBLmTty6.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-h9DMXFX4.js → NLProgramming-DtT1uf1W.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-Cihn-xX8.js → Notes-DcqQAxTK.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-BE6ZGa3R.js → NotificationSettings-cb0kWoZe.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-CnwojoSI.js → OrderTableRenderer-kw9HZQNN.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-B2vpwmjb.js → Organization-DlTlbkUN.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-C4z28R0-.js → Overflow-pp1qs-oY.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-BVlFkwhW.js → P2P-BESLnyYz.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-BXbEdL5B.js → PdhVaultBrowser-B-J1mGuf.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-C28xs4lp.js → Permissions-B36PeT1_.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-Dgl_rBjM.js → PersonalDataHub-CTK2ad-3.js} +3 -3
  55. package/src/assets/web-panel/assets/{Pipeline-3QUIhrKI.js → Pipeline-zJNGXsac.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-8Gh33OZ5.js → Privacy-b9fz0Qf0.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-BNmg4tZi.js → ProjectInit-DjZbZgiB.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-vgMfeCf9.js → ProjectSettings-C-hHJXlD.js} +2 -2
  59. package/src/assets/web-panel/assets/Projects-BC9KSDM6.js +1 -0
  60. package/src/assets/web-panel/assets/{Providers-CXoOa8eX.js → Providers-Dz-CAYYU.js} +1 -1
  61. package/src/assets/web-panel/assets/{QrScannerModal-BhfTF0oS.js → QrScannerModal-A0yoQ3-3.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-C746HEAj.js → QuickAsk-DrFgFJNC.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-BSej8Eo0.js → Recommend-KC8hF1g4.js} +1 -1
  64. package/src/assets/web-panel/assets/{RemoteSession-f3gmnlG3.js → RemoteSession-DGTPIk6u.js} +3 -3
  65. package/src/assets/web-panel/assets/{Reputation-CyvybpkN.js → Reputation-QmbwM7Yk.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-DwV2PeYn.js → Row-BxjJylia.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-11GrzjZy.js → RssFeed-B7Wda1J6.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-BjKXkrAY.js → Search-_plQ_YSA.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-eWiFb9Yk.js → Security-CD2YJZfx.js} +2 -2
  70. package/src/assets/web-panel/assets/{Services-CdCsMAtt.js → Services-qQE7NmwE.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-4Q2UTKQ5.js → Skeleton-DgQqkFf7.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-v4rtYrRj.js → Skills-C4C0oFFt.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-CRhsFvd_.js → Sla-Px2N2B5c.js} +1 -1
  74. package/src/assets/web-panel/assets/SpeechSettings-DN6C3lQd.js +1 -0
  75. package/src/assets/web-panel/assets/{SyncSettings-D16zonl7.js → SyncSettings-jm5aH_m7.js} +2 -2
  76. package/src/assets/web-panel/assets/{Tasks-Xxozz0i_.js → Tasks-DlkJcv67.js} +1 -1
  77. package/src/assets/web-panel/assets/{Templates-CXJpPtCT.js → Templates-DyrTHUBs.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-XRV0L1ZF.js → Tenant-mC434PtL.js} +1 -1
  79. package/src/assets/web-panel/assets/{Terminal-CYuO1i_w.js → Terminal-o0_s3NgK.js} +2 -2
  80. package/src/assets/web-panel/assets/{TimelineRenderer-BXqitWsu.js → TimelineRenderer-DAGlAXOw.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-BvPrDHIy.js → Tokens-BnulS_bs.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-DhCrSTf5.js → Trigger-suQbVXYM.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-DmsuZD6K.js → Trust-DbIJAPo5.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-D_yrts5C.js → UkeySign-CQNpbIHi.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-B01ihPrm.js → VideoEditing-D8aWCERk.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-DpUjKa-N.js → Wallet-CuLpYfZc.js} +2 -2
  87. package/src/assets/web-panel/assets/{WebAuthn-CL07yON6.js → WebAuthn-CsfG8ZMc.js} +2 -2
  88. package/src/assets/web-panel/assets/{WorkflowEditor-CLMflnRr.js → WorkflowEditor-BYsEAZbd.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-DtUqe8h_.js → chat-FT4Um3-I.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-DPKrgVfy.js → colors-CKbS_Wlt.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-BTt2GtOm.js → compact-item-CFJtzuJM.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-D_VeUc1J.js → createContext-B9kSRW6K.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-DJZ0gAMu.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-1kndiylj.js → hasIn-DR-x0Xpi.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-dVc-CXY4.js → index-7jHr_A_k.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-DFIZ_1Sf.js → index-B3ZX81mK.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-fk2Rjacw.js → index-B7osrXqy.js} +3 -3
  98. package/src/assets/web-panel/assets/{index-CHG-KcS4.js → index-BGbPnC5x.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-Dbbymxpj.js → index-BI5hP_qy.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-BaZAbw9A.js → index-BK3TiKVq.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-CzjkKUmR.js → index-BVPU43b1.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-BAXfRKfG.js → index-BW-t9n-q.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-8nz_fmlj.js → index-BfFCQHL3.js} +1 -1
  104. package/src/assets/web-panel/assets/index-Bizb4hkw.js +1 -0
  105. package/src/assets/web-panel/assets/{index-DdkplL9R.js → index-Bt4fS2eL.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DG2MZQ3f.js → index-BwR7yc2h.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-DfKBRdSS.js → index-Bzz0C1BZ.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-GsoUQ2M7.js → index-C2JvmYRc.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-l1BETrDb.js → index-CGaXUsIs.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-4bna2_SR.js → index-CJmIQ9XR.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DfGl8CqG.js → index-C_enk9I_.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-D95OFht7.js → index-Cr2FLUsD.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-DsJCDUJG.js → index-CvrCCqJt.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-sDoMHTNA.js → index-D4LfPvWA.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-By5n8up9.js → index-DMGmg497.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-ocf06EVQ.js → index-DShSkww-.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-Bhudc_Ez.js → index-DTxNy0ZU.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-CX81qSM4.js → index-DW4BWjTk.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-BlDNVgBt.js → index-DWdqx7zI.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CcO04eDn.js → index-Dap9c3eD.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-Dwqmtk65.js → index-DcfxhKXR.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-2eyAXE3d.js → index-DdkIhfi-.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-brCInrzq.js → index-DeSgw-WV.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-DJ8vXGOa.js → index-DiNUEpSQ.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BHpBMWCh.js → index-DjEP7WkH.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-m31Ka8hZ.js → index-DtkFqPVA.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CtF7EN49.js → index-KqDaCApw.js} +1 -1
  128. package/src/assets/web-panel/assets/index-OHSl-xCh.js +1 -0
  129. package/src/assets/web-panel/assets/{index-B9KvcS7R.js → index-OSzjTzGM.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-CauoBQkH.js → index-QBSeNVO3.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-FzdwcSy2.js → index-WE08gMJP.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DxdTdBix.js → index-r2VI1Ikk.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-BepLZwgB.js → index-tqSEHPRT.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-CvyYJd7z.js → initDefaultProps-Dd7n7VgI.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-DYZkhUdz.js → motion-BwxouRw1.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-slnJRVT1.js → move-DObN0PG9.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-DVc0CKmy.js → mtc-parser-B3nOUQc7.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-BCXAtHCq.js → omit-o9WU2Nbl.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-DBsemz_K.js → pickAttrs-CL_vvfQ_.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-BRtkJ-nv.js → placementArrow-CYrM2tyK.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-Cebq7EZn.js → responsiveObserve-k_06cQ96.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-DT7qvId2.js → slide-CPKG0pxS.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-pQiITLkG.js → statusUtils-BDDEeLTw.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-c-19BVKQ.js → styleChecker-Cmb7RTh7.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-DsS5-0bE.js → useFlexGapSupport-e2IedC4N.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-CxGiMe5n.js → useFs-CE_gxVnm.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-D9btVID5.js → usePersonalDataHub-BkMIIKMz.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-CUYFsFEN.js → vnode-DW886XV1.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-CXmn_35j.js → zoom-Dwo_adaf.js} +1 -1
  150. package/src/assets/web-panel/index.html +1 -1
  151. package/src/command-help-index.json +3 -3
  152. package/src/commands/agent.js +105 -35
  153. package/src/commands/artifacts.js +363 -33
  154. package/src/commands/cowork.js +202 -36
  155. package/src/commands/session-budget.js +155 -0
  156. package/src/commands/session-location.js +948 -0
  157. package/src/commands/session.js +72 -46
  158. package/src/data/changelog.json +26 -0
  159. package/src/gateways/ws/artifact-protocol.js +77 -13
  160. package/src/gateways/ws/session-protocol.js +391 -24
  161. package/src/gateways/ws/ws-agent-handler.js +191 -14
  162. package/src/gateways/ws/ws-server.js +14 -3
  163. package/src/gateways/ws/ws-session-gateway.js +101 -5
  164. package/src/harness/jsonl-session-store.js +1210 -0
  165. package/src/lib/agent-team/team-runner.js +43 -13
  166. package/src/lib/artifact-access-ledger.js +461 -0
  167. package/src/lib/artifact-cleanup-ledger.js +861 -0
  168. package/src/lib/artifact-deletion-ledger.js +677 -0
  169. package/src/lib/artifact-store.js +256 -51
  170. package/src/lib/background-agent-keeper-protocol.js +75 -4
  171. package/src/lib/background-agent-launch-barrier.js +74 -0
  172. package/src/lib/background-agent-supervisor.js +149 -5
  173. package/src/lib/background-turn-bootstrap-protocol.js +4 -0
  174. package/src/lib/command-lifecycle-report.js +8 -4
  175. package/src/lib/cowork-adapter.js +9 -5
  176. package/src/lib/cowork-task-runner.js +20 -0
  177. package/src/lib/cowork-workflow.js +178 -20
  178. package/src/lib/direct-model-usage.js +62 -22
  179. package/src/lib/dynamic-workflow-runtime.js +3184 -111
  180. package/src/lib/execution-location-result-apply.js +339 -0
  181. package/src/lib/execution-location-result-artifact.js +271 -0
  182. package/src/lib/execution-location-result-review.js +253 -0
  183. package/src/lib/execution-location-result-store.js +331 -0
  184. package/src/lib/execution-location-result.js +617 -0
  185. package/src/lib/execution-location-target.js +236 -1
  186. package/src/lib/managed-tool-checkpoint.js +47 -4
  187. package/src/lib/process-execution-broker/workspace-transaction.js +3 -0
  188. package/src/lib/session-budget-production-root.js +376 -0
  189. package/src/lib/session-budget-runtime.js +109 -18
  190. package/src/lib/session-budget-usage.js +63 -0
  191. package/src/lib/session-host-snapshot.js +19 -2
  192. package/src/lib/session-resource-budget.js +766 -105
  193. package/src/lib/sub-agent-context.js +69 -22
  194. package/src/lib/web-ui-server.js +12 -1
  195. package/src/lib/with-file-lock.js +175 -26
  196. package/src/repl/agent-repl.js +237 -16
  197. package/src/runtime/agent-core.js +123 -0
  198. package/src/runtime/headless-runner.js +135 -46
  199. package/src/runtime/headless-stream.js +133 -25
  200. package/src/runtime/policies/agent-policy.js +10 -0
  201. package/src/workers/background-agent-keeper.js +112 -19
  202. package/src/workers/background-agent-worker.js +383 -134
  203. package/src/workers/background-turn-bootstrap.js +13 -8
  204. package/src/assets/web-panel/assets/ChatBubbleRenderer-CY5m8ZHg.js +0 -1
  205. package/src/assets/web-panel/assets/MarkdownRenderer-BLif4QSg.js +0 -1
  206. package/src/assets/web-panel/assets/Projects-BhtAVilc.js +0 -1
  207. package/src/assets/web-panel/assets/SpeechSettings-DLjKsDVu.js +0 -1
  208. package/src/assets/web-panel/assets/devWarning-Bj5nUW2v.js +0 -1
  209. package/src/assets/web-panel/assets/index-CPcM-eqo.js +0 -1
  210. package/src/assets/web-panel/assets/index-xeSyVoRe.js +0 -1
@@ -79,6 +79,16 @@ import {
79
79
  readSessionHostResumeState,
80
80
  } from "../lib/session-host-snapshot.js";
81
81
  import { acquireSessionHostLease } from "../lib/session-host-lease.js";
82
+ import {
83
+ openProductionSessionBudgetRoot,
84
+ sessionBudgetAdmissionError,
85
+ } from "../lib/session-budget-production-root.js";
86
+ import {
87
+ beginSessionBudgetUsage,
88
+ markSessionBudgetUsageUnknown,
89
+ recordSessionBudgetUsage,
90
+ rejectSessionBudgetUsageUnknown,
91
+ } from "../lib/session-budget-usage.js";
82
92
  import {
83
93
  SideEffectLedger,
84
94
  classifyToolSideEffect,
@@ -236,6 +246,29 @@ export function resolveReplMeteredSessionId(useJsonl, sessionId) {
236
246
  return useJsonl && sessionId ? sessionId : null;
237
247
  }
238
248
 
249
+ export function combineReplSignals(...signals) {
250
+ const active = [...new Set(signals.filter(Boolean))];
251
+ if (active.length === 0) return null;
252
+ if (active.length === 1) return active[0];
253
+ return AbortSignal.any(active);
254
+ }
255
+
256
+ export async function closeReplSessionBudgetRootScope(scope) {
257
+ const root = scope?.root || null;
258
+ if (!root) return false;
259
+ const closed = await root.close();
260
+ scope.root = null;
261
+ return closed;
262
+ }
263
+
264
+ function releaseReplSessionHostLeaseScope(scope) {
265
+ const lease = scope?.lease || null;
266
+ if (!lease) return false;
267
+ const released = lease.release?.();
268
+ scope.lease = null;
269
+ return released;
270
+ }
271
+
239
272
  function attachReplCompactionLedgerMetadata(error, callId, settled) {
240
273
  let target = error;
241
274
  if (!target || (typeof target !== "object" && typeof target !== "function")) {
@@ -293,6 +326,7 @@ export async function runReplMeteredModelCallWithLedger({
293
326
  provider,
294
327
  model,
295
328
  source = "model",
329
+ sessionBudget = null,
296
330
  call,
297
331
  attachErrorMetadata = false,
298
332
  }) {
@@ -311,6 +345,7 @@ export async function runReplMeteredModelCallWithLedger({
311
345
  provider,
312
346
  model,
313
347
  source,
348
+ sessionBudget,
314
349
  call,
315
350
  });
316
351
  return Object.freeze({ result, callId, usageLedgerSettled });
@@ -545,7 +580,7 @@ async function _persistAlwaysAllow(tool, args) {
545
580
  /**
546
581
  * Execute a tool call — delegates to agent-core with REPL's hookDb and cwd.
547
582
  */
548
- async function executeTool(name, args) {
583
+ async function executeTool(name, args, context = {}) {
549
584
  return coreExecuteTool(name, args, {
550
585
  hookDb: _hookDb,
551
586
  cwd: process.cwd(),
@@ -556,6 +591,9 @@ async function executeTool(name, args) {
556
591
  settingsHooks: _settingsHooks,
557
592
  classifyAllShell: _classifyAllShell,
558
593
  sandbox: _sandbox,
594
+ sessionId: context.sessionId || null,
595
+ sessionBudget: context.sessionBudget || null,
596
+ signal: context.signal || null,
559
597
  });
560
598
  }
561
599
 
@@ -938,6 +976,11 @@ export async function agentLoop(messages, options) {
938
976
  persistTokenUsage(options.sessionId, projectRuntimeTokenUsage(event)),
939
977
  );
940
978
  }
979
+ recordSessionBudgetUsage(
980
+ options.sessionBudget,
981
+ event,
982
+ "REPL usage settlement",
983
+ );
941
984
  } else if (
942
985
  event.type === "model-usage-started" ||
943
986
  event.type === "model-usage-unknown" ||
@@ -966,6 +1009,15 @@ export async function agentLoop(messages, options) {
966
1009
  ),
967
1010
  );
968
1011
  }
1012
+ if (event.type === "model-usage-started") {
1013
+ beginSessionBudgetUsage(
1014
+ options.sessionBudget,
1015
+ event,
1016
+ "REPL provider call",
1017
+ );
1018
+ } else if (markSessionBudgetUsageUnknown(options.sessionBudget, event)) {
1019
+ rejectSessionBudgetUsageUnknown(event, "REPL provider call");
1020
+ }
969
1021
  } else if (event.type === "iteration-warning") {
970
1022
  writeOut(chalk.yellow(`\n ${event.message}\n`));
971
1023
  } else if (event.type === "iteration-budget-exhausted") {
@@ -2630,6 +2682,17 @@ export async function runReplStartupBoundary(options, startupDependencies) {
2630
2682
  }
2631
2683
  return refuseStartup(options, startupCandidate);
2632
2684
  }
2685
+ if (
2686
+ options.sessionBudgetRoot?.enabled === true &&
2687
+ startupAdmission.useJsonl !== true
2688
+ ) {
2689
+ throw Object.assign(
2690
+ new Error(
2691
+ "session budget root requires durable JSONL session persistence, but JSONL storage is unavailable",
2692
+ ),
2693
+ { code: "CC_SESSION_BUDGET_JSONL_REQUIRED" },
2694
+ );
2695
+ }
2633
2696
 
2634
2697
  // Only a frozen, branded admission capability may cross into workspace,
2635
2698
  // pipe, config, plugin, hook, MCP, model, or tool initialization.
@@ -2660,6 +2723,7 @@ export async function runReplStartupBoundary(options, startupDependencies) {
2660
2723
  null,
2661
2724
  );
2662
2725
  const leaseScope = options._sessionHostLeaseScope || null;
2726
+ const budgetScope = options._sessionBudgetRootScope || null;
2663
2727
  const leaseSessionId = startupCandidate?.sessionId || options.sessionId;
2664
2728
  if (
2665
2729
  leaseScope &&
@@ -2669,9 +2733,79 @@ export async function runReplStartupBoundary(options, startupDependencies) {
2669
2733
  ) {
2670
2734
  leaseScope.lease = acquireHostLease(leaseSessionId, { hostKind: "repl" });
2671
2735
  }
2736
+ let workspaceOptions = options;
2737
+ if (options.sessionBudgetRoot?.enabled === true) {
2738
+ if (!leaseSessionId || !leaseScope?.lease) {
2739
+ throw Object.assign(
2740
+ new Error(
2741
+ "session budget root requires an acquired REPL host lease for its durable session",
2742
+ ),
2743
+ { code: "CC_SESSION_BUDGET_LEASE_REQUIRED" },
2744
+ );
2745
+ }
2746
+ if (!budgetScope || budgetScope.root) {
2747
+ throw Object.assign(
2748
+ new Error("REPL session budget root scope is invalid"),
2749
+ { code: "CC_SESSION_BUDGET_SCOPE_INVALID" },
2750
+ );
2751
+ }
2752
+ const openBudgetRoot = dependencyDataFunction(
2753
+ startupDependencies,
2754
+ "openProductionSessionBudgetRoot",
2755
+ null,
2756
+ );
2757
+ if (typeof openBudgetRoot !== "function") {
2758
+ throw invalidReplRecovery(
2759
+ "REPL session budget root dependency is missing",
2760
+ "CC_REPL_STARTUP_DEPENDENCY_INVALID",
2761
+ );
2762
+ }
2763
+ const root = openBudgetRoot(
2764
+ leaseSessionId,
2765
+ options.sessionBudgetRoot,
2766
+ {
2767
+ persist: true,
2768
+ signal: combineReplSignals(options.signal, leaseScope.lease.signal),
2769
+ table: options.sessionBudgetRoot.table,
2770
+ },
2771
+ );
2772
+ if (
2773
+ root?.enabled !== true ||
2774
+ !root.budget ||
2775
+ !root.options ||
2776
+ root.options.sessionBudget !== root.budget ||
2777
+ typeof root.close !== "function"
2778
+ ) {
2779
+ try {
2780
+ root?.close?.();
2781
+ } catch {
2782
+ // The invalid root is rejected regardless of cleanup outcome.
2783
+ }
2784
+ throw Object.assign(new Error("REPL session budget root is invalid"), {
2785
+ code: "CC_SESSION_BUDGET_ROOT_INVALID",
2786
+ });
2787
+ }
2788
+ if (root.budget.signal?.aborted === true) {
2789
+ const admissionError = sessionBudgetAdmissionError(
2790
+ root.budget.reason?.(),
2791
+ "REPL startup",
2792
+ );
2793
+ try {
2794
+ await root.close();
2795
+ } catch (cleanupError) {
2796
+ throw new AggregateError(
2797
+ [admissionError, cleanupError],
2798
+ "REPL budget admission and authority cleanup both failed",
2799
+ );
2800
+ }
2801
+ throw admissionError;
2802
+ }
2803
+ budgetScope.root = root;
2804
+ workspaceOptions = { ...options, ...root.options };
2805
+ }
2672
2806
  const trustedWorkspaceRoot = readCwd();
2673
2807
  return enterWorkspace(trustedWorkspaceRoot, () =>
2674
- startWorkspace(options, startupAdmission),
2808
+ startWorkspace(workspaceOptions, startupAdmission),
2675
2809
  );
2676
2810
  }
2677
2811
 
@@ -2681,26 +2815,34 @@ export function startReplJsonlSession(
2681
2815
  requestedId,
2682
2816
  meta,
2683
2817
  observabilityScope,
2818
+ options = {},
2684
2819
  ) {
2820
+ const requireDurable =
2821
+ observabilityScope != null || options.requireDurable === true;
2685
2822
  try {
2686
2823
  const sessionId = startSession(requestedId, {
2687
2824
  ...meta,
2688
2825
  ...(observabilityScope != null ? { observabilityScope } : {}),
2689
2826
  });
2690
2827
  if (
2691
- observabilityScope != null &&
2828
+ requireDurable &&
2692
2829
  (typeof sessionId !== "string" || !sessionId)
2693
2830
  ) {
2694
2831
  throw new Error("JSONL session creation returned no durable session id");
2695
2832
  }
2696
2833
  return sessionId || null;
2697
2834
  } catch (error) {
2698
- if (observabilityScope == null) return null;
2835
+ if (!requireDurable) return null;
2699
2836
  const failure = new Error(
2700
- "scoped JSONL session could not be durably created",
2837
+ observabilityScope != null
2838
+ ? "scoped JSONL session could not be durably created"
2839
+ : "budgeted JSONL session could not be durably created",
2701
2840
  { cause: error },
2702
2841
  );
2703
- failure.code = "CC_OBSERVABILITY_SCOPE_START_FAILED";
2842
+ failure.code =
2843
+ observabilityScope != null
2844
+ ? "CC_OBSERVABILITY_SCOPE_START_FAILED"
2845
+ : "CC_SESSION_BUDGET_SESSION_START_FAILED";
2704
2846
  throw failure;
2705
2847
  }
2706
2848
  }
@@ -2708,23 +2850,45 @@ export function startReplJsonlSession(
2708
2850
  /** Start the agentic REPL with non-overridable production bindings. */
2709
2851
  export async function startAgentRepl(options = {}) {
2710
2852
  const sessionHostLeaseScope = { lease: null };
2853
+ const sessionBudgetRootScope = { root: null };
2711
2854
  const runtimeOptions = {
2712
2855
  ...options,
2713
2856
  _sessionHostLeaseScope: sessionHostLeaseScope,
2857
+ _sessionBudgetRootScope: sessionBudgetRootScope,
2714
2858
  };
2715
2859
  try {
2716
2860
  const result = await runReplStartupBoundary(runtimeOptions, {
2717
2861
  prepareReplStartupResume,
2718
2862
  refuseReplStartupResume,
2719
2863
  acquireSessionHostLease,
2864
+ openProductionSessionBudgetRoot,
2720
2865
  cwd: () => process.cwd(),
2721
2866
  runWithHostHooksV2Workspace,
2722
2867
  startAgentReplInWorkspace,
2723
2868
  });
2724
- if (result?.started === false) sessionHostLeaseScope.lease?.release?.();
2869
+ if (result?.started === false) {
2870
+ await closeReplSessionBudgetRootScope(sessionBudgetRootScope);
2871
+ releaseReplSessionHostLeaseScope(sessionHostLeaseScope);
2872
+ }
2725
2873
  return result;
2726
2874
  } catch (error) {
2727
- sessionHostLeaseScope.lease?.release?.();
2875
+ const cleanupErrors = [];
2876
+ try {
2877
+ await closeReplSessionBudgetRootScope(sessionBudgetRootScope);
2878
+ } catch (cleanupError) {
2879
+ cleanupErrors.push(cleanupError);
2880
+ }
2881
+ try {
2882
+ releaseReplSessionHostLeaseScope(sessionHostLeaseScope);
2883
+ } catch (cleanupError) {
2884
+ cleanupErrors.push(cleanupError);
2885
+ }
2886
+ if (cleanupErrors.length > 0) {
2887
+ throw new AggregateError(
2888
+ [error, ...cleanupErrors],
2889
+ "REPL startup and authority cleanup both failed",
2890
+ );
2891
+ }
2728
2892
  throw error;
2729
2893
  }
2730
2894
  }
@@ -2802,6 +2966,8 @@ async function startAgentReplInWorkspaceOwned(
2802
2966
  }
2803
2967
  };
2804
2968
  const _sessionHostLeaseScope = options._sessionHostLeaseScope || null;
2969
+ const _sessionBudgetRootScope = options._sessionBudgetRootScope || null;
2970
+ const _sessionBudget = options.sessionBudget || null;
2805
2971
  let _sessionHostLeaseAbortListener = null;
2806
2972
  let _sessionHostLeaseAbortSignal = null;
2807
2973
  const _detachSessionHostLease = () => {
@@ -2840,6 +3006,35 @@ async function startAgentReplInWorkspaceOwned(
2840
3006
  return previous;
2841
3007
  };
2842
3008
  _attachSessionHostLease();
3009
+ let _sessionBudgetAbortListener = null;
3010
+ let _sessionBudgetAbortSignal = null;
3011
+ const _detachSessionBudget = () => {
3012
+ if (_sessionBudgetAbortListener && _sessionBudgetAbortSignal) {
3013
+ _sessionBudgetAbortSignal.removeEventListener(
3014
+ "abort",
3015
+ _sessionBudgetAbortListener,
3016
+ );
3017
+ }
3018
+ _sessionBudgetAbortListener = null;
3019
+ _sessionBudgetAbortSignal = null;
3020
+ };
3021
+ const _attachSessionBudget = () => {
3022
+ const signal = _sessionBudget?.signal;
3023
+ if (!signal || _sessionBudgetAbortListener) return;
3024
+ _sessionBudgetAbortListener = () =>
3025
+ _requestReplOutputClose(
3026
+ sessionBudgetAdmissionError(
3027
+ _sessionBudget.reason?.() || "session-aborted",
3028
+ "REPL session",
3029
+ ),
3030
+ );
3031
+ _sessionBudgetAbortSignal = signal;
3032
+ signal.addEventListener("abort", _sessionBudgetAbortListener, {
3033
+ once: true,
3034
+ });
3035
+ if (signal.aborted) _sessionBudgetAbortListener();
3036
+ };
3037
+ _attachSessionBudget();
2843
3038
  const _replOutputFlow = outputScope.flow;
2844
3039
  outputScope.setFailureHandler(_requestReplOutputClose);
2845
3040
  const _disposeReplPipeSafety = installPipeSafety(undefined, () =>
@@ -2895,7 +3090,8 @@ async function startAgentReplInWorkspaceOwned(
2895
3090
  provider: callProvider || provider,
2896
3091
  model: callModel || model,
2897
3092
  source,
2898
- call,
3093
+ sessionBudget: _sessionBudget,
3094
+ call: () => call({ signal: options.signal || null }),
2899
3095
  attachErrorMetadata: includeLedgerMetadata,
2900
3096
  });
2901
3097
  return includeLedgerMetadata ? metered : metered.result;
@@ -2926,7 +3122,12 @@ async function startAgentReplInWorkspaceOwned(
2926
3122
  sessionId: durableSessionId,
2927
3123
  tool,
2928
3124
  args,
2929
- execute: executeTool,
3125
+ execute: (name, toolArgs) =>
3126
+ executeTool(name, toolArgs, {
3127
+ sessionId: durableSessionId,
3128
+ sessionBudget: _sessionBudget,
3129
+ signal: options.signal || null,
3130
+ }),
2930
3131
  now: options.now || Date.now,
2931
3132
  terminalLatch: _runtimeLedgerTerminalLatch,
2932
3133
  });
@@ -3089,13 +3290,13 @@ async function startAgentReplInWorkspaceOwned(
3089
3290
  callModel: model,
3090
3291
  source: "semantic-compaction",
3091
3292
  includeLedgerMetadata: true,
3092
- call: () =>
3293
+ call: ({ signal }) =>
3093
3294
  chatWithTools([{ role: "user", content: prompt }], {
3094
3295
  provider,
3095
3296
  model,
3096
3297
  baseUrl,
3097
3298
  apiKey,
3098
- signal: _sessionHostLeaseScope?.lease?.signal,
3299
+ signal,
3099
3300
  enabledToolNames: [],
3100
3301
  extraToolDefinitions: [],
3101
3302
  hostManagedToolPolicy: null,
@@ -3535,6 +3736,7 @@ async function startAgentReplInWorkspaceOwned(
3535
3736
  options.sessionId || null,
3536
3737
  meta,
3537
3738
  options.observabilityScope,
3739
+ { requireDurable: Boolean(_sessionBudget) },
3538
3740
  );
3539
3741
  if (
3540
3742
  sessionId &&
@@ -4410,7 +4612,11 @@ async function startAgentReplInWorkspaceOwned(
4410
4612
  callProvider: request?.provider,
4411
4613
  callModel: request?.model,
4412
4614
  source: "model",
4413
- call: () => invokeToolFreeAdvisor(request),
4615
+ call: ({ signal }) =>
4616
+ invokeToolFreeAdvisor({
4617
+ ...request,
4618
+ signal: combineReplSignals(request?.signal, signal),
4619
+ }),
4414
4620
  }),
4415
4621
  onEvent: (event) => {
4416
4622
  if (!useJsonl || !sessionId) return;
@@ -6953,6 +7159,14 @@ async function startAgentReplInWorkspaceOwned(
6953
7159
  if (sessionArg.startsWith("resume ")) {
6954
7160
  const resumeId = sessionArg.slice(7).trim();
6955
7161
  try {
7162
+ if (_sessionBudget && resumeId !== sessionId) {
7163
+ throw Object.assign(
7164
+ new Error(
7165
+ "a budgeted REPL is bound to its startup session; exit and restart to resume another session",
7166
+ ),
7167
+ { code: "CC_SESSION_BUDGET_REPL_SWITCH_UNSUPPORTED" },
7168
+ );
7169
+ }
6956
7170
  if (useJsonl) {
6957
7171
  const initialCandidate = _prepareJsonlResumeCandidate(resumeId);
6958
7172
  if (!initialCandidate.ok) throw initialCandidate.error;
@@ -9084,7 +9298,7 @@ async function startAgentReplInWorkspaceOwned(
9084
9298
  // of hanging forever. undefined → agent-core's 180s default (matches cc
9085
9299
  // chat/ask); config.llm.streamStallTimeoutMs tunes or disables (0).
9086
9300
  streamStallTimeoutMs: _streamStallTimeoutMs,
9087
- signal: _turnAbort.signal,
9301
+ signal: combineReplSignals(_turnAbort.signal, options.signal),
9088
9302
  // On an auto-detected image turn, switch to the vision LLM for this
9089
9303
  // turn only (provider/baseUrl/apiKey unchanged, model → vision model).
9090
9304
  provider: _visionLlm ? _visionLlm.provider : provider,
@@ -9200,12 +9414,13 @@ async function startAgentReplInWorkspaceOwned(
9200
9414
  callProvider: provider,
9201
9415
  callModel: activeModel,
9202
9416
  source: "model",
9203
- call: () =>
9417
+ call: ({ signal }) =>
9204
9418
  chatWithTools([{ role: "user", content: p }], {
9205
9419
  model: activeModel,
9206
9420
  provider,
9207
9421
  baseUrl,
9208
9422
  apiKey,
9423
+ signal,
9209
9424
  enabledToolNames: [],
9210
9425
  }),
9211
9426
  });
@@ -9743,9 +9958,15 @@ async function startAgentReplInWorkspaceOwned(
9743
9958
  }
9744
9959
 
9745
9960
  // Shutdown runtime
9961
+ _detachSessionBudget();
9962
+ try {
9963
+ await closeReplSessionBudgetRootScope(_sessionBudgetRootScope);
9964
+ } catch (error) {
9965
+ _replOutputFailure ||= error;
9966
+ }
9746
9967
  _detachSessionHostLease();
9747
9968
  try {
9748
- _sessionHostLeaseScope?.lease?.release?.();
9969
+ releaseReplSessionHostLeaseScope(_sessionHostLeaseScope);
9749
9970
  } catch (error) {
9750
9971
  _replOutputFailure ||= error;
9751
9972
  }
@@ -109,8 +109,10 @@ import { buildPermissionDecision } from "../lib/permission-decision.js";
109
109
  import { resolveSandboxPolicyPath } from "../lib/agent-sandbox.js";
110
110
  import {
111
111
  beginManagedToolCheckpoint,
112
+ managedToolCheckpointBinding,
112
113
  settleManagedToolCheckpoint,
113
114
  } from "../lib/managed-tool-checkpoint.js";
115
+ import { sessionBudgetAdmissionError } from "../lib/session-budget-production-root.js";
114
116
  import {
115
117
  createMcpCallLedger,
116
118
  McpEffect,
@@ -3570,6 +3572,35 @@ export async function executeTool(name, args, context = {}) {
3570
3572
  }
3571
3573
  }
3572
3574
 
3575
+ let sessionBudgetTool = null;
3576
+ if (typeof context.sessionBudget?.beginTool === "function") {
3577
+ const toolBinding = JSON.stringify({
3578
+ sessionId: context.sessionId || null,
3579
+ turnId: context.turnId || null,
3580
+ toolCallId: context.toolCallId || randomUUID(),
3581
+ tool: name,
3582
+ });
3583
+ const toolBudgetId = `tool:${createHash("sha256")
3584
+ .update(toolBinding, "utf8")
3585
+ .digest("hex")
3586
+ .slice(0, 48)}`;
3587
+ sessionBudgetTool = context.sessionBudget.beginTool({
3588
+ id: toolBudgetId,
3589
+ kind: String(name || "tool").slice(0, 128),
3590
+ });
3591
+ if (!sessionBudgetTool?.ok) {
3592
+ return {
3593
+ error: `Session budget blocked tool execution: ${sessionBudgetTool?.reason || "session-aborted"}`,
3594
+ code: "CC_SESSION_BUDGET_EXHAUSTED",
3595
+ budgetReason: sessionBudgetTool?.reason || "session-aborted",
3596
+ policy: {
3597
+ decision: "blocked",
3598
+ via: "session-budget",
3599
+ },
3600
+ };
3601
+ }
3602
+ }
3603
+
3573
3604
  const startTime = Date.now();
3574
3605
  let toolResult;
3575
3606
  try {
@@ -3598,6 +3629,7 @@ export async function executeTool(name, args, context = {}) {
3598
3629
  strictUsageTelemetry: context.strictUsageTelemetry === true,
3599
3630
  onUsageBoundary: context.onUsageBoundary || null,
3600
3631
  onUsageSettlement: context.onUsageSettlement || null,
3632
+ onProviderReceipt: context.onProviderReceipt || null,
3601
3633
  onToolCallBoundary: context.onToolCallBoundary || null,
3602
3634
  onToolCallSettlement: context.onToolCallSettlement || null,
3603
3635
  backgroundUsageFailureState: context.backgroundUsageFailureState || null,
@@ -3661,6 +3693,8 @@ export async function executeTool(name, args, context = {}) {
3661
3693
  }
3662
3694
  }
3663
3695
  throw err;
3696
+ } finally {
3697
+ sessionBudgetTool?.end?.();
3664
3698
  }
3665
3699
 
3666
3700
  const durationMs = Date.now() - startTime;
@@ -5014,6 +5048,7 @@ async function executeToolInner(
5014
5048
  strictUsageTelemetry = false,
5015
5049
  onUsageBoundary = null,
5016
5050
  onUsageSettlement = null,
5051
+ onProviderReceipt = null,
5017
5052
  onToolCallBoundary = null,
5018
5053
  onToolCallSettlement = null,
5019
5054
  backgroundUsageFailureState = null,
@@ -6763,6 +6798,7 @@ async function executeToolInner(
6763
6798
  strictUsageTelemetry,
6764
6799
  onUsageBoundary,
6765
6800
  onUsageSettlement,
6801
+ onProviderReceipt,
6766
6802
  onToolCallBoundary,
6767
6803
  onToolCallSettlement,
6768
6804
  backgroundUsageFailureState,
@@ -7689,6 +7725,15 @@ async function executeToolInner(
7689
7725
  projectSkillUsage(event),
7690
7726
  )
7691
7727
  : null;
7728
+ const observeSkillReceipt =
7729
+ strictUsageTelemetry === true &&
7730
+ typeof onProviderReceipt === "function"
7731
+ ? (event) =>
7732
+ _notifyStrictProviderReceipt(
7733
+ onProviderReceipt,
7734
+ projectSkillUsage(event),
7735
+ )
7736
+ : null;
7692
7737
  const projectSkillTool = (event) => ({
7693
7738
  ...event,
7694
7739
  attribution: event?.attribution || projectSkillUsage({}).attribution,
@@ -7781,6 +7826,9 @@ async function executeToolInner(
7781
7826
  strictUsageTelemetry: true,
7782
7827
  onUsageBoundary: observeSkillBoundary,
7783
7828
  onUsageSettlement: observeSkillSettlement,
7829
+ ...(observeSkillReceipt
7830
+ ? { onProviderReceipt: observeSkillReceipt }
7831
+ : {}),
7784
7832
  onToolCallBoundary: observeSkillToolBoundary,
7785
7833
  onToolCallSettlement: observeSkillToolSettlement,
7786
7834
  }
@@ -9642,6 +9690,20 @@ async function _executeSpawnSubAgent(args, ctx) {
9642
9690
  }
9643
9691
  }
9644
9692
  : null;
9693
+ const observeSubagentReceipt =
9694
+ ctx.strictUsageTelemetry === true &&
9695
+ typeof ctx.onProviderReceipt === "function"
9696
+ ? (event) => {
9697
+ try {
9698
+ return _notifyStrictProviderReceipt(
9699
+ ctx.onProviderReceipt,
9700
+ projectSubagentUsage(event),
9701
+ );
9702
+ } catch (error) {
9703
+ throw latchBackgroundUsageFailure(error);
9704
+ }
9705
+ }
9706
+ : null;
9645
9707
  const projectSubagentTool = (event) => ({
9646
9708
  ...event,
9647
9709
  attribution:
@@ -9751,6 +9813,9 @@ async function _executeSpawnSubAgent(args, ctx) {
9751
9813
  strictUsageTelemetry: true,
9752
9814
  onUsageBoundary: observeSubagentBoundary,
9753
9815
  onUsageSettlement: observeSubagentSettlement,
9816
+ ...(observeSubagentReceipt
9817
+ ? { onProviderReceipt: observeSubagentReceipt }
9818
+ : {}),
9754
9819
  onToolCallBoundary: observeSubagentToolBoundary,
9755
9820
  onToolCallSettlement: observeSubagentToolSettlement,
9756
9821
  }
@@ -12093,6 +12158,38 @@ function _notifyStrictUsageSettlement(observer, settlement) {
12093
12158
  }
12094
12159
  }
12095
12160
 
12161
+ function _notifyStrictProviderReceipt(observer, receipt) {
12162
+ if (typeof observer !== "function") return;
12163
+ let observation;
12164
+ try {
12165
+ observation = observer(receipt);
12166
+ } catch (error) {
12167
+ throw _runtimeUsageBoundaryFailure(
12168
+ error,
12169
+ "CC_USAGE_RECEIPT_PERSISTENCE_FAILED",
12170
+ "Child provider receipt persistence failed",
12171
+ );
12172
+ }
12173
+ let isThenable = false;
12174
+ try {
12175
+ isThenable = Boolean(observation && typeof observation.then === "function");
12176
+ } catch (error) {
12177
+ throw _runtimeUsageBoundaryFailure(
12178
+ error,
12179
+ "CC_USAGE_RECEIPT_OBSERVER_ASYNC",
12180
+ "Child provider receipt observer must be synchronous",
12181
+ );
12182
+ }
12183
+ if (isThenable) {
12184
+ void Promise.resolve(observation).catch(() => {});
12185
+ throw _runtimeUsageBoundaryFailure(
12186
+ null,
12187
+ "CC_USAGE_RECEIPT_OBSERVER_ASYNC",
12188
+ "Child provider receipt observer must be synchronous",
12189
+ );
12190
+ }
12191
+ }
12192
+
12096
12193
  function _notifyStrictToolObserver(observer, event, phase) {
12097
12194
  const upper = phase.toUpperCase();
12098
12195
  if (typeof observer !== "function") {
@@ -12757,6 +12854,9 @@ export async function* agentLoop(messages, options) {
12757
12854
  ...(typeof options.onUsageSettlement === "function"
12758
12855
  ? { onUsageSettlement: options.onUsageSettlement }
12759
12856
  : {}),
12857
+ ...(typeof options.onProviderReceipt === "function"
12858
+ ? { onProviderReceipt: options.onProviderReceipt }
12859
+ : {}),
12760
12860
  ...(typeof options.onStreamRetry === "function"
12761
12861
  ? { onStreamRetry: options.onStreamRetry }
12762
12862
  : {}),
@@ -12773,6 +12873,7 @@ export async function* agentLoop(messages, options) {
12773
12873
  strictUsageTelemetry: options.strictUsageTelemetry === true,
12774
12874
  onUsageBoundary: options.onUsageBoundary || null,
12775
12875
  onUsageSettlement: options.onUsageSettlement || null,
12876
+ onProviderReceipt: options.onProviderReceipt || null,
12776
12877
  onToolCallBoundary: options.onToolCallBoundary || null,
12777
12878
  onToolCallSettlement: options.onToolCallSettlement || null,
12778
12879
  parentMessages: messages, // pass parent messages for sub-agent auto-condensation
@@ -13013,6 +13114,21 @@ export async function* agentLoop(messages, options) {
13013
13114
  let emptyThinkingReprompted = false;
13014
13115
 
13015
13116
  while (budget.hasRemaining()) {
13117
+ if (typeof toolContext.sessionBudget?.consumeTurn === "function") {
13118
+ const turnBudgetId = `turn:${createHash("sha256")
13119
+ .update(`${runId}:t${budget.consumed + 1}`, "utf8")
13120
+ .digest("hex")
13121
+ .slice(0, 48)}`;
13122
+ const admission = toolContext.sessionBudget.consumeTurn({
13123
+ id: turnBudgetId,
13124
+ });
13125
+ if (!admission?.ok) {
13126
+ throw sessionBudgetAdmissionError(
13127
+ admission?.reason,
13128
+ `turn ${budget.consumed + 1}`,
13129
+ );
13130
+ }
13131
+ }
13016
13132
  budget.consume();
13017
13133
  throwIfAborted(signal);
13018
13134
 
@@ -14205,6 +14321,13 @@ export async function* agentLoop(messages, options) {
14205
14321
  tool_use_id: call.id,
14206
14322
  turn_id: `${runId}:t${budget.consumed}`,
14207
14323
  ...(workflowBinding || {}),
14324
+ ...(managedCheckpointHandle
14325
+ ? {
14326
+ managedCheckpointBinding: managedToolCheckpointBinding(
14327
+ managedCheckpointHandle,
14328
+ ),
14329
+ }
14330
+ : {}),
14208
14331
  };
14209
14332
  // The event yield is a host persistence boundary. A detached child's
14210
14333
  // fatal usage write can settle while the consumer handles it; fence