chainlesschain 0.163.6 → 0.163.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 (234) hide show
  1. package/package.json +2 -1
  2. package/src/assets/web-panel/assets/{AIOps-DDIUofA8.js → AIOps-CavM7W3k.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-Bm-5xYRn.js → ActionButton-CUvZGabQ.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-D5UH4ljI.js → Analytics-DeBnWnbe.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-D_ifjOOP.js → AppLayout-DbI5kxvd.js} +4 -4
  6. package/src/assets/web-panel/assets/{Artifacts-BY1mXdC7.js → Artifacts-D93bigKm.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-Bujr4Ml3.js → Audit-CBNvfUZa.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-sioKSTcC.js → BackgroundAgents-CJLyh_YU.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-DDOAK8RK.js → Backup-D_0yoehD.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-CtCsVVke.js → BaseInput-TJxmbObW.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-DpNj0vnd.js → Chat-CE0dto1q.js} +5 -5
  12. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CZta3Ftr.js → ChatBubbleRenderer-CZ5-yYiD.js} +1 -1
  13. package/src/assets/web-panel/assets/{Checkbox-DoHVNSXq.js → Checkbox-Ck1RVIVo.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-DlVl7Qmv.js → Codegen-qpoyf6DK.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-GIqoPYty.js → Col-DUyPWjIE.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-CIAPEVji.js → Community-D_S1BemS.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-BN7JiI_h.js → Compact-BjxeK-Gc.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-CqUWCM9B.js → Compliance-Dd3CEJsu.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-A4iPp7A4.js → Cowork-B4QG7-ad.js} +3 -3
  20. package/src/assets/web-panel/assets/{Cron-B2zeXXWb.js → Cron-BtZnids5.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-BR2xmWr8.js → Crosschain-CHPfCBFD.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-BzFDjrIv.js → DID-DT8DCEOK.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-DKtDo3yA.js → Dashboard-COQab5_U.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-RNx43_YG.js → Dropdown-BY1PsQuU.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-SwMt4Rcy.js → EmailListRenderer-CsuAuaq3.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-CsYebZ4X.js → FamilyGuardDashboard-BqpinD-j.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-BmRKvBTy.js → Federation-D0gkfQFv.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-CVxGTA-0.js → FormItemContext-BqgE-axK.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-x2iXpyB7.js → GenericCardRenderer-D0hJ2KvC.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-DfqbkiOP.js → Git-CmMB0uPY.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-RuHyyj5O.js → Governance-BnVEI0Dk.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-Bn7uZ7rI.js → Inference-YTAMihRP.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-DlP7XefZ.js → KnowledgeGraph-0ax7VHop.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-BYNdOiCd.js → Logs-B9TRcokL.js} +2 -2
  35. package/src/assets/web-panel/assets/MarkdownRenderer-yySN5YNM.js +1 -0
  36. package/src/assets/web-panel/assets/{Marketplace-JQYmDqM8.js → Marketplace-B6CSuD_H.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-Cyx4yZ-9.js → McpTools-CjMXvOVU.js} +4 -4
  38. package/src/assets/web-panel/assets/{Memory-VDuGZTN2.js → Memory-CXRF71U3.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-_yKo97gi.js → MobileBridge-DQgNp_oS.js} +1 -1
  40. package/src/assets/web-panel/assets/{MobileProjects-CXRXW3q7.js → MobileProjects-DlPwcCbq.js} +1 -1
  41. package/src/assets/web-panel/assets/{Mtc-acTGtfLH.js → Mtc-6hDTRPe1.js} +5 -5
  42. package/src/assets/web-panel/assets/{MtcAudit-ClpjXfkY.js → MtcAudit-BlVHU1DS.js} +4 -4
  43. package/src/assets/web-panel/assets/{Multisig-_6Tn3o96.js → Multisig-DP9pzEbV.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-CK7pbZzP.js → NLProgramming-Djorh8EV.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-Czy6V_P8.js → Notes-oLZ-JkUg.js} +4 -4
  46. package/src/assets/web-panel/assets/{NotificationSettings-Cqx-UVv3.js → NotificationSettings-Cg288VH3.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-C69WDxGy.js → OrderTableRenderer-Bb1O3Ofr.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-DFnA9vLQ.js → Organization-CBdo-bHs.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-ReZkk2yT.js → Overflow-qZdnVumx.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-DzjSI0aI.js → P2P-D4kNfGNQ.js} +2 -2
  51. package/src/assets/web-panel/assets/PdhVaultBrowser-DnlMemM7.js +7 -0
  52. package/src/assets/web-panel/assets/{Permissions-DhQ5klhR.js → Permissions-DHucHFBJ.js} +3 -3
  53. package/src/assets/web-panel/assets/{PersonalDataHub-CUL1iHrW.js → PersonalDataHub-BovlOIPR.js} +4 -4
  54. package/src/assets/web-panel/assets/{Pipeline-DU88iu4N.js → Pipeline-Deru3CQY.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-Bw-sYfyK.js → Privacy-Bq5oTTbU.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-Bq3Q5y0z.js → ProjectInit-BfzxVWAz.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-C8spzpho.js → ProjectSettings-CKC6XBtH.js} +2 -2
  58. package/src/assets/web-panel/assets/Projects-CMolGhae.js +1 -0
  59. package/src/assets/web-panel/assets/{Providers-Bf4eTP9W.js → Providers-C_jx4TWX.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-Dme9BDU1.js → QrScannerModal-BdIHeVGC.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-CIXfv1rE.js → QuickAsk-BwZwAcPD.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-CIxvdeZ-.js → Recommend-BNTt0L-m.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-C6k7MExI.js → RemoteSession-Biyn2-Ro.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-CISDz2bl.js → Reputation-D6VpG32B.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-CdnDxXyf.js → Row-D_74OvQQ.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-C-QpRHsl.js → RssFeed-BTr0a-BQ.js} +3 -3
  67. package/src/assets/web-panel/assets/{Search-DBjaGzSn.js → Search-C3MCFoNU.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-CQKukOeE.js → Security-CqW9aJ6s.js} +3 -3
  69. package/src/assets/web-panel/assets/{Services-DZz86jWb.js → Services-Cw5GNaHF.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-jb8RMK0d.js → Skeleton-DZps5qeY.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-CdY76fZG.js → Skills-C6NQ1znT.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-C_CSiZX9.js → Sla-DFP8G2Sh.js} +1 -1
  73. package/src/assets/web-panel/assets/SpeechSettings-ESt6MB6v.js +1 -0
  74. package/src/assets/web-panel/assets/{SyncSettings-qvimGO0O.js → SyncSettings-BHnN98aM.js} +2 -2
  75. package/src/assets/web-panel/assets/{Tasks-Dng5LPJC.js → Tasks-NiSCaOf-.js} +1 -1
  76. package/src/assets/web-panel/assets/{Templates-Bwqq5Wll.js → Templates-DsKFhW2C.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-DNWuwP7Z.js → Tenant-CQ0E0ze5.js} +1 -1
  78. package/src/assets/web-panel/assets/{Terminal-B-6Othpp.js → Terminal-D_rBu_by.js} +2 -2
  79. package/src/assets/web-panel/assets/{TimelineRenderer-DKpKZfzx.js → TimelineRenderer-D3Vm4Po4.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-DzfGMd2J.js → Tokens-DNTxRH6q.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-BXwUi74J.js → Trigger-Dgprz1ms.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-BNzUq4ui.js → Trust-B2rUnVBD.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-BYugxww4.js → UkeySign-DEGQNc6_.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-DdauhtSJ.js → VideoEditing-jlsAx3Eh.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-CSC9bCe_.js → Wallet-8jQih1ij.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-Q8AN3bTO.js → WebAuthn-XLeO6xIB.js} +5 -5
  87. package/src/assets/web-panel/assets/{WorkflowEditor-d-LBGCuA.js → WorkflowEditor-De_dgDAG.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-BLVDCgsZ.js → chat-CI19R_Sk.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-BZlPSEHl.js → colors-DsYTOYN3.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-IWseP6R6.js → compact-item-CM3-t_Qr.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-DnVRV3Ao.js → createContext-BjxlBRZv.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-S1ld2LwU.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-DLQZA_Wn.js → hasIn-RDaWX_4i.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-BSjilZ9L.js → index-9R6BxAr0.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-B_N4-Gq9.js → index-B-Z8eFUJ.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-Dy0R5ZED.js → index-B0PMlbMs.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-C1ifZtXo.js → index-B5REnKt8.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CINJQEj6.js → index-B7WBt_4T.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-DocEhinm.js → index-B9O9YyWE.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-DjWnONdy.js → index-BCnZyIMA.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-hwVDeoC0.js → index-BGqqJfL0.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-Bbj2NS_I.js → index-BHNYPO0b.js} +3 -3
  103. package/src/assets/web-panel/assets/{index-C5dgnilC.js → index-BKJr-TZp.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-CT9vVN-X.js → index-BN6UPD2E.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DpVrK6fr.js → index-Bi46Xu4u.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-CpBaJ3TD.js → index-BlT2VAEK.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-1jeAudHd.js → index-C0yx-jtQ.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DOoQpuQY.js → index-C4gkzxkw.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DZpYeqrh.js → index-CVQMeiwH.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-BhA3QEni.js → index-Cd3euP_4.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-N_GoWZX4.js → index-Cd9OJhHG.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-BOZJBTWZ.js → index-CiECJi-Q.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-CarMTIyQ.js → index-CjTrRt13.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-CZDekj7T.js → index-CnHH7bnD.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-M7wxfAbm.js → index-Cpqm1qfU.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-Bxp7uDD8.js → index-CyOGN6a5.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DalA0TKC.js → index-D0zcy54x.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-COev0W2g.js → index-D6sm5-Xq.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DUq0c7gq.js → index-DIUnNOjG.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BZs5bBnk.js → index-DX7tuWVJ.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CbQNL0ue.js → index-DXXtGMUJ.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-DTbxp4UH.js → index-DcPFB8qJ.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-YSw_gxlZ.js → index-DoQA0-52.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-D_LQodeJ.js → index-Drlnwr8F.js} +1 -1
  125. package/src/assets/web-panel/assets/index-Drz6yq0m.js +1 -0
  126. package/src/assets/web-panel/assets/{index-jWb70ZgZ.js → index-Dsij_KsN.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-DB0MJgF_.js → index-Dxge-xWl.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-BEu2lMBy.js → index-DyIWssPC.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-C2FqfMvU.js → index-IeiL9RKc.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Dkwsi1Kn.js → index-nAH87mQP.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-gt8bNefW.js → index-pPL66J85.js} +1 -1
  132. package/src/assets/web-panel/assets/index-uWiUs7S_.js +1 -0
  133. package/src/assets/web-panel/assets/{initDefaultProps-Co67Kqmb.js → initDefaultProps-BTL88of4.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-BMOxQSF_.js → motion-BUB2pXwB.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-C5fWDw-N.js → move-egCkkOMm.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-BJevpL0e.js → mtc-parser-DAWhZC8c.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-BCzNU8s6.js → omit-CvOxe_6d.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-CybWvDPk.js → pickAttrs-DZUSLZ5Z.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-BMWS9HnW.js → placementArrow-BERxGNMY.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-BoL2UnGY.js → responsiveObserve-DZuDfZ9n.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-DWNfXraU.js → slide-DO756sgI.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-BquTM3tX.js → statusUtils-BRQlIz28.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-BEkCleim.js → styleChecker-DCSfdybl.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-Oecnq7EA.js → useFlexGapSupport-LD8dWVve.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-CkDffJ4F.js → useFs-BX9uW2LK.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-qbvKXesB.js → usePersonalDataHub-BPSlPuHU.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-C6v8n6mA.js → vnode-BmOILC9V.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-4CTeFILV.js → zoom-1iKowKGg.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/command-help-index.json +5 -5
  151. package/src/commands/agent.js +90 -1
  152. package/src/commands/automation.js +103 -1
  153. package/src/commands/chat.js +11 -2
  154. package/src/commands/compact.js +106 -23
  155. package/src/commands/loop.js +28 -10
  156. package/src/commands/routine.js +1 -1
  157. package/src/commands/scheduler-daemon.js +359 -2
  158. package/src/commands/session-observability.js +305 -0
  159. package/src/commands/session.js +38 -0
  160. package/src/commands/team-merge-review.js +937 -0
  161. package/src/commands/team.js +2 -0
  162. package/src/data/changelog.json +27 -1
  163. package/src/gateways/ws/ws-agent-handler.js +439 -5
  164. package/src/harness/jsonl-session-store.js +463 -125
  165. package/src/harness/prompt-compressor.js +86 -13
  166. package/src/harness/provider-backed-compaction.js +100 -27
  167. package/src/lib/advisor-runtime.js +3 -1
  168. package/src/lib/agent-schedule-store.js +549 -28
  169. package/src/lib/agent-team/team-adjudication.js +40 -1
  170. package/src/lib/agent-team/team-merge-review-store.js +765 -0
  171. package/src/lib/agent-team/team-merge-review-transaction.js +1223 -0
  172. package/src/lib/agent-team/team-merge-review.js +1847 -0
  173. package/src/lib/automation-center-incidents.js +314 -0
  174. package/src/lib/automation-center-runtime.js +448 -0
  175. package/src/lib/automation-center.js +182 -38
  176. package/src/lib/automation-engine.js +535 -0
  177. package/src/lib/automation-execution-authority.js +241 -12
  178. package/src/lib/automation-execution-incident.js +737 -0
  179. package/src/lib/background-agent-supervisor.js +793 -215
  180. package/src/lib/background-command-argv.js +24 -0
  181. package/src/lib/background-interaction-journal.js +361 -52
  182. package/src/lib/background-interaction-resolver.js +32 -0
  183. package/src/lib/background-launch-profile.js +2 -0
  184. package/src/lib/causal-observability.js +2661 -0
  185. package/src/lib/chat-session-admission.js +76 -0
  186. package/src/lib/cost-budget.js +5 -7
  187. package/src/lib/cowork/ab-comparator-cli.js +11 -0
  188. package/src/lib/cowork/debate-review-cli.js +12 -0
  189. package/src/lib/cowork-adapter.js +159 -38
  190. package/src/lib/cowork-cron.js +442 -15
  191. package/src/lib/cowork-task-runner.js +112 -17
  192. package/src/lib/delivery-coordinator.js +142 -0
  193. package/src/lib/direct-model-usage.js +121 -0
  194. package/src/lib/file-lines.js +183 -47
  195. package/src/lib/llm-pricing.js +12 -17
  196. package/src/lib/loop.js +26 -2
  197. package/src/lib/routine-store.js +380 -21
  198. package/src/lib/runtime-usage-ledger.js +182 -0
  199. package/src/lib/scheduler-kernel/agenda-adapter.js +325 -10
  200. package/src/lib/scheduler-kernel/automation-adapter.js +514 -18
  201. package/src/lib/scheduler-kernel/automation-event-adapter.js +123 -11
  202. package/src/lib/scheduler-kernel/contract.js +91 -0
  203. package/src/lib/scheduler-kernel/cowork-cron-adapter.js +297 -4
  204. package/src/lib/scheduler-kernel/loop-adapter.js +547 -6
  205. package/src/lib/scheduler-kernel/migration-admin.js +346 -0
  206. package/src/lib/scheduler-kernel/migration-rollback-admin.js +932 -0
  207. package/src/lib/scheduler-kernel/routine-adapter.js +400 -20
  208. package/src/lib/scheduler-kernel/runtime-control-capabilities.js +31 -0
  209. package/src/lib/scheduler-kernel/runtime.js +237 -2
  210. package/src/lib/scheduler-kernel/source-locator-path.js +142 -0
  211. package/src/lib/scheduler-kernel/store.js +3957 -248
  212. package/src/lib/session-host-lease.js +171 -2
  213. package/src/lib/session-host-snapshot.js +14 -3
  214. package/src/lib/session-persistence-failure.js +1 -0
  215. package/src/lib/session-tail.js +179 -34
  216. package/src/lib/session-transcript-structure.js +96 -0
  217. package/src/lib/sub-agent-context.js +328 -22
  218. package/src/lib/ws-agent-handler.js +4 -1
  219. package/src/repl/agent-repl.js +732 -91
  220. package/src/repl/chat-repl.js +5 -1
  221. package/src/runtime/agent-core.js +1282 -207
  222. package/src/runtime/fallback-model.js +5 -0
  223. package/src/runtime/headless-runner.js +324 -82
  224. package/src/runtime/headless-stream.js +232 -26
  225. package/src/runtime/mcp-config.js +81 -10
  226. package/src/runtime/policies/agent-policy.js +4 -0
  227. package/src/workers/background-agent-worker.js +403 -96
  228. package/src/assets/web-panel/assets/MarkdownRenderer-aMtgN-R6.js +0 -1
  229. package/src/assets/web-panel/assets/PdhVaultBrowser-DKTf5xIP.js +0 -7
  230. package/src/assets/web-panel/assets/Projects-Dd-xuPIc.js +0 -1
  231. package/src/assets/web-panel/assets/SpeechSettings-C7tT9iad.js +0 -1
  232. package/src/assets/web-panel/assets/devWarning-Jzu62CLC.js +0 -1
  233. package/src/assets/web-panel/assets/index-Zb2MeDSy.js +0 -1
  234. package/src/assets/web-panel/assets/index-fikqml4k.js +0 -1
@@ -263,6 +263,11 @@ export function makeFallbackChatFn(opts = {}) {
263
263
  try {
264
264
  return await baseChatFn(messages, options);
265
265
  } catch (firstErr) {
266
+ // A strict call-ledger boundary identifies exactly one provider/model
267
+ // transport. Retrying behind that boundary would either attribute the
268
+ // fallback's usage to the primary identity or lose the failed attempt's
269
+ // possible spend, so surface the primary error without another call.
270
+ if (options.strictUsageTelemetry === true) throw firstErr;
266
271
  let err = firstErr;
267
272
  let lastTried = options.model;
268
273
  for (const candidate of models) {
@@ -74,7 +74,10 @@ import {
74
74
  } from "../lib/mcp-call-ledger-store.js";
75
75
  import { createMcpHostRecoveryRuntime } from "../lib/mcp-host-recovery-runtime.js";
76
76
  import { readSessionHostResumeState } from "../lib/session-host-snapshot.js";
77
- import { acquireSessionHostLease } from "../lib/session-host-lease.js";
77
+ import {
78
+ acquireSessionHostLease,
79
+ createSessionHostWriteDelegation,
80
+ } from "../lib/session-host-lease.js";
78
81
  import { TurnBindingLog, createTurnBindingFeed } from "../lib/turn-binding.js";
79
82
  import { TURN_BINDING_EVENT } from "../lib/turn-binding-store.js";
80
83
  import { operationIdempotencyKey } from "../lib/idempotency.js";
@@ -122,6 +125,13 @@ export const _goalProcessDeps = {
122
125
  run: goalBrokerRunner,
123
126
  };
124
127
 
128
+ export const RUNTIME_LEDGER_PERSISTENCE_FAILURE_MESSAGE =
129
+ "CC_RUNTIME_USAGE_LEDGER_FAILED: runtime usage telemetry was not durably persisted";
130
+
131
+ export function resolveHeadlessMeteredSessionId(persist, sessionId) {
132
+ return persist && sessionId ? sessionId : null;
133
+ }
134
+
125
135
  function runHeadlessGoalCommand(command, options = {}) {
126
136
  return _goalProcessDeps.run(command, [], {
127
137
  ...options,
@@ -172,6 +182,14 @@ import {
172
182
  createSessionPersistenceFailure,
173
183
  projectSessionPersistenceFailure,
174
184
  } from "../lib/session-persistence-failure.js";
185
+ import {
186
+ markRuntimeLedgerPersistenceError,
187
+ projectRuntimeTokenUsage,
188
+ projectRuntimeUsageBoundary,
189
+ runtimeUsageEventType,
190
+ runtimeToolCallId,
191
+ } from "../lib/runtime-usage-ledger.js";
192
+ import { runMeteredDirectModelCall } from "../lib/direct-model-usage.js";
175
193
 
176
194
  /**
177
195
  * Normalize a public --permission-mode spelling to the canonical internal mode.
@@ -289,14 +307,20 @@ export function parseToolList(value) {
289
307
  * still REPLAYS prior history into context, but nothing new is written — the
290
308
  * deterministic-CI shape ("read context, leave no trace").
291
309
  *
292
- * @param {object} options { resume, continueSession, sessionId, persistSession, ephemeral }
310
+ * @param {object} options { resume, continueSession, sessionId, persistSession, ephemeral, observabilityScope }
293
311
  * @param {object} store { getLastSessionId } (injection seam)
294
312
  * @param {string} fallbackId used when nothing is being resumed
295
313
  * @returns {{ sessionId:string, resumeId:string|null, persist:boolean, wantLatest:boolean }}
296
314
  */
297
315
  export function resolveHeadlessSession(options = {}, store = {}, fallbackId) {
298
- const { resume, continueSession, sessionId, persistSession, ephemeral } =
299
- options;
316
+ const {
317
+ resume,
318
+ continueSession,
319
+ sessionId,
320
+ persistSession,
321
+ ephemeral,
322
+ observabilityScope,
323
+ } = options;
300
324
  const wantLatest = continueSession === true || resume === true;
301
325
  let resumeId = null;
302
326
  if (wantLatest) {
@@ -323,7 +347,10 @@ export function resolveHeadlessSession(options = {}, store = {}, fallbackId) {
323
347
  const persist =
324
348
  ephemeral === true
325
349
  ? false
326
- : persistSession === true || resumeId != null || wantLatest;
350
+ : persistSession === true ||
351
+ resumeId != null ||
352
+ wantLatest ||
353
+ observabilityScope != null;
327
354
  const id = resumeId || sessionId || fallbackId;
328
355
  return { sessionId: id, resumeId, persist, wantLatest };
329
356
  }
@@ -403,6 +430,11 @@ async function withHeadlessSessionHostLease(options, deps, task) {
403
430
  "runAgentHeadless requires a non-empty prompt (use -p, a positional arg, or pipe stdin).",
404
431
  );
405
432
  }
433
+ if (options.observabilityScope != null && options.ephemeral === true) {
434
+ throw new Error(
435
+ "observability scope requires durable session persistence and cannot be combined with ephemeral mode",
436
+ );
437
+ }
406
438
  const outputFormat = options.outputFormat || "text";
407
439
  if (!VALID_OUTPUT_FORMATS.includes(outputFormat)) {
408
440
  throw new Error(
@@ -657,6 +689,19 @@ async function runAgentHeadlessInWorkspace(
657
689
  // but it does not opt into replaying the target's prior conversation.
658
690
  const canonicalResume = resumeId ? canonicalAdmission : null;
659
691
 
692
+ if (options.observabilityScope != null && canonicalAdmission) {
693
+ const message =
694
+ "CC_OBSERVABILITY_SCOPE_IMMUTABLE: an existing session scope cannot be overwritten; create a new scoped session";
695
+ emitHeadlessError(message);
696
+ writeErr(`${message}\n`);
697
+ return {
698
+ exitCode: 1,
699
+ result: message,
700
+ isError: true,
701
+ sessionSnapshot: canonicalAdmission.snapshot,
702
+ };
703
+ }
704
+
660
705
  // `let` (not const): a custom-command macro's `model:` frontmatter may
661
706
  // override it below (when the user passed no explicit --model), mirroring
662
707
  // `cc command run`.
@@ -898,6 +943,23 @@ async function runAgentHeadlessInWorkspace(
898
943
  deps.verifySession ||
899
944
  (hasInjectedSessionStore ? () => null : jsonlVerifySession),
900
945
  };
946
+ if (options.observabilityScope != null) {
947
+ let existingSession;
948
+ try {
949
+ existingSession = store.sessionExists(sessionId);
950
+ } catch {
951
+ existingSession = null;
952
+ }
953
+ if (existingSession !== false) {
954
+ const message =
955
+ existingSession === true
956
+ ? "CC_OBSERVABILITY_SCOPE_IMMUTABLE: an existing session scope cannot be overwritten; create a new scoped session"
957
+ : "CC_OBSERVABILITY_SCOPE_AUTHORITY_UNAVAILABLE: existing session authority could not be excluded";
958
+ emitHeadlessError(message);
959
+ writeErr(`${message}\n`);
960
+ return { exitCode: 1, result: message, isError: true };
961
+ }
962
+ }
901
963
  // ── Headless `/config` directive (Claude-Code 2.1.181: /config in -p mode) ──
902
964
  // A leading `/config …` prompt is a one-shot config get/set/show, not a task
903
965
  // for the LLM — handled before bootstrap/session/model so it never spends a
@@ -1163,9 +1225,15 @@ async function runAgentHeadlessInWorkspace(
1163
1225
  : null;
1164
1226
  const _backgroundInteraction = _bgPhase.enabled
1165
1227
  ? deps.backgroundInteractionClient ||
1166
- createBackgroundInteractionClient({
1228
+ (
1229
+ deps.createBackgroundInteractionClient ||
1230
+ createBackgroundInteractionClient
1231
+ )({
1167
1232
  backgroundAgentId: process.env.CC_BACKGROUND_AGENT_ID,
1168
1233
  sessionId,
1234
+ sessionHostWriteDelegation: sessionHostLease?.leaseId
1235
+ ? createSessionHostWriteDelegation(sessionHostLease)
1236
+ : null,
1169
1237
  // One headless invocation is one user turn even when its model/tool
1170
1238
  // loop contains several internal iterations.
1171
1239
  turnId: options.turnId || sideEffectRunNonce,
@@ -1650,6 +1718,7 @@ async function runAgentHeadlessInWorkspace(
1650
1718
  title: prompt.slice(0, 60),
1651
1719
  provider,
1652
1720
  model,
1721
+ observabilityScope: options.observabilityScope,
1653
1722
  });
1654
1723
  }
1655
1724
  // Persist the expanded content so a resumed session faithfully replays
@@ -2045,6 +2114,18 @@ async function runAgentHeadlessInWorkspace(
2045
2114
  };
2046
2115
  persistContextSources();
2047
2116
 
2117
+ // Scoped call-ledger writes are safety boundaries, not best-effort
2118
+ // diagnostics. Normalize every persistence failure so the outer host aborts
2119
+ // this turn and cannot begin another paid model/tool call.
2120
+ const persistRuntimeLedgerWrite = (action) => {
2121
+ try {
2122
+ return action();
2123
+ } catch (error) {
2124
+ throw markRuntimeLedgerPersistenceError(error);
2125
+ }
2126
+ };
2127
+
2128
+ const childToolExecs = new Map();
2048
2129
  const loopOptions = {
2049
2130
  model,
2050
2131
  provider,
@@ -2164,19 +2245,85 @@ async function runAgentHeadlessInWorkspace(
2164
2245
  onStreamRetry: (attempt, error, telemetry = {}) => {
2165
2246
  writeErr(` ⟳ connection dropped — retrying (attempt ${attempt})…\n`);
2166
2247
  if (persist) {
2167
- try {
2248
+ persistRuntimeLedgerWrite(() =>
2168
2249
  store.appendLlmRetryCompact(sessionId, {
2169
2250
  attempt,
2170
2251
  durationMs: telemetry.durationMs,
2171
2252
  provider: telemetry.provider || provider,
2172
2253
  model: telemetry.model || model,
2173
2254
  reason: classifyStreamRetryReason(error),
2174
- });
2175
- } catch {
2176
- /* usage telemetry is best-effort */
2177
- }
2255
+ }),
2256
+ );
2178
2257
  }
2179
2258
  },
2259
+ onUsageBoundary: persist
2260
+ ? (event) => {
2261
+ persistRuntimeLedgerWrite(() =>
2262
+ store.appendEvent(
2263
+ sessionId,
2264
+ runtimeUsageEventType("started"),
2265
+ projectRuntimeUsageBoundary(event, "started"),
2266
+ ),
2267
+ );
2268
+ }
2269
+ : undefined,
2270
+ onUsageSettlement: persist
2271
+ ? (event) => {
2272
+ if (event?.type === "token-usage") {
2273
+ persistRuntimeLedgerWrite(() =>
2274
+ store.appendTokenUsage(
2275
+ sessionId,
2276
+ projectRuntimeTokenUsage(event),
2277
+ ),
2278
+ );
2279
+ return;
2280
+ }
2281
+ persistRuntimeLedgerWrite(() =>
2282
+ store.appendEvent(
2283
+ sessionId,
2284
+ runtimeUsageEventType("unknown"),
2285
+ projectRuntimeUsageBoundary(event, "unknown"),
2286
+ ),
2287
+ );
2288
+ }
2289
+ : undefined,
2290
+ onToolCallBoundary: persist
2291
+ ? (event) => {
2292
+ const id = runtimeToolCallId(event?.tool_use_id);
2293
+ childToolExecs.set(id, {
2294
+ tool: event?.tool || "?",
2295
+ startedAt: deps.now ? deps.now() : Date.now(),
2296
+ });
2297
+ persistRuntimeLedgerWrite(() =>
2298
+ store.appendEvent(sessionId, "tool_call_started", {
2299
+ id,
2300
+ tool: event?.tool || "?",
2301
+ }),
2302
+ );
2303
+ }
2304
+ : undefined,
2305
+ onToolCallSettlement: persist
2306
+ ? (event) => {
2307
+ const id = runtimeToolCallId(event?.tool_use_id);
2308
+ const started = childToolExecs.get(id);
2309
+ childToolExecs.delete(id);
2310
+ persistRuntimeLedgerWrite(() =>
2311
+ store.appendToolCallCompact(sessionId, {
2312
+ id,
2313
+ tool: event?.tool || started?.tool || "?",
2314
+ isError: Boolean(event?.error || event?.result?.error),
2315
+ skill: event?.attribution?.skill,
2316
+ durationMs: started
2317
+ ? Math.max(
2318
+ 0,
2319
+ (deps.now ? deps.now() : Date.now()) - started.startedAt,
2320
+ )
2321
+ : undefined,
2322
+ }),
2323
+ );
2324
+ }
2325
+ : undefined,
2326
+ strictUsageTelemetry: persist,
2180
2327
  onStall: (ms, timeoutMs) => {
2181
2328
  const silent = Math.round(ms / 1000);
2182
2329
  const retryIn = timeoutMs > ms ? Math.round((timeoutMs - ms) / 1000) : 0;
@@ -2249,9 +2396,10 @@ async function runAgentHeadlessInWorkspace(
2249
2396
  const toolCalls = [];
2250
2397
  // The core normally attaches a precise toolTelemetryRecord on success.
2251
2398
  // Keep an event-boundary fallback for denials/early throws that settle
2252
- // before that record is produced. Tools are serial in this loop, so one
2253
- // timestamp is sufficient and never leaks into the result envelope.
2254
- let currentToolStartedAt = null;
2399
+ // before that record is produced. Read-only batches can run concurrently,
2400
+ // so timestamps and result pairing are keyed by provider tool-call id.
2401
+ const activeToolCalls = new Map();
2402
+ const toolStartedAt = new Map();
2255
2403
  // Policy denials (blocked tool calls) collected for an end-of-run summary,
2256
2404
  // so a non-interactive run surfaces what got blocked the way the REPL's
2257
2405
  // `/permissions denials` does (Claude-Code 2.1.193 denial reasons).
@@ -2263,15 +2411,10 @@ async function runAgentHeadlessInWorkspace(
2263
2411
  cache_read_input_tokens: 0,
2264
2412
  cache_creation_input_tokens: 0,
2265
2413
  };
2266
- // 用量归因: attributed child-loop usage (spawn_sub_agent / isolated
2267
- // run_skill). Kept OUT of the `usage` accumulator above so the result
2268
- // envelope and the end-of-run aggregate token_usage event keep their
2269
- // long-standing "main loop only" semantics — the attributed records are
2270
- // persisted as their own token_usage events instead (no double count).
2271
- const attributedUsage = [];
2272
2414
  let finalText = "";
2273
2415
  let endReason = "complete";
2274
2416
  let stopForCost = false;
2417
+ let stopForCompactionUsageUnknown = false;
2275
2418
 
2276
2419
  const emitStream = (obj) => {
2277
2420
  if (isStream) writeOut(JSON.stringify(obj) + "\n");
@@ -2388,12 +2531,22 @@ async function runAgentHeadlessInWorkspace(
2388
2531
  `Condition: ${cond.text || cond.source}\n\n` +
2389
2532
  `Latest assistant output:\n${String(transcript.finalText || "").slice(0, 2000)}\n\n` +
2390
2533
  `Reply with STRICT JSON only: {"met": true|false, "reason": "<short>"}.`;
2391
- const r = await chatWithTools([{ role: "user", content: judgePrompt }], {
2392
- model,
2534
+ const r = await runMeteredDirectModelCall({
2535
+ sessionId: resolveHeadlessMeteredSessionId(persist, sessionId),
2536
+ persist: persist
2537
+ ? (type, data) => store.appendEvent(sessionId, type, data)
2538
+ : null,
2393
2539
  provider,
2394
- baseUrl,
2395
- apiKey,
2396
- enabledToolNames: [],
2540
+ model,
2541
+ source: "model",
2542
+ call: () =>
2543
+ chatWithTools([{ role: "user", content: judgePrompt }], {
2544
+ model,
2545
+ provider,
2546
+ baseUrl,
2547
+ apiKey,
2548
+ enabledToolNames: [],
2549
+ }),
2397
2550
  });
2398
2551
  const text = r?.message?.content || "";
2399
2552
  let met = false;
@@ -2557,7 +2710,7 @@ async function runAgentHeadlessInWorkspace(
2557
2710
  break;
2558
2711
  }
2559
2712
  case "tool-executing": {
2560
- currentToolStartedAt = deps.now ? deps.now() : Date.now();
2713
+ const telemetryToolId = runtimeToolCallId(event.tool_use_id);
2561
2714
  const line = ` [${event.tool}] ${formatToolArgs(event.tool, event.args)}`;
2562
2715
  if (isText) writeErr(line + "\n");
2563
2716
  emitStream({
@@ -2566,11 +2719,27 @@ async function runAgentHeadlessInWorkspace(
2566
2719
  tool: event.tool,
2567
2720
  args: event.args,
2568
2721
  });
2569
- toolCalls.push({
2570
- ...(event.tool_use_id ? { id: event.tool_use_id } : {}),
2722
+ const toolCall = {
2723
+ id: telemetryToolId,
2571
2724
  tool: event.tool,
2572
2725
  args: event.args,
2573
- });
2726
+ };
2727
+ toolCalls.push(toolCall);
2728
+ toolStartedAt.set(
2729
+ telemetryToolId,
2730
+ deps.now ? deps.now() : Date.now(),
2731
+ );
2732
+ if (event.tool_use_id) {
2733
+ activeToolCalls.set(event.tool_use_id, toolCall);
2734
+ }
2735
+ if (persist) {
2736
+ persistRuntimeLedgerWrite(() =>
2737
+ store.appendEvent(sessionId, "tool_call_started", {
2738
+ id: telemetryToolId,
2739
+ tool: event.tool,
2740
+ }),
2741
+ );
2742
+ }
2574
2743
  // P0-2: record an irreversible effect as STARTED (persisted before
2575
2744
  // it settles) so a crash before the matching tool-result leaves a
2576
2745
  // reconcilable "in flight" marker instead of a silent replay.
@@ -2647,35 +2816,66 @@ async function runAgentHeadlessInWorkspace(
2647
2816
  ? { permission_decision: event.permission_decision }
2648
2817
  : {}),
2649
2818
  });
2650
- if (toolCalls.length > 0) {
2651
- const settledCall = toolCalls[toolCalls.length - 1];
2819
+ const settledCall =
2820
+ (event.tool_use_id
2821
+ ? activeToolCalls.get(event.tool_use_id)
2822
+ : null) ||
2823
+ [...toolCalls]
2824
+ .reverse()
2825
+ .find(
2826
+ (call) =>
2827
+ !call._runtimeSettled &&
2828
+ (!event.tool || call.tool === event.tool),
2829
+ ) ||
2830
+ null;
2831
+ if (settledCall) {
2652
2832
  settledCall.is_error = Boolean(err);
2653
2833
  settledCall.durationMs =
2654
2834
  event.result?.toolTelemetryRecord?.durationMs ??
2655
- (currentToolStartedAt === null
2835
+ (toolStartedAt.get(settledCall.id) === undefined
2656
2836
  ? undefined
2657
2837
  : Math.max(
2658
2838
  0,
2659
2839
  (deps.now ? deps.now() : Date.now()) -
2660
- currentToolStartedAt,
2840
+ toolStartedAt.get(settledCall.id),
2661
2841
  ));
2662
2842
  Object.assign(
2663
2843
  settledCall,
2664
2844
  extractPluginUsageAttribution(event.result),
2665
2845
  );
2846
+ Object.defineProperty(settledCall, "_runtimeSettled", {
2847
+ configurable: true,
2848
+ value: true,
2849
+ });
2850
+ toolStartedAt.delete(settledCall.id);
2851
+ if (event.tool_use_id) activeToolCalls.delete(event.tool_use_id);
2852
+ }
2853
+ if (persist && settledCall) {
2854
+ persistRuntimeLedgerWrite(() =>
2855
+ store.appendToolCallCompact(sessionId, {
2856
+ id: settledCall.id || `tool-${toolCalls.length}`,
2857
+ tool: settledCall.tool,
2858
+ isError: Boolean(settledCall.is_error),
2859
+ skill:
2860
+ settledCall.tool === "run_skill"
2861
+ ? settledCall.args?.skill_name || null
2862
+ : undefined,
2863
+ plugin: settledCall.plugin || undefined,
2864
+ pluginVersion: settledCall.pluginVersion || undefined,
2865
+ durationMs: settledCall.durationMs,
2866
+ }),
2867
+ );
2666
2868
  }
2667
- currentToolStartedAt = null;
2668
2869
  // Track policy denials (not plain tool failures) for the end-of-run
2669
2870
  // summary. The preceding tool-executing pushed the args.
2670
2871
  if (err) {
2671
- const last = toolCalls[toolCalls.length - 1];
2672
2872
  const denial = classifyDenial({
2673
2873
  tool: event.tool,
2674
2874
  result: event.result,
2675
2875
  error: event.error,
2676
2876
  argsSummary:
2677
- last && last.tool === event.tool
2678
- ? formatToolArgs(event.tool, last.args)
2877
+ settledCall && settledCall.tool === event.tool
2878
+ ? formatToolArgs(event.tool, settledCall.args)
2679
2879
  : "",
2680
2880
  });
2681
2881
  if (denial) {
@@ -2704,19 +2904,51 @@ async function runAgentHeadlessInWorkspace(
2704
2904
  emitStream({ ...event, reason });
2705
2905
  break;
2706
2906
  }
2707
- case "token-usage": {
2708
- if (event.attribution) {
2709
- // Child-loop (sub-agent / isolated-skill) spend: excluded from
2710
- // the main `usage` envelope, persisted with its attribution
2711
- // frame below, but still counted toward the cost budget — it
2712
- // is real money on the same key.
2713
- attributedUsage.push({
2714
- provider: event.provider ?? null,
2715
- model: event.model ?? null,
2716
- usage: event.usage || null,
2717
- attribution: event.attribution,
2907
+ case "model-usage-started": {
2908
+ if (persist && event.ledgerPersisted !== true) {
2909
+ persistRuntimeLedgerWrite(() =>
2910
+ store.appendEvent(
2911
+ sessionId,
2912
+ runtimeUsageEventType("started"),
2913
+ projectRuntimeUsageBoundary(event, "started"),
2914
+ ),
2915
+ );
2916
+ }
2917
+ break;
2918
+ }
2919
+ case "model-usage-unknown":
2920
+ case "compaction-usage-unknown": {
2921
+ if (persist && event.ledgerPersisted !== true) {
2922
+ persistRuntimeLedgerWrite(() =>
2923
+ store.appendEvent(
2924
+ sessionId,
2925
+ runtimeUsageEventType("unknown"),
2926
+ projectRuntimeUsageBoundary(event, "unknown"),
2927
+ ),
2928
+ );
2929
+ }
2930
+ if (event.type === "compaction-usage-unknown") {
2931
+ endReason = "compaction-usage-unknown";
2932
+ stopForCompactionUsageUnknown = true;
2933
+ emitStream({
2934
+ type: "compaction_usage_unknown",
2935
+ provider: event.provider,
2936
+ model: event.model,
2937
+ source: event.source || "semantic-compaction",
2938
+ reason: event.reason || "provider_transport_outcome_unknown",
2939
+ usage_outcome: "unknown",
2718
2940
  });
2719
- } else {
2941
+ }
2942
+ break;
2943
+ }
2944
+ case "token-usage": {
2945
+ const persistedUsage = projectRuntimeTokenUsage(event);
2946
+ if (persist && event.ledgerPersisted !== true) {
2947
+ persistRuntimeLedgerWrite(() =>
2948
+ store.appendTokenUsage(sessionId, persistedUsage),
2949
+ );
2950
+ }
2951
+ if (!event.attribution) {
2720
2952
  usage.input_tokens += event.usage?.input_tokens || 0;
2721
2953
  usage.output_tokens += event.usage?.output_tokens || 0;
2722
2954
  // Carry prompt-cache tokens into accumulated usage (cost accuracy).
@@ -2808,7 +3040,7 @@ async function runAgentHeadlessInWorkspace(
2808
3040
  await deps.outputFlow?.wait?.();
2809
3041
  // Hard cost cap reached: stop consuming the loop so no further paid LLM
2810
3042
  // call is made (break out of the for-await, not just the switch).
2811
- if (stopForCost) break;
3043
+ if (stopForCost || stopForCompactionUsageUnknown) break;
2812
3044
  }
2813
3045
  // P1 turn→checkpoint binding: the turn settled — persist the explicit
2814
3046
  // table (latest snapshot wins on load; no-op when nothing was recorded).
@@ -2918,6 +3150,7 @@ async function runAgentHeadlessInWorkspace(
2918
3150
  });
2919
3151
  }
2920
3152
  } catch (err) {
3153
+ if (err?.runtimeLedgerPersistence === true) throw err;
2921
3154
  evaluation = {
2922
3155
  met: false,
2923
3156
  reason: `goal check failed: ${err.message}`,
@@ -2966,11 +3199,18 @@ async function runAgentHeadlessInWorkspace(
2966
3199
  break;
2967
3200
  }
2968
3201
  } catch (err) {
2969
- const message = err?.message || String(err);
3202
+ const runtimeLedgerPersistenceFailed =
3203
+ err?.runtimeLedgerPersistence === true;
3204
+ const message = runtimeLedgerPersistenceFailed
3205
+ ? RUNTIME_LEDGER_PERSISTENCE_FAILURE_MESSAGE
3206
+ : err?.message || String(err);
3207
+ const errorSubtype = runtimeLedgerPersistenceFailed
3208
+ ? "error_persistence"
3209
+ : "error";
2970
3210
  if (isStream) {
2971
3211
  emitStream({
2972
3212
  type: "result",
2973
- subtype: "error",
3213
+ subtype: errorSubtype,
2974
3214
  is_error: true,
2975
3215
  error: message,
2976
3216
  });
@@ -2978,7 +3218,7 @@ async function runAgentHeadlessInWorkspace(
2978
3218
  writeOut(
2979
3219
  JSON.stringify(
2980
3220
  buildResultEnvelope({
2981
- subtype: "error",
3221
+ subtype: errorSubtype,
2982
3222
  isError: true,
2983
3223
  result: message,
2984
3224
  sessionId,
@@ -2997,7 +3237,7 @@ async function runAgentHeadlessInWorkspace(
2997
3237
  // Provider/transport failures get their own exit code (5) so CI can tell
2998
3238
  // "the model call failed" from "the run itself errored" (1).
2999
3239
  loopFailureOutcome = {
3000
- exitCode: classifyLoopError(err),
3240
+ exitCode: runtimeLedgerPersistenceFailed ? 1 : classifyLoopError(err),
3001
3241
  result: message,
3002
3242
  isError: true,
3003
3243
  };
@@ -3184,26 +3424,6 @@ async function runAgentHeadlessInWorkspace(
3184
3424
  if (persist && !isError) {
3185
3425
  try {
3186
3426
  if (finalText) store.appendAssistantMessage(sessionId, finalText);
3187
- // 用量归因: compact per-tool records (name + error flag + skill hint —
3188
- // never args) so `cc session usage --by tool|mcp` can aggregate
3189
- // headless sessions too.
3190
- for (const tc of toolCalls) {
3191
- store.appendToolCallCompact(sessionId, {
3192
- tool: tc.tool,
3193
- isError: Boolean(tc.is_error),
3194
- skill:
3195
- tc.tool === "run_skill" ? tc.args?.skill_name || null : undefined,
3196
- plugin: tc.plugin || undefined,
3197
- pluginVersion: tc.pluginVersion || undefined,
3198
- durationMs: tc.durationMs,
3199
- });
3200
- }
3201
- // Attributed child-loop usage first (chronology: it happened during
3202
- // the run), then the unchanged main-loop aggregate.
3203
- for (const au of attributedUsage) {
3204
- store.appendTokenUsage(sessionId, au);
3205
- }
3206
- store.appendTokenUsage(sessionId, usage);
3207
3427
  } catch (error) {
3208
3428
  const persistenceError = createSessionPersistenceFailure(error, {
3209
3429
  sessionId,
@@ -3233,8 +3453,9 @@ async function runAgentHeadlessInWorkspace(
3233
3453
 
3234
3454
  // Run-end goal self-assessment (cc goal Phase 2, opt-in via --goal-assess).
3235
3455
  // Spends one extra completion to judge whether the run advanced the bound
3236
- // goal, then persists progress / key-result / drift updates. Best-effort: it
3237
- // must never change the run's own outcome.
3456
+ // goal, then persists progress / key-result / drift updates. Ordinary
3457
+ // assessment failures are best-effort; a usage-ledger durability failure is
3458
+ // terminal because reporting the extra paid call as successful is unsafe.
3238
3459
  if (options.goalAssess && boundGoalId && !isError) {
3239
3460
  try {
3240
3461
  const { getGoal } = await import("../lib/goal-store.js");
@@ -3246,10 +3467,23 @@ async function runAgentHeadlessInWorkspace(
3246
3467
  deps.assessChat ||
3247
3468
  (async (assessPrompt) => {
3248
3469
  const { chatWithTools } = await import("./agent-core.js");
3249
- const r = await chatWithTools(
3250
- [{ role: "user", content: assessPrompt }],
3251
- { model, provider, baseUrl, apiKey, enabledToolNames: [] },
3252
- );
3470
+ const r = await runMeteredDirectModelCall({
3471
+ sessionId: resolveHeadlessMeteredSessionId(persist, sessionId),
3472
+ persist: persist
3473
+ ? (type, data) => store.appendEvent(sessionId, type, data)
3474
+ : null,
3475
+ provider,
3476
+ model,
3477
+ source: "model",
3478
+ call: () =>
3479
+ chatWithTools([{ role: "user", content: assessPrompt }], {
3480
+ model,
3481
+ provider,
3482
+ baseUrl,
3483
+ apiKey,
3484
+ enabledToolNames: [],
3485
+ }),
3486
+ });
3253
3487
  return r?.message?.content || "";
3254
3488
  });
3255
3489
  const { assessment } = await doAssess({
@@ -3276,8 +3510,16 @@ async function runAgentHeadlessInWorkspace(
3276
3510
  });
3277
3511
  }
3278
3512
  }
3279
- } catch {
3280
- /* assessment is best-effort — never affect the run outcome */
3513
+ } catch (error) {
3514
+ if (error?.runtimeLedgerPersistence === true) {
3515
+ isError = true;
3516
+ subtype = "error_persistence";
3517
+ finalText = RUNTIME_LEDGER_PERSISTENCE_FAILURE_MESSAGE;
3518
+ if (isText) {
3519
+ writeErr(`${RUNTIME_LEDGER_PERSISTENCE_FAILURE_MESSAGE}\n`);
3520
+ }
3521
+ }
3522
+ // Non-ledger assessment failures remain best-effort.
3281
3523
  }
3282
3524
  }
3283
3525