chainlesschain 0.162.197 → 0.162.200

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 (233) hide show
  1. package/bin/chainlesschain.js +14 -6
  2. package/package.json +4 -1
  3. package/scripts/command-lifecycle-report.mjs +94 -0
  4. package/src/assets/web-panel/assets/{AIOps-D3Gu1a5d.js → AIOps-DcQ0bWKy.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-DrwAoKaz.js → ActionButton-GecwfFPt.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-C7Q-gd_3.js → Analytics-CD6iSt9v.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-DgBtae-n.js → AppLayout-CDEtuEYf.js} +5 -5
  8. package/src/assets/web-panel/assets/{Artifacts-pQ6LcA-W.js → Artifacts-DS3jAjeW.js} +1 -1
  9. package/src/assets/web-panel/assets/{Audit-DK61tocB.js → Audit-CcSJA048.js} +1 -1
  10. package/src/assets/web-panel/assets/{BackgroundAgents-BOKgDFRh.js → BackgroundAgents-DRo9Morb.js} +1 -1
  11. package/src/assets/web-panel/assets/{Backup-Bo9G4vTP.js → Backup-Vw5MrWft.js} +1 -1
  12. package/src/assets/web-panel/assets/{BaseInput-Do_dE9_v.js → BaseInput-DNHIu823.js} +1 -1
  13. package/src/assets/web-panel/assets/{Chat-COVvZzOL.js → Chat-DvAsO8-b.js} +4 -4
  14. package/src/assets/web-panel/assets/ChatBubbleRenderer-9aDuObay.js +1 -0
  15. package/src/assets/web-panel/assets/{Checkbox-Z9MJMolt.js → Checkbox-CKCa7tvn.js} +1 -1
  16. package/src/assets/web-panel/assets/{Codegen-BVzWKVbf.js → Codegen-CIFvZdaT.js} +1 -1
  17. package/src/assets/web-panel/assets/{Col-C8MnYcbT.js → Col-C79yz7bK.js} +1 -1
  18. package/src/assets/web-panel/assets/{Community-DQxqw15l.js → Community-DVvZskLJ.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compact-BAUmrh3y.js → Compact-oaew61hV.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compliance-jPAkQ3zK.js → Compliance-DqA7wmRx.js} +1 -1
  21. package/src/assets/web-panel/assets/{Cowork-BBQyxbh8.js → Cowork-B-qGadxa.js} +3 -3
  22. package/src/assets/web-panel/assets/{Cron-W5koq8Z5.js → Cron-CUlCl4sS.js} +2 -2
  23. package/src/assets/web-panel/assets/{Crosschain-BQhnu5hS.js → Crosschain-CNOlr9DU.js} +1 -1
  24. package/src/assets/web-panel/assets/{DID-DD7PlI18.js → DID-DJqFCT_3.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dashboard-w_ILuwKI.js → Dashboard-CznGpphf.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dropdown-qiDUAyAo.js → Dropdown-_cJw218E.js} +1 -1
  27. package/src/assets/web-panel/assets/{EmailListRenderer-PDeBcI5H.js → EmailListRenderer-Dr-1BZ9C.js} +1 -1
  28. package/src/assets/web-panel/assets/{FamilyGuardDashboard-SuArscRM.js → FamilyGuardDashboard-Dxf4xtSk.js} +1 -1
  29. package/src/assets/web-panel/assets/{Federation-BCovZaUn.js → Federation-DOiG3i_1.js} +1 -1
  30. package/src/assets/web-panel/assets/{FormItemContext-DjlFdVFk.js → FormItemContext-BzbMcFB9.js} +1 -1
  31. package/src/assets/web-panel/assets/{GenericCardRenderer-DoEZ7fcS.js → GenericCardRenderer-VbBrYttP.js} +1 -1
  32. package/src/assets/web-panel/assets/{Git-CV0-6GPI.js → Git-CLG8E6ED.js} +2 -2
  33. package/src/assets/web-panel/assets/{Governance-B_SFN50w.js → Governance-LGJQfk_q.js} +1 -1
  34. package/src/assets/web-panel/assets/{Inference-heI0Eo6k.js → Inference-DlQKx9lF.js} +1 -1
  35. package/src/assets/web-panel/assets/{KnowledgeGraph-Cz5INS5p.js → KnowledgeGraph-DU8vEouV.js} +1 -1
  36. package/src/assets/web-panel/assets/{Logs-BSFxiHkg.js → Logs-FZIQOdln.js} +2 -2
  37. package/src/assets/web-panel/assets/MarkdownRenderer-BJNWIrbw.js +1 -0
  38. package/src/assets/web-panel/assets/{Marketplace-0TWTpE7k.js → Marketplace-C_xd-zZI.js} +1 -1
  39. package/src/assets/web-panel/assets/{McpTools-CV4-wBLm.js → McpTools-q-YktphS.js} +5 -5
  40. package/src/assets/web-panel/assets/{Memory-x5bH5rw5.js → Memory-Cq9OhDin.js} +2 -2
  41. package/src/assets/web-panel/assets/{MobileBridge-DaBmUu9G.js → MobileBridge-B03_R98T.js} +1 -1
  42. package/src/assets/web-panel/assets/MobileProjects-DZrk-qmF.js +1 -0
  43. package/src/assets/web-panel/assets/{Mtc-B_zKEBif.js → Mtc-BidCKW28.js} +5 -5
  44. package/src/assets/web-panel/assets/{MtcAudit-BCfKD2yg.js → MtcAudit-r-iaMVM7.js} +2 -2
  45. package/src/assets/web-panel/assets/{Multisig-DgYfj6c_.js → Multisig-CgTUFvff.js} +3 -3
  46. package/src/assets/web-panel/assets/{NLProgramming-Dz09lFUm.js → NLProgramming-B7NvzfAV.js} +1 -1
  47. package/src/assets/web-panel/assets/{Notes-Cuj6ugBE.js → Notes-80CWNqJI.js} +3 -3
  48. package/src/assets/web-panel/assets/{NotificationSettings-DK2WXjhg.js → NotificationSettings-0H6xdiY3.js} +1 -1
  49. package/src/assets/web-panel/assets/{OrderTableRenderer-D1IAOQoo.js → OrderTableRenderer-CKP4AFWy.js} +1 -1
  50. package/src/assets/web-panel/assets/{Organization-9fqnPvTw.js → Organization-B8sxCV_h.js} +4 -4
  51. package/src/assets/web-panel/assets/{Overflow-n5xHkhow.js → Overflow-CW9JBBhQ.js} +1 -1
  52. package/src/assets/web-panel/assets/{P2P-B5AUWwH-.js → P2P-bdSQV7oZ.js} +2 -2
  53. package/src/assets/web-panel/assets/{PdhVaultBrowser-CoUDV6dy.js → PdhVaultBrowser-DQad42nW.js} +4 -4
  54. package/src/assets/web-panel/assets/{Permissions-DPRmQf_H.js → Permissions-CueexxTR.js} +4 -4
  55. package/src/assets/web-panel/assets/{PersonalDataHub-B37bsbEN.js → PersonalDataHub-fqxflhR8.js} +6 -6
  56. package/src/assets/web-panel/assets/{Pipeline-CCAuPqu9.js → Pipeline-KFwwnIMC.js} +1 -1
  57. package/src/assets/web-panel/assets/{Privacy-B81msZdv.js → Privacy-ClnD9buY.js} +1 -1
  58. package/src/assets/web-panel/assets/{ProjectInit-B-Py2NbF.js → ProjectInit-CZEz6sm3.js} +2 -2
  59. package/src/assets/web-panel/assets/{ProjectSettings-CYsneiRB.js → ProjectSettings-B6NzpmOI.js} +2 -2
  60. package/src/assets/web-panel/assets/{Projects-Y975Mh6R.js → Projects-DYyuwPCs.js} +1 -1
  61. package/src/assets/web-panel/assets/Providers-C3tz_jdh.js +1 -0
  62. package/src/assets/web-panel/assets/{QrScannerModal-Bj_6gJ0l.js → QrScannerModal-BzuOBbqB.js} +1 -1
  63. package/src/assets/web-panel/assets/{QuickAsk-BgpBCMPE.js → QuickAsk-CmNO9qSj.js} +1 -1
  64. package/src/assets/web-panel/assets/{Recommend-DhUW3YUA.js → Recommend-VJNj3_NF.js} +1 -1
  65. package/src/assets/web-panel/assets/{RemoteSession-DdeyfbkA.js → RemoteSession-CrbdbSBF.js} +2 -2
  66. package/src/assets/web-panel/assets/{Reputation-fxW421xd.js → Reputation-DTyMd45j.js} +1 -1
  67. package/src/assets/web-panel/assets/{Row-De73w1og.js → Row-DHrQ-Icz.js} +1 -1
  68. package/src/assets/web-panel/assets/{RssFeed-3US_Q_lj.js → RssFeed-DqWxY9c5.js} +2 -2
  69. package/src/assets/web-panel/assets/{Search-DbZ_DU74.js → Search-ctF1Ks3J.js} +1 -1
  70. package/src/assets/web-panel/assets/{Security-DoIU1vMF.js → Security-BrQz8uo5.js} +4 -4
  71. package/src/assets/web-panel/assets/{Services-DB_RGqpc.js → Services-D4scVFar.js} +2 -2
  72. package/src/assets/web-panel/assets/{Skeleton-DnzLaayC.js → Skeleton-oUScaOjv.js} +1 -1
  73. package/src/assets/web-panel/assets/{Skills-VzVXHENF.js → Skills-CL-y0eLt.js} +1 -1
  74. package/src/assets/web-panel/assets/{Sla-DMfvjCAI.js → Sla-DQExhwXj.js} +1 -1
  75. package/src/assets/web-panel/assets/{SpeechSettings-DQQOYWbF.js → SpeechSettings-iNp_I7kN.js} +1 -1
  76. package/src/assets/web-panel/assets/{SyncSettings-Bmx3FG1P.js → SyncSettings-CTDlMo0A.js} +2 -2
  77. package/src/assets/web-panel/assets/{Tasks-DOQyfb-2.js → Tasks-4kb8l3sc.js} +1 -1
  78. package/src/assets/web-panel/assets/{Templates-D6hTRT7c.js → Templates-BXcL9oXW.js} +1 -1
  79. package/src/assets/web-panel/assets/{Tenant-CTPQZAzs.js → Tenant-DLE8eS0D.js} +1 -1
  80. package/src/assets/web-panel/assets/{Terminal-B7vII3oH.js → Terminal-DGpUZPPK.js} +2 -2
  81. package/src/assets/web-panel/assets/{TimelineRenderer-BkiFJeXV.js → TimelineRenderer-C1pWXGPC.js} +1 -1
  82. package/src/assets/web-panel/assets/{Tokens-BPPdQMNo.js → Tokens-BYfbfqhZ.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trigger-BxG8JAEI.js → Trigger-K9YfLOCw.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trust-DHD7nMpM.js → Trust-Ctkq77Hy.js} +1 -1
  85. package/src/assets/web-panel/assets/{UkeySign-B4BJpU47.js → UkeySign-C6_CSe9J.js} +1 -1
  86. package/src/assets/web-panel/assets/{VideoEditing-CRiGpFx2.js → VideoEditing-Be3rpOWs.js} +1 -1
  87. package/src/assets/web-panel/assets/{Wallet-BSDSNiem.js → Wallet-D0UIplxk.js} +4 -4
  88. package/src/assets/web-panel/assets/{WebAuthn-DLTUh5Zv.js → WebAuthn-CF9bM9I3.js} +5 -5
  89. package/src/assets/web-panel/assets/{WorkflowEditor-tW2MwjhD.js → WorkflowEditor-D0H1XVPY.js} +1 -1
  90. package/src/assets/web-panel/assets/{chat-SgsLQ3FC.js → chat-Cgzzbe0o.js} +1 -1
  91. package/src/assets/web-panel/assets/{colors-BHjjLIKO.js → colors-BwNxEVS0.js} +1 -1
  92. package/src/assets/web-panel/assets/{compact-item-VceErdKq.js → compact-item-D60Z4Hhs.js} +1 -1
  93. package/src/assets/web-panel/assets/{createContext-BZ332MYl.js → createContext-MFk58XB0.js} +1 -1
  94. package/src/assets/web-panel/assets/devWarning-BJiw369i.js +1 -0
  95. package/src/assets/web-panel/assets/{hasIn-CBTjJOjn.js → hasIn-CRj2SvGO.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-DaCCy6lq.js → index--s45_1cb.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-CMVvxIS8.js → index--tquQ2ZG.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-BhXZEUAc.js → index-1T1rhokn.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BQSmZGgs.js → index-B-M82_rx.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-BeiqkxJG.js → index-BE_el1Zs.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-29wVzi-k.js → index-BhRkR7IO.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-iYQNU9za.js → index-Bo0y96-K.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BRWhLbWF.js → index-CJgu5JUK.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BPXFLYdW.js → index-CLWwdebO.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-Cr4rjlW5.js → index-CNAK5QG_.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-CaIS_TNX.js → index-CQjJjPRD.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-1n7xjKDU.js → index-CTDbAfae.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-BETEjuNr.js → index-CVI_9sRK.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-By5jBtkV.js → index-CY14oMQK.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DgPvuIn2.js → index-CbiTJkZf.js} +1 -1
  111. package/src/assets/web-panel/assets/index-CiMouosn.js +1 -0
  112. package/src/assets/web-panel/assets/{index-CawpdGTW.js → index-CqWpxMqx.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-_PHrIO4O.js → index-CvB8lYUR.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BOtvPdHt.js → index-D51XwtCY.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CrUgDQkf.js → index-D6HvK_1O.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-BY1wexYG.js → index-D9jVIwLJ.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-C_B9rFQE.js → index-DA4tE98u.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-B5KAGxNo.js → index-DBwOtXw0.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-BC1xuQgX.js → index-DKdNzTIb.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-B2u26AS3.js → index-DRySdmvN.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DePOeMDM.js → index-DWzyTev7.js} +1 -1
  122. package/src/assets/web-panel/assets/index-DXcKlwy7.js +1 -0
  123. package/src/assets/web-panel/assets/{index-BTlc-Bve.js → index-DYjs7jAP.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-CLc19alH.js → index-DbROzMBp.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-fU7wNHDB.js → index-DhFtk5PR.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-D_SePDWj.js → index-Di2AbMLg.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-vIXOpcjD.js → index-DvmocQsM.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-BcUenmCX.js → index-Dw-o0zEF.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DUkVN794.js → index-DysPoP38.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-CtjLcCNU.js → index-LX9pJxm_.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-B40dQn0G.js → index-OI_fXWx0.js} +3 -3
  132. package/src/assets/web-panel/assets/{index-FJ3zC9LK.js → index-eDTOX8Xj.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-DdefYBSw.js → index-gWKDsTzF.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-CpumS98o.js → index-q_GDUVAA.js} +1 -1
  135. package/src/assets/web-panel/assets/{initDefaultProps-D1oZNz0D.js → initDefaultProps-C61kZqEd.js} +1 -1
  136. package/src/assets/web-panel/assets/{motion-C8k6doMO.js → motion-DZnT5U1L.js} +1 -1
  137. package/src/assets/web-panel/assets/{move-DJ4qSbYt.js → move-L8wzwbel.js} +1 -1
  138. package/src/assets/web-panel/assets/{mtc-parser-CdpJD85j.js → mtc-parser-DLdYSejc.js} +1 -1
  139. package/src/assets/web-panel/assets/{omit-B0V4slKA.js → omit-D53cbS59.js} +1 -1
  140. package/src/assets/web-panel/assets/{pickAttrs-Di5NiW1F.js → pickAttrs-Bbc5HPtu.js} +1 -1
  141. package/src/assets/web-panel/assets/{placementArrow-B5OMHgEM.js → placementArrow-BkvmO860.js} +1 -1
  142. package/src/assets/web-panel/assets/{responsiveObserve-C6U9IWql.js → responsiveObserve-u2y1ryS1.js} +1 -1
  143. package/src/assets/web-panel/assets/{slide-BMyTH3rN.js → slide-BBqj7svU.js} +1 -1
  144. package/src/assets/web-panel/assets/{statusUtils-C7d6BG7Z.js → statusUtils-GN0mqu2d.js} +1 -1
  145. package/src/assets/web-panel/assets/{styleChecker-CR50QnQy.js → styleChecker-BvwPKoBT.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFlexGapSupport-DBEeoMb8.js → useFlexGapSupport-CCt8tnfY.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFs-3r099cjv.js → useFs-DXAxl2SV.js} +1 -1
  148. package/src/assets/web-panel/assets/{usePersonalDataHub-C5IYNdTK.js → usePersonalDataHub-DihlR2dj.js} +1 -1
  149. package/src/assets/web-panel/assets/{vnode-DmEOLRHf.js → vnode-D7BOX2gi.js} +1 -1
  150. package/src/assets/web-panel/assets/{zoom-DnpUiVCB.js → zoom-CVbO-nL7.js} +1 -1
  151. package/src/assets/web-panel/index.html +1 -1
  152. package/src/command-help-index.json +4 -4
  153. package/src/commands/agent.js +3 -3
  154. package/src/commands/background-session.js +145 -0
  155. package/src/commands/mcp.js +244 -7
  156. package/src/commands/serve.js +1 -1
  157. package/src/commands/session-show.js +129 -0
  158. package/src/commands/session.js +97 -145
  159. package/src/commands/skill.js +87 -50
  160. package/src/data/changelog.json +40 -1
  161. package/src/gateways/ws/session-protocol.js +14 -4
  162. package/src/gateways/ws/ws-agent-handler.js +39 -1
  163. package/src/harness/jsonl-session-store.js +1547 -127
  164. package/src/harness/mcp-client.js +2690 -409
  165. package/src/harness/session-index.js +80 -80
  166. package/src/harness/session-list-index.js +210 -7
  167. package/src/lazy-dispatch.js +76 -8
  168. package/src/lib/abort-utils.js +68 -0
  169. package/src/lib/agent-core.js +1 -59
  170. package/src/lib/background-interaction-journal.js +2 -2
  171. package/src/lib/chat-core.js +24 -6
  172. package/src/lib/command-lifecycle-report.js +516 -0
  173. package/src/lib/cowork-mcp-tools.js +47 -2
  174. package/src/lib/cowork-task-runner.js +11 -3
  175. package/src/lib/doctor-checkup.js +9 -7
  176. package/src/lib/learning/skill-improver.js +21 -2
  177. package/src/lib/mcp-call-ledger-store.js +116 -3
  178. package/src/lib/mcp-call-ledger.js +59 -14
  179. package/src/lib/mcp-client.js +1 -0
  180. package/src/lib/mcp-stdio-environment.js +48 -0
  181. package/src/lib/mcp-stdio-executable-identity.js +1133 -0
  182. package/src/lib/mcp-stdio-execution-authority.js +363 -0
  183. package/src/lib/mcp-stdio-package-materialization.js +1424 -0
  184. package/src/lib/mcp-tool-metadata.js +436 -0
  185. package/src/lib/mcp-tool-result.js +367 -0
  186. package/src/lib/observability/index.js +71 -0
  187. package/src/lib/packer/native-update-state.js +979 -1
  188. package/src/lib/packer/pack-update-applier.js +1050 -125
  189. package/src/lib/packer/pkg-config-generator.js +1 -0
  190. package/src/lib/paths.js +53 -0
  191. package/src/lib/pr-link-ledger.js +8 -27
  192. package/src/lib/pr-link-store.js +26 -0
  193. package/src/lib/process-execution-broker/index.js +192 -35
  194. package/src/lib/process-execution-broker/platform-sandbox.js +291 -24
  195. package/src/lib/process-tree-termination.js +253 -0
  196. package/src/lib/recent-session.js +17 -17
  197. package/src/lib/secure-file-identity.js +47 -0
  198. package/src/lib/secure-fs.js +21 -2
  199. package/src/lib/session-anti-rollback-anchor.js +766 -0
  200. package/src/lib/session-host-lease.js +492 -0
  201. package/src/lib/session-host-snapshot.js +9 -5
  202. package/src/lib/session-persistence-failure.js +109 -0
  203. package/src/lib/session-picker.js +26 -3
  204. package/src/lib/session-projection.js +5 -1
  205. package/src/lib/session-search.js +25 -11
  206. package/src/lib/session-tail.js +31 -1
  207. package/src/lib/side-effect-ledger-store.js +2 -2
  208. package/src/lib/skill-budget.js +222 -0
  209. package/src/lib/skill-execution-authority.js +385 -0
  210. package/src/lib/skill-execution-identity.js +39 -2
  211. package/src/lib/skill-loader.js +322 -86
  212. package/src/lib/skill-mcp.js +43 -1
  213. package/src/lib/turn-binding-store.js +2 -2
  214. package/src/repl/agent-repl.js +483 -77
  215. package/src/repl/bg-dashboard.js +81 -28
  216. package/src/repl/chat-repl.js +77 -12
  217. package/src/runtime/agent-core.js +428 -113
  218. package/src/runtime/agent-runtime.js +26 -3
  219. package/src/runtime/cleanup-deadline.js +143 -0
  220. package/src/runtime/headless-runner.js +494 -149
  221. package/src/runtime/headless-stream.js +504 -75
  222. package/src/runtime/mcp-config.js +157 -10
  223. package/src/runtime/mcp-tool-search.js +0 -0
  224. package/src/runtime/output-backpressure.js +419 -0
  225. package/src/runtime/pipe-safety.js +56 -21
  226. package/src/assets/web-panel/assets/ChatBubbleRenderer-BUUyJ5QO.js +0 -1
  227. package/src/assets/web-panel/assets/MarkdownRenderer-1mNozZ8v.js +0 -1
  228. package/src/assets/web-panel/assets/MobileProjects-DqnoFPgR.js +0 -1
  229. package/src/assets/web-panel/assets/Providers-uO-10aP1.js +0 -1
  230. package/src/assets/web-panel/assets/devWarning-DosMaL-k.js +0 -1
  231. package/src/assets/web-panel/assets/index-0O5ePnUq.js +0 -1
  232. package/src/assets/web-panel/assets/index-ChAzPigF.js +0 -1
  233. package/src/lib/skill-process-broker.js +0 -85
@@ -16,7 +16,11 @@
16
16
 
17
17
  import fs from "fs";
18
18
  import path from "path";
19
- import { MCPClient, redactMcpUrl } from "../harness/mcp-client.js";
19
+ import {
20
+ MCPClient,
21
+ inferTransport,
22
+ redactMcpUrl,
23
+ } from "../harness/mcp-client.js";
20
24
  import { projectRootBase } from "../lib/project-root.cjs";
21
25
  import {
22
26
  discoverIdeServer,
@@ -36,6 +40,38 @@ import {
36
40
  import { collectPluginMcpServers } from "../lib/plugin-runtime/mcp.js";
37
41
  import { EventRuntimeStore } from "../lib/event-runtime-store.js";
38
42
  import { mcpEffectDescriptorFields } from "../lib/mcp-effect-contract.js";
43
+ import {
44
+ admitMcpToolList,
45
+ isMcpToolMetadataError,
46
+ } from "../lib/mcp-tool-metadata.js";
47
+ import { issueMcpStdioExecutionAuthority } from "../lib/mcp-stdio-execution-authority.js";
48
+
49
+ function authorizeStdioServers(
50
+ servers,
51
+ approvalKind,
52
+ sourceForServer,
53
+ { writeErr = () => {}, failFast = false } = {},
54
+ ) {
55
+ for (const [name, config] of Object.entries(servers || {})) {
56
+ if (!config || typeof config !== "object") continue;
57
+ if (inferTransport(config) !== "stdio") continue;
58
+ try {
59
+ config.mcpStdioExecutionAuthority = issueMcpStdioExecutionAuthority({
60
+ serverName: name,
61
+ config,
62
+ approvalKind,
63
+ approvalSource: sourceForServer(name, config),
64
+ });
65
+ } catch (error) {
66
+ if (failFast) throw error;
67
+ delete servers[name];
68
+ writeErr(
69
+ ` mcp: SKIPPING stdio server "${name}" because its local-code execution authority could not be issued.\n`,
70
+ );
71
+ }
72
+ }
73
+ return servers;
74
+ }
39
75
 
40
76
  function headersHelperField(value) {
41
77
  return typeof value === "string" && value.trim()
@@ -64,6 +100,51 @@ export function parseMcpServers(raw) {
64
100
  transport: cfg.transport,
65
101
  headers:
66
102
  cfg.headers && typeof cfg.headers === "object" ? cfg.headers : {},
103
+ ...(Number.isFinite(cfg.maxPayloadBytes)
104
+ ? { maxPayloadBytes: cfg.maxPayloadBytes }
105
+ : {}),
106
+ ...(Number.isFinite(cfg.maxInboundMessagesPerSecond)
107
+ ? {
108
+ maxInboundMessagesPerSecond: cfg.maxInboundMessagesPerSecond,
109
+ }
110
+ : {}),
111
+ ...(Number.isFinite(cfg.maxInboundBytesPerMinute)
112
+ ? { maxInboundBytesPerMinute: cfg.maxInboundBytesPerMinute }
113
+ : {}),
114
+ ...(Number.isFinite(cfg.maxJsonDepth)
115
+ ? { maxJsonDepth: cfg.maxJsonDepth }
116
+ : {}),
117
+ ...(Number.isFinite(cfg.maxJsonNodes)
118
+ ? { maxJsonNodes: cfg.maxJsonNodes }
119
+ : {}),
120
+ ...(Number.isFinite(cfg.maxTools) ? { maxTools: cfg.maxTools } : {}),
121
+ ...(Number.isFinite(cfg.maxToolDescriptionBytes)
122
+ ? { maxToolDescriptionBytes: cfg.maxToolDescriptionBytes }
123
+ : {}),
124
+ ...(Number.isFinite(cfg.maxToolSchemaBytes)
125
+ ? { maxToolSchemaBytes: cfg.maxToolSchemaBytes }
126
+ : {}),
127
+ ...(Number.isFinite(cfg.maxToolSchemaDepth)
128
+ ? { maxToolSchemaDepth: cfg.maxToolSchemaDepth }
129
+ : {}),
130
+ ...(Number.isFinite(cfg.maxToolSchemaNodes)
131
+ ? { maxToolSchemaNodes: cfg.maxToolSchemaNodes }
132
+ : {}),
133
+ ...(Number.isFinite(cfg.maxToolDefinitionBytes)
134
+ ? { maxToolDefinitionBytes: cfg.maxToolDefinitionBytes }
135
+ : {}),
136
+ ...(Number.isFinite(cfg.maxToolMetadataBytes)
137
+ ? { maxToolMetadataBytes: cfg.maxToolMetadataBytes }
138
+ : {}),
139
+ ...(Number.isFinite(cfg.maxToolResultBytes)
140
+ ? { maxToolResultBytes: cfg.maxToolResultBytes }
141
+ : {}),
142
+ ...(Number.isFinite(cfg.maxToolResultDepth)
143
+ ? { maxToolResultDepth: cfg.maxToolResultDepth }
144
+ : {}),
145
+ ...(Number.isFinite(cfg.maxToolResultNodes)
146
+ ? { maxToolResultNodes: cfg.maxToolResultNodes }
147
+ : {}),
67
148
  ...headersHelperField(cfg.headersHelper),
68
149
  ...(cfg.configScope ? { configScope: cfg.configScope } : {}),
69
150
  ...(cfg.configSource ? { configSource: cfg.configSource } : {}),
@@ -83,6 +164,12 @@ export async function loadManagedMcp(settings, deps = {}) {
83
164
  config.configScope = "managed";
84
165
  config.configSource = deps.managedFile || "managed-settings";
85
166
  }
167
+ authorizeStdioServers(
168
+ servers,
169
+ "managed-settings",
170
+ (_name, config) => config.configSource,
171
+ { writeErr: deps.writeErr },
172
+ );
86
173
  if (Object.keys(servers).length === 0) return deps.into || null;
87
174
  (deps.writeErr || (() => {}))(
88
175
  ` mcp: ${Object.keys(servers).length} managed server(s) from ${deps.managedFile || "managed settings"}\n`,
@@ -210,6 +297,9 @@ export async function setupMcpFromConfig(servers, deps = {}) {
210
297
  ) {
211
298
  result.instructionsByServer = {};
212
299
  }
300
+ if (!Number.isSafeInteger(result._mcpToolMetadataBytes)) {
301
+ result._mcpToolMetadataBytes = 0;
302
+ }
213
303
  const {
214
304
  mcpClient,
215
305
  extraToolDefinitions,
@@ -290,7 +380,18 @@ export async function setupMcpFromConfig(servers, deps = {}) {
290
380
  writeErr(line);
291
381
  continue;
292
382
  }
293
- const tools = Array.isArray(res?.tools) ? res.tools : [];
383
+ let tools = [];
384
+ let toolMetadataError = null;
385
+ try {
386
+ const admitted = admitMcpToolList(name, res?.tools ?? [], cfg, {
387
+ clientBytesUsed: result._mcpToolMetadataBytes,
388
+ });
389
+ tools = admitted.tools;
390
+ result._mcpToolMetadataBytes += admitted.metadataBytes;
391
+ } catch (error) {
392
+ if (!isMcpToolMetadataError(error)) throw error;
393
+ toolMetadataError = error;
394
+ }
294
395
  const resources = Array.isArray(res?.resources) ? res.resources : [];
295
396
  const prompts = Array.isArray(res?.prompts) ? res.prompts : [];
296
397
  // A server can connect (initialize OK) yet have its tools/list fail — the
@@ -304,6 +405,11 @@ export async function setupMcpFromConfig(servers, deps = {}) {
304
405
  if (hint) line += hint;
305
406
  writeErr(line);
306
407
  }
408
+ if (toolMetadataError) {
409
+ writeErr(
410
+ ` mcp: "${name}" connected but tool metadata was rejected: ${toolMetadataError.message}\n`,
411
+ );
412
+ }
307
413
  connected.push({
308
414
  server: name,
309
415
  tools: tools.length,
@@ -321,6 +427,18 @@ export async function setupMcpFromConfig(servers, deps = {}) {
321
427
  if (!p || !p.name) continue;
322
428
  result.prompts.push({ ...p, server: name });
323
429
  }
430
+ const toolResultConfig = Object.freeze({
431
+ ...(Number.isFinite(cfg.maxToolResultBytes)
432
+ ? { maxToolResultBytes: cfg.maxToolResultBytes }
433
+ : {}),
434
+ ...(Number.isFinite(cfg.maxToolResultDepth)
435
+ ? { maxToolResultDepth: cfg.maxToolResultDepth }
436
+ : {}),
437
+ ...(Number.isFinite(cfg.maxToolResultNodes)
438
+ ? { maxToolResultNodes: cfg.maxToolResultNodes }
439
+ : {}),
440
+ });
441
+ const hasToolResultConfig = Object.keys(toolResultConfig).length > 0;
324
442
  for (const t of tools) {
325
443
  if (!t || !t.name) continue;
326
444
  const full = mcpToolName(name, t.name);
@@ -337,6 +455,7 @@ export async function setupMcpFromConfig(servers, deps = {}) {
337
455
  kind: "mcp",
338
456
  serverName: name,
339
457
  toolName: t.name,
458
+ ...(hasToolResultConfig ? { toolResultConfig } : {}),
340
459
  };
341
460
  externalToolDescriptors[full] = {
342
461
  name: full,
@@ -510,6 +629,12 @@ export async function loadMcpConfig(filePath, deps = {}) {
510
629
  `(expected {"mcpServers": {"name": {"command": "..."}}}).`,
511
630
  );
512
631
  }
632
+ authorizeStdioServers(
633
+ servers,
634
+ "explicit-config",
635
+ () => path.resolve(filePath),
636
+ { failFast: true },
637
+ );
513
638
  return setupMcpFromConfig(servers, deps);
514
639
  }
515
640
 
@@ -555,6 +680,13 @@ export async function loadRegisteredMcp(rawDb, deps = {}) {
555
680
  };
556
681
  }
557
682
  if (Object.keys(servers).length === 0) return deps.into || null;
683
+ authorizeStdioServers(
684
+ servers,
685
+ "registered-config",
686
+ (name, config) =>
687
+ `${config.configScope || "user"}:${config.configSource || "user-database"}:${name}`,
688
+ { writeErr: deps.writeErr },
689
+ );
558
690
  return setupMcpFromConfig(servers, deps);
559
691
  }
560
692
 
@@ -786,14 +918,16 @@ export async function loadProjectMcp(opts = {}, deps = {}) {
786
918
  config.configScope = "project";
787
919
  config.configSource = file;
788
920
  config.projectPath = path.dirname(file);
789
- if (config.headersHelper) {
790
- if (typeof trust.issueProjectMcpWorkspaceAuthority !== "function") {
791
- writeErr(
792
- ` mcp: SKIPPING project headersHelper "${name}" — project execution authority is unavailable.\n`,
793
- );
794
- delete parsed[name];
795
- continue;
796
- }
921
+ const needsExecutionAuthority =
922
+ config.headersHelper || inferTransport(config) === "stdio";
923
+ if (
924
+ needsExecutionAuthority &&
925
+ typeof trust.issueProjectMcpWorkspaceAuthority !== "function"
926
+ ) {
927
+ delete parsed[name];
928
+ continue;
929
+ }
930
+ if (needsExecutionAuthority) {
797
931
  config.projectMcpWorkspaceAuthority =
798
932
  trust.issueProjectMcpWorkspaceAuthority({
799
933
  file,
@@ -813,6 +947,12 @@ export async function loadProjectMcp(opts = {}, deps = {}) {
813
947
  ` mcp: ${Object.keys(servers).length} server(s) from project .mcp.json ` +
814
948
  `(${seenFiles.join(", ")}) — loaded via --project-mcp\n`,
815
949
  );
950
+ authorizeStdioServers(
951
+ servers,
952
+ "project-config",
953
+ (name, config) => `${config.configSource}:${name}`,
954
+ { writeErr },
955
+ );
816
956
  return setupMcpFromConfig(servers, deps);
817
957
  }
818
958
 
@@ -856,6 +996,13 @@ export async function loadPluginMcp(opts = {}, deps = {}) {
856
996
  writeErr(
857
997
  ` mcp: ${names.length} server(s) from trusted plugin(s): ${names.join(", ")}\n`,
858
998
  );
999
+ authorizeStdioServers(
1000
+ servers,
1001
+ "trusted-plugin",
1002
+ (name, config) =>
1003
+ `${config.pluginId || "plugin"}@${config.pluginVersion || "unknown"}:${config.pluginSource || "unknown"}:${name}`,
1004
+ { writeErr },
1005
+ );
859
1006
  return setupMcpFromConfig(servers, deps);
860
1007
  }
861
1008
 
Binary file
@@ -0,0 +1,419 @@
1
+ import { Buffer } from "node:buffer";
2
+
3
+ const DEFAULT_MAX_QUEUED_BYTES = 1024 * 1024;
4
+ const HOST_OUTPUT_DRAIN_TIMEOUT_MS = 30_000;
5
+
6
+ function normalizeDrainTimeoutMs(value) {
7
+ return Number.isFinite(value) &&
8
+ value > 0 &&
9
+ value <= HOST_OUTPUT_DRAIN_TIMEOUT_MS
10
+ ? Math.max(1, Math.floor(value))
11
+ : HOST_OUTPUT_DRAIN_TIMEOUT_MS;
12
+ }
13
+
14
+ function outputError(code, message, details = {}) {
15
+ const error = new Error(message);
16
+ error.code = code;
17
+ error.isOutputBackpressureFailure = true;
18
+ Object.assign(error, details);
19
+ return error;
20
+ }
21
+
22
+ function chunkBytes(chunk, encoding) {
23
+ if (Buffer.isBuffer(chunk) || ArrayBuffer.isView(chunk)) {
24
+ return chunk.byteLength;
25
+ }
26
+ return Buffer.byteLength(String(chunk), encoding || "utf8");
27
+ }
28
+
29
+ /**
30
+ * Honor Writable.write(false) without forcing every existing output call site
31
+ * to become async. Once the native stream applies backpressure, later chunks
32
+ * stay in a bounded host queue until `drain`; producers await `wait()` at their
33
+ * event boundaries, so model/input consumption stops instead of growing the
34
+ * native Writable queue without limit.
35
+ */
36
+ export function createWritableBackpressureGate(
37
+ stream,
38
+ {
39
+ label = "output",
40
+ maxQueuedBytes = DEFAULT_MAX_QUEUED_BYTES,
41
+ drainTimeoutMs,
42
+ onFailure = null,
43
+ } = {},
44
+ ) {
45
+ if (!stream || typeof stream.write !== "function") {
46
+ throw new TypeError(`${label} must be a writable stream`);
47
+ }
48
+ // Capture the native writer before a caller optionally installs this gate as
49
+ // `stream.write`. Looking it up dynamically would recurse after installation.
50
+ const nativeWrite = stream.write.bind(stream);
51
+ const queueLimit =
52
+ Number.isSafeInteger(maxQueuedBytes) && maxQueuedBytes > 0
53
+ ? maxQueuedBytes
54
+ : DEFAULT_MAX_QUEUED_BYTES;
55
+ const queue = [];
56
+ const outputDrainTimeoutMs = normalizeDrainTimeoutMs(drainTimeoutMs);
57
+ let queuedBytes = 0;
58
+ let blocked = false;
59
+ let failure = null;
60
+ let waitPromise = null;
61
+ let resolveWait = null;
62
+ let rejectWait = null;
63
+ let disposed = false;
64
+ let backpressureCount = 0;
65
+ let drainTimer = null;
66
+ let blockedAt = null;
67
+
68
+ const clearDrainDeadline = () => {
69
+ if (drainTimer !== null) clearTimeout(drainTimer);
70
+ drainTimer = null;
71
+ blockedAt = null;
72
+ };
73
+
74
+ const notifyCallback = (callback, error) => {
75
+ if (typeof callback !== "function") return;
76
+ queueMicrotask(() => {
77
+ try {
78
+ callback(error);
79
+ } catch {
80
+ // A write callback is observational and cannot replace gate failure.
81
+ }
82
+ });
83
+ };
84
+
85
+ const ensureWait = () => {
86
+ if (waitPromise) return;
87
+ waitPromise = new Promise((resolve, reject) => {
88
+ resolveWait = resolve;
89
+ rejectWait = reject;
90
+ });
91
+ // A caller may rely only on event-driven writes (for example a coalescer
92
+ // timer) and observe the failure later. Mark the promise handled now while
93
+ // preserving rejection for every explicit `wait()` caller.
94
+ waitPromise.catch(() => {});
95
+ };
96
+ const finishWait = () => {
97
+ clearDrainDeadline();
98
+ const resolve = resolveWait;
99
+ waitPromise = null;
100
+ resolveWait = null;
101
+ rejectWait = null;
102
+ resolve?.();
103
+ };
104
+ const fail = (error) => {
105
+ if (failure) return;
106
+ clearDrainDeadline();
107
+ failure = error;
108
+ blocked = false;
109
+ const discarded = queue.splice(0);
110
+ queuedBytes = 0;
111
+ for (const entry of discarded) notifyCallback(entry.callback, error);
112
+ ensureWait();
113
+ rejectWait?.(error);
114
+ try {
115
+ onFailure?.(error);
116
+ } catch {
117
+ // Failure notification must never replace the original stream error.
118
+ }
119
+ };
120
+ const startDrainDeadline = () => {
121
+ if (drainTimer !== null || failure || disposed) return;
122
+ blockedAt = Date.now();
123
+ drainTimer = setTimeout(() => {
124
+ const elapsedMs = Math.max(0, Date.now() - blockedAt);
125
+ fail(
126
+ outputError(
127
+ "CC_OUTPUT_BACKPRESSURE_TIMEOUT",
128
+ `${label} did not drain within ${outputDrainTimeoutMs} ms`,
129
+ {
130
+ timeoutMs: outputDrainTimeoutMs,
131
+ elapsedMs,
132
+ queuedBytes,
133
+ queuedChunks: queue.length,
134
+ },
135
+ ),
136
+ );
137
+ }, outputDrainTimeoutMs);
138
+ };
139
+ const writeNative = (chunk, encoding, callback) => {
140
+ let accepted;
141
+ try {
142
+ accepted =
143
+ typeof callback === "function"
144
+ ? encoding != null
145
+ ? nativeWrite(chunk, encoding, callback)
146
+ : nativeWrite(chunk, callback)
147
+ : encoding != null
148
+ ? nativeWrite(chunk, encoding)
149
+ : nativeWrite(chunk);
150
+ } catch (error) {
151
+ const wrapped = outputError(
152
+ error?.code === "EPIPE" ? "EPIPE" : "CC_OUTPUT_STREAM_ERROR",
153
+ `${label} write failed: ${error?.message || error}`,
154
+ { cause: error },
155
+ );
156
+ notifyCallback(callback, wrapped);
157
+ fail(wrapped);
158
+ return false;
159
+ }
160
+ if (accepted === false) {
161
+ blocked = true;
162
+ backpressureCount += 1;
163
+ ensureWait();
164
+ startDrainDeadline();
165
+ }
166
+ return accepted !== false;
167
+ };
168
+ const onDrain = () => {
169
+ if (disposed || failure) return;
170
+ blocked = false;
171
+ while (queue.length > 0 && !blocked && !failure) {
172
+ const entry = queue.shift();
173
+ queuedBytes -= entry.bytes;
174
+ writeNative(entry.chunk, entry.encoding, entry.callback);
175
+ }
176
+ if (!blocked && queue.length === 0 && !failure) finishWait();
177
+ };
178
+ const onError = (cause) => {
179
+ fail(
180
+ outputError(
181
+ cause?.code === "EPIPE" ? "EPIPE" : "CC_OUTPUT_STREAM_ERROR",
182
+ `${label} stream failed: ${cause?.message || cause}`,
183
+ { cause },
184
+ ),
185
+ );
186
+ };
187
+
188
+ stream.on?.("drain", onDrain);
189
+ stream.on?.("error", onError);
190
+
191
+ return {
192
+ write(chunk, encoding, callback) {
193
+ if (typeof encoding === "function") {
194
+ callback = encoding;
195
+ encoding = undefined;
196
+ }
197
+ if (disposed || failure) {
198
+ notifyCallback(
199
+ callback,
200
+ failure ||
201
+ outputError(
202
+ "CC_OUTPUT_BACKPRESSURE_DISPOSED",
203
+ `${label} is no longer writable`,
204
+ ),
205
+ );
206
+ return false;
207
+ }
208
+ if (!blocked && queue.length === 0) {
209
+ return writeNative(chunk, encoding, callback);
210
+ }
211
+
212
+ const bytes = chunkBytes(chunk, encoding);
213
+ if (queuedBytes + bytes > queueLimit) {
214
+ const overflow = outputError(
215
+ "CC_OUTPUT_BACKPRESSURE_OVERFLOW",
216
+ `${label} backpressure queue exceeded ${queueLimit} bytes`,
217
+ { queuedBytes, incomingBytes: bytes, maxQueuedBytes: queueLimit },
218
+ );
219
+ notifyCallback(callback, overflow);
220
+ fail(overflow);
221
+ return false;
222
+ }
223
+ queue.push({ chunk, encoding, callback, bytes });
224
+ queuedBytes += bytes;
225
+ ensureWait();
226
+ return false;
227
+ },
228
+ async wait() {
229
+ if (failure) throw failure;
230
+ if (blocked || queue.length > 0) {
231
+ ensureWait();
232
+ await waitPromise;
233
+ }
234
+ if (failure) throw failure;
235
+ },
236
+ snapshot() {
237
+ return Object.freeze({
238
+ label,
239
+ blocked,
240
+ queuedBytes,
241
+ queuedChunks: queue.length,
242
+ backpressureCount,
243
+ drainTimeoutMs: outputDrainTimeoutMs,
244
+ blockedForMs:
245
+ blockedAt === null ? 0 : Math.max(0, Date.now() - blockedAt),
246
+ failed: failure != null,
247
+ failureCode: failure?.code || null,
248
+ });
249
+ },
250
+ dispose() {
251
+ if (disposed) return;
252
+ disposed = true;
253
+ stream.removeListener?.("drain", onDrain);
254
+ stream.removeListener?.("error", onError);
255
+ if (!failure && (blocked || queue.length > 0)) {
256
+ fail(
257
+ outputError(
258
+ "CC_OUTPUT_BACKPRESSURE_DISPOSED",
259
+ `${label} disposed before queued output drained`,
260
+ ),
261
+ );
262
+ }
263
+ },
264
+ };
265
+ }
266
+
267
+ /**
268
+ * Install a gate directly on a Writable's `write` method. This is intended for
269
+ * readline/TTY owners whose transitive writers all hold the same stream object
270
+ * and cannot each be converted to an async writer. The original method shape
271
+ * is restored exactly when `restore()` runs.
272
+ */
273
+ export function installWritableBackpressureGate(stream, options = {}) {
274
+ const hadOwnWrite = Object.prototype.hasOwnProperty.call(stream, "write");
275
+ const ownWriteDescriptor = hadOwnWrite
276
+ ? Object.getOwnPropertyDescriptor(stream, "write")
277
+ : null;
278
+ const gate = createWritableBackpressureGate(stream, options);
279
+ const installedWrite = (chunk, encoding, callback) =>
280
+ gate.write(chunk, encoding, callback);
281
+ try {
282
+ Object.defineProperty(stream, "write", {
283
+ configurable: true,
284
+ enumerable: ownWriteDescriptor?.enumerable ?? false,
285
+ writable: true,
286
+ value: installedWrite,
287
+ });
288
+ } catch (cause) {
289
+ gate.dispose();
290
+ throw outputError(
291
+ "CC_OUTPUT_BACKPRESSURE_INSTALL_FAILED",
292
+ `${options.label || "output"} write method cannot be gated`,
293
+ { cause },
294
+ );
295
+ }
296
+
297
+ let restored = false;
298
+ return {
299
+ wait: gate.wait,
300
+ snapshot: gate.snapshot,
301
+ restore() {
302
+ if (restored) return;
303
+ restored = true;
304
+ if (stream.write === installedWrite) {
305
+ if (hadOwnWrite) {
306
+ Object.defineProperty(stream, "write", ownWriteDescriptor);
307
+ } else {
308
+ Reflect.deleteProperty(stream, "write");
309
+ }
310
+ }
311
+ gate.dispose();
312
+ },
313
+ };
314
+ }
315
+
316
+ /** Install coordinated gates on stdout and stderr for a long-lived TTY owner. */
317
+ export function installOutputBackpressure({
318
+ stdout = process.stdout,
319
+ stderr = process.stderr,
320
+ maxQueuedBytes,
321
+ drainTimeoutMs,
322
+ onFailure,
323
+ } = {}) {
324
+ if (stdout === stderr) {
325
+ const shared = installWritableBackpressureGate(stdout, {
326
+ label: "output",
327
+ maxQueuedBytes,
328
+ drainTimeoutMs,
329
+ onFailure,
330
+ });
331
+ return {
332
+ wait: shared.wait,
333
+ snapshot: () => {
334
+ const current = shared.snapshot();
335
+ return { stdout: current, stderr: current };
336
+ },
337
+ restore: shared.restore,
338
+ };
339
+ }
340
+ const out = installWritableBackpressureGate(stdout, {
341
+ label: "stdout",
342
+ maxQueuedBytes,
343
+ drainTimeoutMs,
344
+ onFailure,
345
+ });
346
+ let err;
347
+ try {
348
+ err = installWritableBackpressureGate(stderr, {
349
+ label: "stderr",
350
+ maxQueuedBytes,
351
+ drainTimeoutMs,
352
+ onFailure,
353
+ });
354
+ } catch (error) {
355
+ out.restore();
356
+ throw error;
357
+ }
358
+ let restored = false;
359
+ return {
360
+ wait: () => Promise.all([out.wait(), err.wait()]),
361
+ snapshot: () => ({ stdout: out.snapshot(), stderr: err.snapshot() }),
362
+ restore() {
363
+ if (restored) return;
364
+ restored = true;
365
+ out.restore();
366
+ err.restore();
367
+ },
368
+ };
369
+ }
370
+
371
+ function injectedWriter(write) {
372
+ return {
373
+ write,
374
+ wait: async () => {},
375
+ snapshot: () => null,
376
+ dispose: () => {},
377
+ };
378
+ }
379
+
380
+ /** Create one coordinator for stdout and stderr. */
381
+ export function createHeadlessOutputBackpressure({
382
+ stdout = process.stdout,
383
+ stderr = process.stderr,
384
+ writeOut = null,
385
+ writeErr = null,
386
+ maxQueuedBytes,
387
+ drainTimeoutMs,
388
+ onFailure,
389
+ } = {}) {
390
+ const out = writeOut
391
+ ? injectedWriter(writeOut)
392
+ : createWritableBackpressureGate(stdout, {
393
+ label: "stdout",
394
+ maxQueuedBytes,
395
+ drainTimeoutMs,
396
+ onFailure,
397
+ });
398
+ const err = writeErr
399
+ ? injectedWriter(writeErr)
400
+ : createWritableBackpressureGate(stderr, {
401
+ label: "stderr",
402
+ maxQueuedBytes,
403
+ drainTimeoutMs,
404
+ onFailure,
405
+ });
406
+
407
+ return {
408
+ writeOut: (chunk, encoding) => out.write(chunk, encoding),
409
+ writeErr: (chunk, encoding) => err.write(chunk, encoding),
410
+ wait: () => Promise.all([out.wait(), err.wait()]),
411
+ snapshot: () => ({ stdout: out.snapshot(), stderr: err.snapshot() }),
412
+ dispose() {
413
+ out.dispose();
414
+ err.dispose();
415
+ },
416
+ };
417
+ }
418
+
419
+ export const MAX_OUTPUT_DRAIN_TIMEOUT_MS = HOST_OUTPUT_DRAIN_TIMEOUT_MS;