chainlesschain 0.162.197 → 0.162.198

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 (208) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/assets/{AIOps-D3Gu1a5d.js → AIOps-CSN-D2xb.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-DrwAoKaz.js → ActionButton-CBSMlGzv.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-C7Q-gd_3.js → Analytics-3yr3Nt2t.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-DgBtae-n.js → AppLayout-1b-o3lMH.js} +5 -5
  6. package/src/assets/web-panel/assets/{Artifacts-pQ6LcA-W.js → Artifacts-Dr8rJi17.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-DK61tocB.js → Audit-2V689HC2.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-BOKgDFRh.js → BackgroundAgents-DIxkNrD_.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-Bo9G4vTP.js → Backup-Pg6BcwrE.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-Do_dE9_v.js → BaseInput-CLUpqyfH.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-COVvZzOL.js → Chat-qVS8rD4G.js} +5 -5
  12. package/src/assets/web-panel/assets/ChatBubbleRenderer-ti49X12Q.js +1 -0
  13. package/src/assets/web-panel/assets/{Checkbox-Z9MJMolt.js → Checkbox-Bs9AaEay.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-BVzWKVbf.js → Codegen-Dvc1mq8q.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-C8MnYcbT.js → Col-C4_biO7A.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-DQxqw15l.js → Community-al25XQUV.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-BAUmrh3y.js → Compact-D-ZDB8M1.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-jPAkQ3zK.js → Compliance-6lIfDz1W.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-BBQyxbh8.js → Cowork-DdI48XMJ.js} +3 -3
  20. package/src/assets/web-panel/assets/{Cron-W5koq8Z5.js → Cron-DF5HZd2g.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-BQhnu5hS.js → Crosschain-DuxeSvt3.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-DD7PlI18.js → DID-B9yHkUTd.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-w_ILuwKI.js → Dashboard-Z5EuI3IM.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-qiDUAyAo.js → Dropdown-vuRfO3dY.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-PDeBcI5H.js → EmailListRenderer-QFLCc1uL.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-SuArscRM.js → FamilyGuardDashboard-BZ7EXkFJ.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-BCovZaUn.js → Federation-DycIEg2s.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-DjlFdVFk.js → FormItemContext-Ba0H_7yG.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-DoEZ7fcS.js → GenericCardRenderer--JgSTK-C.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-CV0-6GPI.js → Git-DEvTbldE.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-B_SFN50w.js → Governance-BJIljy18.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-heI0Eo6k.js → Inference-CVyW3G3q.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-Cz5INS5p.js → KnowledgeGraph-v8-borge.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-BSFxiHkg.js → Logs-BCdS7gGo.js} +2 -2
  35. package/src/assets/web-panel/assets/MarkdownRenderer-CU-JB2Ns.js +1 -0
  36. package/src/assets/web-panel/assets/{Marketplace-0TWTpE7k.js → Marketplace-AN6tGA2B.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-CV4-wBLm.js → McpTools-DGViXASN.js} +4 -4
  38. package/src/assets/web-panel/assets/{Memory-x5bH5rw5.js → Memory-Bpvmx9X4.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-DaBmUu9G.js → MobileBridge-CTP-DOTC.js} +1 -1
  40. package/src/assets/web-panel/assets/MobileProjects-C8qfktxn.js +1 -0
  41. package/src/assets/web-panel/assets/{Mtc-B_zKEBif.js → Mtc-ndYr0M1s.js} +5 -5
  42. package/src/assets/web-panel/assets/{MtcAudit-BCfKD2yg.js → MtcAudit-Ci0-YK7W.js} +2 -2
  43. package/src/assets/web-panel/assets/{Multisig-DgYfj6c_.js → Multisig-BehSTFW7.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-Dz09lFUm.js → NLProgramming-B91_YBLv.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-Cuj6ugBE.js → Notes-BQlJ0-gq.js} +3 -3
  46. package/src/assets/web-panel/assets/{NotificationSettings-DK2WXjhg.js → NotificationSettings-CDgYMjYK.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-D1IAOQoo.js → OrderTableRenderer-BJkSlKeH.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-9fqnPvTw.js → Organization-B-b3cWCp.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-n5xHkhow.js → Overflow-CILUL4nL.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-B5AUWwH-.js → P2P-BTCFBkF0.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-CoUDV6dy.js → PdhVaultBrowser-BAR6AUx5.js} +4 -4
  52. package/src/assets/web-panel/assets/{Permissions-DPRmQf_H.js → Permissions-RRf6HbWJ.js} +4 -4
  53. package/src/assets/web-panel/assets/{PersonalDataHub-B37bsbEN.js → PersonalDataHub-BGTMiICa.js} +4 -4
  54. package/src/assets/web-panel/assets/{Pipeline-CCAuPqu9.js → Pipeline-945qY9YF.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-B81msZdv.js → Privacy-DPZwI6lJ.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-B-Py2NbF.js → ProjectInit-BPH2NRKc.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-CYsneiRB.js → ProjectSettings-BZCRNCvb.js} +2 -2
  58. package/src/assets/web-panel/assets/{Projects-Y975Mh6R.js → Projects-BTI__tBt.js} +1 -1
  59. package/src/assets/web-panel/assets/{Providers-uO-10aP1.js → Providers-DDCf_nIw.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-Bj_6gJ0l.js → QrScannerModal-N6rbqt1r.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-BgpBCMPE.js → QuickAsk-DrwjPS7M.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-DhUW3YUA.js → Recommend-Cog9Wd99.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-DdeyfbkA.js → RemoteSession-DC9pynjM.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-fxW421xd.js → Reputation-D4th4gKS.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-De73w1og.js → Row-ogiWR6v9.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-3US_Q_lj.js → RssFeed-uYlk-2Oj.js} +3 -3
  67. package/src/assets/web-panel/assets/{Search-DbZ_DU74.js → Search-DYzzwvtM.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-DoIU1vMF.js → Security-Da7YOyX6.js} +4 -4
  69. package/src/assets/web-panel/assets/{Services-DB_RGqpc.js → Services-CLI1VM1X.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-DnzLaayC.js → Skeleton-DK77dzDC.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-VzVXHENF.js → Skills-C_z7Lmhl.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-DMfvjCAI.js → Sla-D6413Q8L.js} +1 -1
  73. package/src/assets/web-panel/assets/{SpeechSettings-DQQOYWbF.js → SpeechSettings-C07ydbj2.js} +1 -1
  74. package/src/assets/web-panel/assets/{SyncSettings-Bmx3FG1P.js → SyncSettings-DGOm2W22.js} +2 -2
  75. package/src/assets/web-panel/assets/{Tasks-DOQyfb-2.js → Tasks-Cr_PVyLM.js} +1 -1
  76. package/src/assets/web-panel/assets/{Templates-D6hTRT7c.js → Templates-BhL2mZ0t.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-CTPQZAzs.js → Tenant-CPk5oyUr.js} +1 -1
  78. package/src/assets/web-panel/assets/{Terminal-B7vII3oH.js → Terminal-ClhqUsqV.js} +2 -2
  79. package/src/assets/web-panel/assets/{TimelineRenderer-BkiFJeXV.js → TimelineRenderer-BCC7MV5a.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-BPPdQMNo.js → Tokens-DD1Jt4oO.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-BxG8JAEI.js → Trigger-BCydFvN2.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-DHD7nMpM.js → Trust-DDHT1noa.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-B4BJpU47.js → UkeySign-CWPZC7oI.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-CRiGpFx2.js → VideoEditing-9Ea0nJR0.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-BSDSNiem.js → Wallet-BjxhLxTf.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-DLTUh5Zv.js → WebAuthn-C6uCye67.js} +5 -5
  87. package/src/assets/web-panel/assets/{WorkflowEditor-tW2MwjhD.js → WorkflowEditor-d2g4reYo.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-SgsLQ3FC.js → chat-frTc6ScX.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-BHjjLIKO.js → colors-B5K6lG3v.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-VceErdKq.js → compact-item-Cdn46r8D.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-BZ332MYl.js → createContext-DU1jqVQi.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-CP-jEUyw.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-CBTjJOjn.js → hasIn-DdNH-aW_.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-CawpdGTW.js → index-32ajXmTb.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-BOtvPdHt.js → index-7ehytj1K.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-vIXOpcjD.js → index-BC4eGkar.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-Cr4rjlW5.js → index-BVLL-mq_.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-D_SePDWj.js → index-BXKhhx9V.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BETEjuNr.js → index-BcGwGIaR.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-BY1wexYG.js → index-Be4OtL-N.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BRWhLbWF.js → index-BoFak7le.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-29wVzi-k.js → index-BwlIxAmX.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BeiqkxJG.js → index-CGiwfwB9.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BQSmZGgs.js → index-CHmkkdfT.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BhXZEUAc.js → index-CQorP1Ng.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-C_B9rFQE.js → index-CUoNAmE8.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-iYQNU9za.js → index-Cj6P9Nst.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DePOeMDM.js → index-CtRPi4YC.js} +1 -1
  109. package/src/assets/web-panel/assets/index-CzrCHrFy.js +1 -0
  110. package/src/assets/web-panel/assets/{index-DdefYBSw.js → index-D1qIC4GR.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-By5jBtkV.js → index-D23xGYjM.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-CMVvxIS8.js → index-D4l82Me1.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-CLc19alH.js → index-D4miNkWv.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-B2u26AS3.js → index-DIVyTmZ3.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-DaCCy6lq.js → index-DM5FmPZU.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DUkVN794.js → index-DRzBBdQ0.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-BPXFLYdW.js → index-Dca_i7H8.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-CpumS98o.js → index-DftZuyA7.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-CrUgDQkf.js → index-DtBCCkC4.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CtjLcCNU.js → index-HjCvXHf5.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CaIS_TNX.js → index-LaivuXyF.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-BC1xuQgX.js → index-MM4Zz2OE.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-BcUenmCX.js → index-NmEXVjzt.js} +1 -1
  124. package/src/assets/web-panel/assets/index-OJsGskZw.js +1 -0
  125. package/src/assets/web-panel/assets/{index-_PHrIO4O.js → index-PjAS0sIZ.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-DgPvuIn2.js → index-VDM2KKo9.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-B5KAGxNo.js → index-cYaWV4Mq.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-B40dQn0G.js → index-gg3QPC3i.js} +3 -3
  129. package/src/assets/web-panel/assets/{index-BTlc-Bve.js → index-kVO_MDm-.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-FJ3zC9LK.js → index-mgU3Q-lN.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-1n7xjKDU.js → index-t_OBzIP4.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-fU7wNHDB.js → index-yZRuZpwK.js} +1 -1
  133. package/src/assets/web-panel/assets/{initDefaultProps-D1oZNz0D.js → initDefaultProps-DwLTRNdo.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-C8k6doMO.js → motion-BchZDXnh.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-DJ4qSbYt.js → move-e8M-zZFl.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-CdpJD85j.js → mtc-parser-Ci40fQb3.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-B0V4slKA.js → omit-C7110_f2.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-Di5NiW1F.js → pickAttrs-skteMgnM.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-B5OMHgEM.js → placementArrow-MGZ-lh2B.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-C6U9IWql.js → responsiveObserve-N4Sd7uy-.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-BMyTH3rN.js → slide-C7HDGRaa.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-C7d6BG7Z.js → statusUtils-BhRexlgy.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-CR50QnQy.js → styleChecker-ChEoQkN2.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-DBEeoMb8.js → useFlexGapSupport-CDbG1s2Y.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-3r099cjv.js → useFs-CUIx0tcJ.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-C5IYNdTK.js → usePersonalDataHub-bkO7L7ec.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-DmEOLRHf.js → vnode-B_ZvABIG.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-DnpUiVCB.js → zoom-D5shjpS8.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/command-help-index.json +4 -4
  151. package/src/commands/agent.js +3 -3
  152. package/src/commands/background-session.js +145 -0
  153. package/src/commands/mcp.js +125 -7
  154. package/src/commands/serve.js +1 -1
  155. package/src/commands/session-show.js +131 -0
  156. package/src/commands/session.js +50 -106
  157. package/src/commands/skill.js +87 -50
  158. package/src/data/changelog.json +14 -1
  159. package/src/gateways/ws/ws-agent-handler.js +8 -1
  160. package/src/harness/jsonl-session-store.js +428 -25
  161. package/src/harness/mcp-client.js +2652 -404
  162. package/src/harness/session-list-index.js +65 -7
  163. package/src/lazy-dispatch.js +76 -8
  164. package/src/lib/abort-utils.js +68 -0
  165. package/src/lib/agent-core.js +1 -59
  166. package/src/lib/chat-core.js +24 -6
  167. package/src/lib/cowork-mcp-tools.js +47 -2
  168. package/src/lib/cowork-task-runner.js +11 -3
  169. package/src/lib/doctor-checkup.js +9 -7
  170. package/src/lib/learning/skill-improver.js +21 -2
  171. package/src/lib/mcp-call-ledger-store.js +116 -3
  172. package/src/lib/mcp-call-ledger.js +59 -14
  173. package/src/lib/mcp-client.js +1 -0
  174. package/src/lib/mcp-stdio-executable-identity.js +598 -0
  175. package/src/lib/mcp-stdio-execution-authority.js +363 -0
  176. package/src/lib/mcp-tool-metadata.js +436 -0
  177. package/src/lib/mcp-tool-result.js +367 -0
  178. package/src/lib/observability/index.js +71 -0
  179. package/src/lib/pr-link-ledger.js +8 -27
  180. package/src/lib/pr-link-store.js +26 -0
  181. package/src/lib/process-execution-broker/index.js +14 -0
  182. package/src/lib/process-tree-termination.js +253 -0
  183. package/src/lib/session-host-snapshot.js +9 -5
  184. package/src/lib/session-projection.js +5 -1
  185. package/src/lib/session-tail.js +31 -1
  186. package/src/lib/skill-budget.js +222 -0
  187. package/src/lib/skill-execution-authority.js +381 -0
  188. package/src/lib/skill-execution-identity.js +39 -2
  189. package/src/lib/skill-loader.js +322 -86
  190. package/src/lib/skill-mcp.js +43 -1
  191. package/src/repl/agent-repl.js +174 -38
  192. package/src/repl/bg-dashboard.js +81 -28
  193. package/src/repl/chat-repl.js +77 -12
  194. package/src/runtime/agent-core.js +340 -108
  195. package/src/runtime/agent-runtime.js +26 -3
  196. package/src/runtime/headless-runner.js +150 -23
  197. package/src/runtime/headless-stream.js +309 -59
  198. package/src/runtime/mcp-config.js +157 -10
  199. package/src/runtime/mcp-tool-search.js +0 -0
  200. package/src/runtime/output-backpressure.js +366 -0
  201. package/src/runtime/pipe-safety.js +56 -21
  202. package/src/assets/web-panel/assets/ChatBubbleRenderer-BUUyJ5QO.js +0 -1
  203. package/src/assets/web-panel/assets/MarkdownRenderer-1mNozZ8v.js +0 -1
  204. package/src/assets/web-panel/assets/MobileProjects-DqnoFPgR.js +0 -1
  205. package/src/assets/web-panel/assets/devWarning-DosMaL-k.js +0 -1
  206. package/src/assets/web-panel/assets/index-0O5ePnUq.js +0 -1
  207. package/src/assets/web-panel/assets/index-ChAzPigF.js +0 -1
  208. package/src/lib/skill-process-broker.js +0 -85
@@ -92,6 +92,7 @@ import {
92
92
  readVerifiedProjection as jsonlReadVerifiedProjection,
93
93
  findLatestEvent as jsonlFindLatestEvent,
94
94
  sessionExists as jsonlSessionExists,
95
+ sessionHasPersistedEvidence as jsonlSessionHasPersistedEvidence,
95
96
  } from "../harness/jsonl-session-store.js";
96
97
  import {
97
98
  isVerifiedSessionHostSnapshot,
@@ -123,6 +124,7 @@ import {
123
124
  parseSessionSlashCommandEvent,
124
125
  } from "./session-slash-commands.js";
125
126
  import { extractPluginUsageAttribution } from "../lib/plugin-usage-attribution.js";
127
+ import { createHeadlessOutputBackpressure } from "./output-backpressure.js";
126
128
 
127
129
  function invalidMcpRecoveryTransaction(capability, expected) {
128
130
  const error = new TypeError(
@@ -778,6 +780,7 @@ async function runTurn(
778
780
  sideEffects,
779
781
  turnNumber,
780
782
  turnBindingFeed,
783
+ waitForOutput,
781
784
  now = Date.now,
782
785
  },
783
786
  ) {
@@ -1017,6 +1020,7 @@ async function runTurn(
1017
1020
  if (event.type) emit(event);
1018
1021
  break;
1019
1022
  }
1023
+ await waitForOutput?.();
1020
1024
  // Hard cost cap reached — stop consuming the loop (break the for-await, not
1021
1025
  // just the switch) so no further paid LLM call is made.
1022
1026
  if (stopForCost) break;
@@ -1044,21 +1048,216 @@ async function runTurn(
1044
1048
  * writeOut, writeErr, expandFileRefs }
1045
1049
  * @returns {Promise<{exitCode:number, turns:number}>}
1046
1050
  */
1051
+ function createHeadlessStreamCleanupScope({ input }) {
1052
+ let mcpClient = null;
1053
+ let remoteApproval = null;
1054
+ let inputCancel = null;
1055
+ let interactionCleanup = null;
1056
+ let outputCleanup = null;
1057
+ let sessionEnd = null;
1058
+ let reason = "error";
1059
+ let stopRequested = false;
1060
+ let interactionCleanupPromise = Promise.resolve();
1061
+ let cleanupPromise = null;
1062
+
1063
+ const runBestEffort = async (operation) => {
1064
+ if (typeof operation !== "function") return;
1065
+ try {
1066
+ await operation();
1067
+ } catch {
1068
+ // Cleanup is exhaustive: one failing disposer must not prevent the
1069
+ // remaining resources from being retired.
1070
+ }
1071
+ };
1072
+
1073
+ const stopInputOwner = () => {
1074
+ try {
1075
+ if (input && input.readableEnded !== true && input.destroyed !== true) {
1076
+ if (typeof input.destroy === "function") input.destroy();
1077
+ else input.pause?.();
1078
+ }
1079
+ } catch {
1080
+ // Best-effort for non-Node custom input objects.
1081
+ }
1082
+ };
1083
+ const cancelInputIterator = () => {
1084
+ try {
1085
+ Promise.resolve(inputCancel?.()).catch(() => {});
1086
+ } catch {
1087
+ // A custom async iterator may reject cancellation synchronously.
1088
+ }
1089
+ };
1090
+ const settleInteractions = () => {
1091
+ interactionCleanupPromise = runBestEffort(() =>
1092
+ interactionCleanup?.(reason),
1093
+ );
1094
+ };
1095
+ const requestStop = () => {
1096
+ if (stopRequested) return;
1097
+ stopRequested = true;
1098
+ stopInputOwner();
1099
+ cancelInputIterator();
1100
+ settleInteractions();
1101
+ };
1102
+
1103
+ return {
1104
+ setReason(nextReason) {
1105
+ if (!stopRequested && !cleanupPromise && nextReason) {
1106
+ reason = String(nextReason);
1107
+ }
1108
+ },
1109
+ setMcpClient(client) {
1110
+ mcpClient = client || null;
1111
+ },
1112
+ setRemoteApproval(approval) {
1113
+ remoteApproval = approval || null;
1114
+ },
1115
+ setInputCancel(cancel) {
1116
+ inputCancel = typeof cancel === "function" ? cancel : null;
1117
+ if (stopRequested) cancelInputIterator();
1118
+ },
1119
+ setInteractionCleanup(cleanup) {
1120
+ interactionCleanup = typeof cleanup === "function" ? cleanup : null;
1121
+ if (stopRequested) settleInteractions();
1122
+ },
1123
+ setOutputCleanup(cleanup) {
1124
+ outputCleanup = typeof cleanup === "function" ? cleanup : null;
1125
+ },
1126
+ setSessionEnd(cleanup) {
1127
+ sessionEnd = typeof cleanup === "function" ? cleanup : null;
1128
+ },
1129
+ requestStop,
1130
+ cleanup() {
1131
+ if (!cleanupPromise) {
1132
+ cleanupPromise = (async () => {
1133
+ // Stop the live stdin owner before network/process resources. A
1134
+ // flowing stdin iterator can otherwise keep the process alive after
1135
+ // an early return or exception.
1136
+ requestStop();
1137
+ await interactionCleanupPromise;
1138
+ await runBestEffort(() => outputCleanup?.(reason));
1139
+ await runBestEffort(() => mcpClient?.disconnectAll?.());
1140
+ await runBestEffort(() => remoteApproval?.close?.());
1141
+ await runBestEffort(() => sessionEnd?.(reason));
1142
+ })();
1143
+ }
1144
+ return cleanupPromise;
1145
+ },
1146
+ };
1147
+ }
1148
+
1047
1149
  export async function runAgentHeadlessStream(options = {}, deps = {}) {
1048
1150
  const trustedWorkspaceRoot = options.cwd || process.cwd();
1049
- return runWithHostHooksV2Workspace(trustedWorkspaceRoot, () =>
1050
- runAgentHeadlessStreamInWorkspace(options, deps),
1051
- );
1151
+ const input = deps.input || process.stdin;
1152
+ const pipeState = { closed: false };
1153
+ const streamCleanup = createHeadlessStreamCleanupScope({ input });
1154
+ const stdout = deps.stdout || process.stdout;
1155
+ const stderr = deps.stderr || process.stderr;
1156
+ const shouldInstallPipeSafety =
1157
+ typeof deps.installPipeSafety === "function" ||
1158
+ (!deps.writeOut && !deps.writeErr);
1159
+ const pipeAbort = shouldInstallPipeSafety ? new AbortController() : null;
1160
+ const managesNativeOutput = !deps.writeOut || !deps.writeErr;
1161
+ const outputAbort = managesNativeOutput ? new AbortController() : null;
1162
+ const handlePipeClosed = () => {
1163
+ if (pipeState.closed) return;
1164
+ pipeState.closed = true;
1165
+ streamCleanup.setReason("pipe_closed");
1166
+ process.exitCode = 0;
1167
+ pipeAbort?.abort();
1168
+ streamCleanup.requestStop();
1169
+ };
1170
+ const outputFlow =
1171
+ deps.outputFlow ||
1172
+ createHeadlessOutputBackpressure({
1173
+ stdout,
1174
+ stderr,
1175
+ writeOut: deps.writeOut,
1176
+ writeErr: deps.writeErr,
1177
+ maxQueuedBytes: deps.outputBackpressureMaxBytes,
1178
+ onFailure: (error) => {
1179
+ outputAbort?.abort(error);
1180
+ if (error?.code === "EPIPE") handlePipeClosed();
1181
+ },
1182
+ });
1183
+ const abortSignals = [
1184
+ options.signal,
1185
+ pipeAbort?.signal,
1186
+ outputAbort?.signal,
1187
+ ].filter(Boolean);
1188
+ const runtimeOptions =
1189
+ abortSignals.length === 0
1190
+ ? options
1191
+ : {
1192
+ ...options,
1193
+ signal:
1194
+ abortSignals.length === 1
1195
+ ? abortSignals[0]
1196
+ : AbortSignal.any(abortSignals),
1197
+ };
1198
+ const runtimeDeps = {
1199
+ ...deps,
1200
+ writeOut: outputFlow.writeOut,
1201
+ writeErr: outputFlow.writeErr,
1202
+ outputFlow,
1203
+ };
1204
+ const onCallerAbort = () => {
1205
+ streamCleanup.setReason("aborted");
1206
+ streamCleanup.requestStop();
1207
+ };
1208
+ options.signal?.addEventListener("abort", onCallerAbort, { once: true });
1209
+ if (options.signal?.aborted) onCallerAbort();
1210
+ const installSafety = deps.installPipeSafety || installPipeSafety;
1211
+ let disposePipeSafety = null;
1212
+
1213
+ let outcome;
1214
+ let failure = null;
1215
+ try {
1216
+ disposePipeSafety = shouldInstallPipeSafety
1217
+ ? installSafety([stdout, stderr], handlePipeClosed)
1218
+ : null;
1219
+
1220
+ outcome = await runWithHostHooksV2Workspace(trustedWorkspaceRoot, () =>
1221
+ runAgentHeadlessStreamInWorkspace(
1222
+ runtimeOptions,
1223
+ runtimeDeps,
1224
+ pipeState,
1225
+ streamCleanup,
1226
+ ),
1227
+ );
1228
+ } catch (error) {
1229
+ failure = error;
1230
+ } finally {
1231
+ await streamCleanup.cleanup();
1232
+ try {
1233
+ await outputFlow.wait();
1234
+ } catch (error) {
1235
+ failure ||= error;
1236
+ }
1237
+ outputFlow.dispose();
1238
+ options.signal?.removeEventListener("abort", onCallerAbort);
1239
+ disposePipeSafety?.();
1240
+ }
1241
+
1242
+ if (pipeState.closed) {
1243
+ return { ...(outcome || { turns: 0 }), exitCode: 0 };
1244
+ }
1245
+ if (failure) throw failure;
1246
+ return outcome;
1052
1247
  }
1053
1248
 
1054
- async function runAgentHeadlessStreamInWorkspace(options = {}, deps = {}) {
1249
+ async function runAgentHeadlessStreamInWorkspace(
1250
+ options = {},
1251
+ deps = {},
1252
+ pipeState = { closed: false },
1253
+ streamCleanup,
1254
+ ) {
1055
1255
  const model = options.model || "qwen2.5:7b";
1056
1256
  const provider = options.provider || "ollama";
1057
1257
  const baseUrl = options.baseUrl || "http://localhost:11434";
1058
1258
  const apiKey = options.apiKey || null;
1059
- const writeOut = deps.writeOut || ((s) => process.stdout.write(s));
1060
- const writeErr = deps.writeErr || ((s) => process.stderr.write(s));
1061
- if (!deps.writeOut && !deps.writeErr) installPipeSafety();
1259
+ const writeOut = deps.writeOut;
1260
+ const writeErr = deps.writeErr;
1062
1261
 
1063
1262
  const sessionId =
1064
1263
  options.sessionId || `headless-stream-${Date.now()}-${process.pid}`;
@@ -1079,8 +1278,10 @@ async function runAgentHeadlessStreamInWorkspace(options = {}, deps = {}) {
1079
1278
  fieldGate,
1080
1279
  });
1081
1280
  const emit = streamCoalescer.emit;
1281
+ streamCleanup.setOutputCleanup(() => streamCoalescer.flush?.());
1082
1282
 
1083
1283
  const hasInjectedSessionStore =
1284
+ typeof deps.sessionHasPersistedEvidence === "function" ||
1084
1285
  typeof deps.sessionExists === "function" ||
1085
1286
  typeof deps.rebuildMessages === "function" ||
1086
1287
  typeof deps.appendEvent === "function" ||
@@ -1118,7 +1319,10 @@ async function runAgentHeadlessStreamInWorkspace(options = {}, deps = {}) {
1118
1319
  ? jsonlReadVerifiedProjection
1119
1320
  : null;
1120
1321
  const resumeDependencies = {
1121
- sessionExists: deps.sessionExists || jsonlSessionExists,
1322
+ sessionExists:
1323
+ deps.sessionHasPersistedEvidence ||
1324
+ deps.sessionExists ||
1325
+ jsonlSessionHasPersistedEvidence,
1122
1326
  readVerifiedEvents: (...args) =>
1123
1327
  requireSynchronousRecoveryResult(
1124
1328
  readVerifiedEvents(...args),
@@ -1293,7 +1497,7 @@ async function runAgentHeadlessStreamInWorkspace(options = {}, deps = {}) {
1293
1497
  cwd,
1294
1498
  settingsFile: options.settingsFile,
1295
1499
  });
1296
- if (notice) process.stderr.write(notice + "\n");
1500
+ if (notice) writeErr(notice + "\n");
1297
1501
  } catch {
1298
1502
  /* trust notice is best-effort */
1299
1503
  }
@@ -1334,6 +1538,20 @@ async function runAgentHeadlessStreamInWorkspace(options = {}, deps = {}) {
1334
1538
  const doExpand = deps.expandFileRefs || expandFileRefsAsync;
1335
1539
  const runSessionSlashCommand =
1336
1540
  deps.executeSessionSlashCommand || executeSessionSlashCommand;
1541
+ let turns = 0;
1542
+
1543
+ streamCleanup.setSessionEnd(async (reason) => {
1544
+ if (!settingsHooks) return;
1545
+ const runObserveHooks =
1546
+ deps.runObserveHooks ||
1547
+ (await import("../lib/settings-hook-events.js")).runObserveHooks;
1548
+ runObserveHooks(
1549
+ settingsHooks,
1550
+ "SessionEnd",
1551
+ { reason, cwd, session_id: sessionId },
1552
+ { cwd },
1553
+ );
1554
+ });
1337
1555
 
1338
1556
  const getApprovalGate =
1339
1557
  deps.getApprovalGate ||
@@ -1388,6 +1606,7 @@ async function runAgentHeadlessStreamInWorkspace(options = {}, deps = {}) {
1388
1606
  result: reason,
1389
1607
  session_id: sessionId,
1390
1608
  });
1609
+ streamCleanup.setReason("blocked");
1391
1610
  return { exitCode: 2, turns: 0 };
1392
1611
  }
1393
1612
 
@@ -1444,11 +1663,7 @@ async function runAgentHeadlessStreamInWorkspace(options = {}, deps = {}) {
1444
1663
  (hasInjectedSessionStore ? null : jsonlReadVerifiedProjection),
1445
1664
  findLatestEvent: storeFindLatestEvent,
1446
1665
  };
1447
- const mcpLedgerSink = persist
1448
- ? createSessionMcpLedgerSink(sessionId, {
1449
- appendEvent: store.appendAuthorityEvent,
1450
- })
1451
- : null;
1666
+ let mcpLedgerSink = null;
1452
1667
 
1453
1668
  // ── P0-2: crash-safe side-effect ledger — the stream twin of the
1454
1669
  // single-prompt runner (headless-runner.js) and the WS bridge
@@ -1740,6 +1955,37 @@ async function runAgentHeadlessStreamInWorkspace(options = {}, deps = {}) {
1740
1955
  e.code = "USER_TIMEOUT"; // handler → user_timeout (model proceeds, not a failure)
1741
1956
  p.reject(e);
1742
1957
  };
1958
+ streamCleanup.setInteractionCleanup((reason) => {
1959
+ const via = reason === "pipe_closed" ? "pipe-closed" : "session-closed";
1960
+ for (const [id, pending] of [...pendingApprovals.entries()]) {
1961
+ pendingApprovals.delete(id);
1962
+ clearTimeout(pending.timer);
1963
+ try {
1964
+ emit({
1965
+ type: "approval_resolved",
1966
+ id,
1967
+ approved: false,
1968
+ via,
1969
+ session_id: sessionId,
1970
+ });
1971
+ } catch {
1972
+ // The output pipe may itself be the reason cleanup is running.
1973
+ }
1974
+ pending.resolve(false);
1975
+ }
1976
+ for (const [id, pending] of [...pendingQuestions.entries()]) {
1977
+ pendingQuestions.delete(id);
1978
+ clearTimeout(pending.timer);
1979
+ try {
1980
+ emit({ type: "question_resolved", id, via, session_id: sessionId });
1981
+ } catch {
1982
+ // Best-effort cleanup notification.
1983
+ }
1984
+ const error = new Error(`ask_user_question ${via}`);
1985
+ error.code = "USER_TIMEOUT";
1986
+ pending.reject(error);
1987
+ }
1988
+ });
1743
1989
  const interactionAskUser = ({
1744
1990
  question,
1745
1991
  options: qOptions,
@@ -2089,6 +2335,7 @@ async function runAgentHeadlessStreamInWorkspace(options = {}, deps = {}) {
2089
2335
  loadJetbrainsMcp: deps.loadJetbrainsMcp,
2090
2336
  },
2091
2337
  );
2338
+ streamCleanup.setMcpClient(mcp?.mcpClient);
2092
2339
  // MCP tool search (context scaling): defer big tool schemas behind the
2093
2340
  // internal tool_search tool. Below-threshold / disabled → no-op.
2094
2341
  if (mcp) {
@@ -2114,6 +2361,14 @@ async function runAgentHeadlessStreamInWorkspace(options = {}, deps = {}) {
2114
2361
  }
2115
2362
  }
2116
2363
 
2364
+ mcpLedgerSink = persist
2365
+ ? createSessionMcpLedgerSink(
2366
+ sessionId,
2367
+ hasInjectedSessionStore
2368
+ ? { appendEvent: store.appendAuthorityEvent }
2369
+ : { recovery: mcpLedgerRecovery },
2370
+ )
2371
+ : null;
2117
2372
  const mcpRecoveryRuntime = createMcpHostRecoveryRuntime({
2118
2373
  bundle: mcp,
2119
2374
  sessionId,
@@ -2156,7 +2411,7 @@ async function runAgentHeadlessStreamInWorkspace(options = {}, deps = {}) {
2156
2411
  });
2157
2412
  }
2158
2413
  if (mcp?.mcpClient?.setElicitationHandler && interactiveQuestions) {
2159
- mcp.mcpClient.setElicitationHandler(async (request) => {
2414
+ const elicitationHandler = async (request) => {
2160
2415
  const hookContext = {
2161
2416
  schema_version: 1,
2162
2417
  server: request.server || null,
@@ -2214,6 +2469,9 @@ async function runAgentHeadlessStreamInWorkspace(options = {}, deps = {}) {
2214
2469
  });
2215
2470
  throw error;
2216
2471
  }
2472
+ };
2473
+ mcp.mcpClient.setElicitationHandler(elicitationHandler, {
2474
+ signal: options.signal || null,
2217
2475
  });
2218
2476
  }
2219
2477
 
@@ -2247,7 +2505,6 @@ async function runAgentHeadlessStreamInWorkspace(options = {}, deps = {}) {
2247
2505
  is_error: true,
2248
2506
  error: err.message,
2249
2507
  });
2250
- if (mcp?.mcpClient) await mcp.mcpClient.disconnectAll().catch(() => {});
2251
2508
  return { exitCode: 1, turns: 0 };
2252
2509
  }
2253
2510
  if (approvalGate && typeof approvalGate.setConfirmer === "function") {
@@ -2273,11 +2530,14 @@ async function runAgentHeadlessStreamInWorkspace(options = {}, deps = {}) {
2273
2530
  options.interactiveApprovals !== true
2274
2531
  ) {
2275
2532
  try {
2276
- const { startHeadlessRemoteApproval } =
2277
- await import("../lib/remote-approval-bridge.js");
2278
- _remoteApproval = await startHeadlessRemoteApproval({
2533
+ const startRemoteApproval =
2534
+ deps.startHeadlessRemoteApproval ||
2535
+ (await import("../lib/remote-approval-bridge.js"))
2536
+ .startHeadlessRemoteApproval;
2537
+ _remoteApproval = await startRemoteApproval({
2279
2538
  agentSessionId: sessionId,
2280
2539
  });
2540
+ streamCleanup.setRemoteApproval(_remoteApproval);
2281
2541
  emit({
2282
2542
  type: "remote_control",
2283
2543
  subtype: "pairing",
@@ -2414,7 +2674,6 @@ async function runAgentHeadlessStreamInWorkspace(options = {}, deps = {}) {
2414
2674
  })
2415
2675
  : null;
2416
2676
 
2417
- let turns = 0;
2418
2677
  let sawError = false;
2419
2678
  // Session-scoped tool-call correlation ids ("tu-<n>", additive protocol-v1
2420
2679
  // field): one counter across ALL turns so ids never repeat within a session.
@@ -2447,9 +2706,11 @@ async function runAgentHeadlessStreamInWorkspace(options = {}, deps = {}) {
2447
2706
  let inputDone = false;
2448
2707
  let currentAbort = null;
2449
2708
  let slashRequestSeq = 0;
2709
+ const inputLines = readJsonLines(input);
2710
+ streamCleanup.setInputCancel(() => inputLines.return?.());
2450
2711
  (async () => {
2451
2712
  try {
2452
- for await (const line of readJsonLines(input)) {
2713
+ for await (const line of inputLines) {
2453
2714
  const parsed = parseInputEvent(line);
2454
2715
  if (parsed == null) continue;
2455
2716
  if (parsed.hello) {
@@ -2537,15 +2798,25 @@ async function runAgentHeadlessStreamInWorkspace(options = {}, deps = {}) {
2537
2798
  const nextEvent = async () => {
2538
2799
  for (;;) {
2539
2800
  if (queue.length > 0) return queue.shift();
2540
- if (inputDone) return null;
2801
+ if (inputDone || options.signal?.aborted) return null;
2541
2802
  await new Promise((r) => {
2542
- wakeQueue = r;
2803
+ let settled = false;
2804
+ const wake = () => {
2805
+ if (settled) return;
2806
+ settled = true;
2807
+ options.signal?.removeEventListener("abort", wake);
2808
+ if (wakeQueue === wake) wakeQueue = null;
2809
+ r();
2810
+ };
2811
+ wakeQueue = wake;
2812
+ options.signal?.addEventListener("abort", wake, { once: true });
2813
+ if (options.signal?.aborted) wake();
2543
2814
  });
2544
- wakeQueue = null;
2545
2815
  }
2546
2816
  };
2547
2817
 
2548
2818
  for (;;) {
2819
+ await deps.outputFlow?.wait?.();
2549
2820
  const parsed = await nextEvent();
2550
2821
  if (parsed == null) break; // stdin closed
2551
2822
  if (turnBindingPersistenceError) {
@@ -3118,6 +3389,7 @@ async function runAgentHeadlessStreamInWorkspace(options = {}, deps = {}) {
3118
3389
  sideEffects,
3119
3390
  turnNumber: turns,
3120
3391
  turnBindingFeed,
3392
+ waitForOutput: deps.outputFlow?.wait,
3121
3393
  now: deps.now || Date.now,
3122
3394
  },
3123
3395
  );
@@ -3294,41 +3566,19 @@ async function runAgentHeadlessStreamInWorkspace(options = {}, deps = {}) {
3294
3566
  }
3295
3567
  }
3296
3568
 
3297
- // Tear down ad-hoc MCP servers (--mcp-config) when stdin closes.
3298
- if (mcp?.mcpClient) {
3299
- try {
3300
- await mcp.mcpClient.disconnectAll();
3301
- } catch {
3302
- // ignore — disconnect is best-effort
3303
- }
3304
- }
3305
-
3306
- // Tear down the --remote-control approval bridge + its self-hosted WS
3307
- // server so the stream session's port never outlives the invocation.
3308
- if (_remoteApproval) {
3309
- try {
3310
- await _remoteApproval.close();
3311
- } catch {
3312
- // best-effort
3313
- }
3314
- }
3569
+ streamCleanup.setReason(
3570
+ pipeState.closed
3571
+ ? "pipe_closed"
3572
+ : options.signal?.aborted
3573
+ ? "aborted"
3574
+ : inputDone
3575
+ ? "stdin_closed"
3576
+ : "completed",
3577
+ );
3578
+ await streamCleanup.cleanup();
3315
3579
 
3316
- // settings.json SessionEnd hooks (observe-only) when stdin closes.
3317
- if (settingsHooks) {
3318
- try {
3319
- const { runObserveHooks } =
3320
- await import("../lib/settings-hook-events.js");
3321
- runObserveHooks(
3322
- settingsHooks,
3323
- "SessionEnd",
3324
- { reason: "stdin_closed", cwd, session_id: sessionId },
3325
- { cwd },
3326
- );
3327
- } catch {
3328
- // observe-only
3329
- }
3580
+ if (!pipeState.closed) {
3581
+ emit({ type: "system", subtype: "end", session_id: sessionId, turns });
3330
3582
  }
3331
-
3332
- emit({ type: "system", subtype: "end", session_id: sessionId, turns });
3333
- return { exitCode: sawError ? 1 : 0, turns };
3583
+ return { exitCode: pipeState.closed ? 0 : sawError ? 1 : 0, turns };
3334
3584
  }