very-happy-cli 0.2.175 → 0.2.177

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 (185) hide show
  1. package/dist/{AcpBackend-Sb6N_HcB.cjs → AcpBackend-B-ny68XM.cjs} +188 -37
  2. package/dist/{AcpBackend-BZrLVcHb.mjs → AcpBackend-B0K0WrtW.mjs} +187 -38
  3. package/dist/{AcpSessionManager-C2MqOirs.cjs → AcpSessionManager-CjdJLofq.cjs} +1 -1
  4. package/dist/{AcpSessionManager-y1Iy1mzc.mjs → AcpSessionManager-DykjzBM4.mjs} +1 -1
  5. package/dist/{BasePermissionHandler-BbLYwd13.cjs → BasePermissionHandler-DR6nxuEn.cjs} +1 -1
  6. package/dist/{BasePermissionHandler-DriZLITp.mjs → BasePermissionHandler-hdY7kTqX.mjs} +1 -1
  7. package/dist/{agentHome-BoYfpemd.cjs → agentHome-BdTXEUPe.cjs} +4 -4
  8. package/dist/{agentHome-BtuRubHG.mjs → agentHome-GRN2VfHv.mjs} +4 -4
  9. package/dist/{api-KZmVqSKO.cjs → api-BWX10o97.cjs} +17 -10
  10. package/dist/{api-D08IEaWa.mjs → api-CKBViqI3.mjs} +18 -11
  11. package/dist/{apiMachine-Dct2GDAq.cjs → apiMachine-BYYFGgFs.cjs} +15 -14
  12. package/dist/{apiMachine-Cx9Zn-78.mjs → apiMachine-DttO4UFj.mjs} +15 -14
  13. package/dist/{attachmentContent-PrNJg8gG.mjs → attachmentContent-cPVF463_.mjs} +2 -2
  14. package/dist/{attachmentContent-4L9dO8E3.cjs → attachmentContent-kJKXpkMX.cjs} +2 -2
  15. package/dist/{attachmentLimits-BLbji11b.mjs → attachmentLimits-Di1Z93lN.mjs} +1 -1
  16. package/dist/{attachmentLimits-D6bT2jU1.cjs → attachmentLimits-DtFqqiwR.cjs} +1 -1
  17. package/dist/{auth-D1qHU-i_.mjs → auth-BmESeKuM.mjs} +5 -5
  18. package/dist/{auth-PY_HGlzz.mjs → auth-CKdXb9zp.mjs} +8 -8
  19. package/dist/{auth-BGmM3Vlm.cjs → auth-CTECt2Oz.cjs} +5 -5
  20. package/dist/{auth-BI0CsMcy.cjs → auth-DNxVmVbn.cjs} +8 -8
  21. package/dist/{auto-COMphIfD.mjs → auto-Ch3203qd.mjs} +17 -16
  22. package/dist/{auto-DM4_FeKb.cjs → auto-D1ypjjfx.cjs} +16 -15
  23. package/dist/{backgroundTaskActivity-8PdPxrvy.mjs → backgroundTaskActivity-BVwJBl02.mjs} +1 -1
  24. package/dist/{bootstrap-DTJ6-vYT.cjs → bootstrap-6OI698q9.cjs} +2 -2
  25. package/dist/{bootstrap-CWjpC5-J.mjs → bootstrap-C0s2bPFQ.mjs} +2 -2
  26. package/dist/{browser-xuW4fiHo.mjs → browser-BlLWZUMx.mjs} +1 -1
  27. package/dist/{browser-DmgVoopB.cjs → browser-DG6Uof5O.cjs} +1 -1
  28. package/dist/{claudeLocal-B0P-wVJJ.mjs → claudeLocal-CcWcKnoo.mjs} +5 -5
  29. package/dist/{claudeLocal-CtZVz3ee.cjs → claudeLocal-CemsIArT.cjs} +5 -5
  30. package/dist/{claudeLocalLauncher-D4vmjI3c.mjs → claudeLocalLauncher-7p6y88nj.mjs} +15 -18
  31. package/dist/{claudeLocalLauncher-Dnv4CH8r.cjs → claudeLocalLauncher-A4VuevIi.cjs} +15 -18
  32. package/dist/{claudeSessionFork-CxjOBoBh.mjs → claudeSessionFork-BtROOjqf.mjs} +1 -1
  33. package/dist/{claudeSessionFork-DQk5-dzR.cjs → claudeSessionFork-CbDfm8Fz.cjs} +1 -1
  34. package/dist/{client-eQjOvC55.mjs → client-BPMWutfs.mjs} +3 -3
  35. package/dist/{client-BhLhjj_x.cjs → client-COmgDDy0.cjs} +2 -2
  36. package/dist/{client-C4ddTzrD.mjs → client-DG5ndWLw.mjs} +2 -2
  37. package/dist/{client-BHZVyQwi.cjs → client-DyvBTYee.cjs} +3 -3
  38. package/dist/codex/happyMcpStdioBridge.cjs +15 -15
  39. package/dist/codex/happyMcpStdioBridge.mjs +16 -16
  40. package/dist/{codexAppServerClient-CppPl_R6.mjs → codexAppServerClient-D-Z8qSfI.mjs} +233 -24
  41. package/dist/{codexAppServerClient-D-9z-lWP.cjs → codexAppServerClient-R24WZZfg.cjs} +233 -24
  42. package/dist/{codexCommand-AgVJYnFU.cjs → codexCommand-6hW19gsq.cjs} +159 -84
  43. package/dist/{codexCommand-BdrBNbZu.mjs → codexCommand-CVTkZJ1o.mjs} +158 -83
  44. package/dist/{BaseReasoningProcessor-_S1PbSvH.cjs → codexTermination-BBU7e92y.cjs} +25 -1
  45. package/dist/{BaseReasoningProcessor-DnykPlPo.mjs → codexTermination-CCIfwzcx.mjs} +25 -2
  46. package/dist/{config-Cr3VUzbE.mjs → config-CvsNChKX.mjs} +3 -3
  47. package/dist/{config-D89sE3wK.cjs → config-DhdrvOLV.cjs} +3 -3
  48. package/dist/{configuration-BNGPXg07.mjs → configuration-D55F0t16.mjs} +1 -1
  49. package/dist/{configuration-UV4EE5ui.cjs → configuration-DZPy0T9Z.cjs} +1 -1
  50. package/dist/{connect-C0iLkCiY.mjs → connect-CwCXMRmD.mjs} +14 -14
  51. package/dist/{connect-B35YXbdZ.cjs → connect-Wz-XZYXW.cjs} +13 -13
  52. package/dist/{context-BmH2BKip.cjs → context-BKbrZ55r.cjs} +1 -1
  53. package/dist/{context-Ptdnlcv6.mjs → context-CCRpVXFo.mjs} +1 -1
  54. package/dist/{controlClient-DqtC0pq1.mjs → controlClient-C4xB5J6O.mjs} +4 -4
  55. package/dist/{controlClient-CtsQMw--.cjs → controlClient-SX8gSza2.cjs} +3 -3
  56. package/dist/{createSessionMetadata-2IuH5nlA.cjs → createSessionMetadata-BCFmYlBo.cjs} +2 -2
  57. package/dist/{createSessionMetadata-CtNMvfth.mjs → createSessionMetadata-Bi-m0Y_O.mjs} +2 -2
  58. package/dist/{defaultPermissionMode-Bn4HcU8S.cjs → defaultPermissionMode-DMBEnXll.cjs} +2 -2
  59. package/dist/{defaultPermissionMode-DYihjV2g.mjs → defaultPermissionMode-wBcbBezm.mjs} +2 -2
  60. package/dist/{deterministicJson-DF4xv6MH.mjs → deterministicJson-BkQETt8_.mjs} +9 -9
  61. package/dist/{deterministicJson-je21npNx.cjs → deterministicJson-ChGfQEF6.cjs} +9 -9
  62. package/dist/{doctor-Ba92L7-b.mjs → doctor-B9c2C9dF.mjs} +8 -8
  63. package/dist/{doctor-BXKcYVGU.cjs → doctor-BsN3JZJn.cjs} +7 -7
  64. package/dist/{downloadTarget-CUJg8iJV.mjs → downloadTarget-ByXzbDK4.mjs} +6 -6
  65. package/dist/{downloadTarget-JC7FZl7W.cjs → downloadTarget-Dj3WoVJa.cjs} +6 -6
  66. package/dist/{ensureDaemonRunning-JPA9tHNE.mjs → ensureDaemonRunning--HYzs5Ce.mjs} +5 -5
  67. package/dist/{ensureDaemonRunning-bIp6-vgi.cjs → ensureDaemonRunning-7Wb8M7Lv.cjs} +5 -5
  68. package/dist/{handleResumeCommand-B6lE5DtU.mjs → handleResumeCommand-DHddBkNJ.mjs} +5 -5
  69. package/dist/{handleResumeCommand-B6b9kIYf.cjs → handleResumeCommand-OmuUGYjQ.cjs} +5 -5
  70. package/dist/{index-B2KL0aPc.cjs → index-BRJzH4sc.cjs} +141 -87
  71. package/dist/{index-CjE4kBKx.mjs → index-BzJNDsJq.mjs} +143 -89
  72. package/dist/{index-B6UGRQ7h.mjs → index-CEjJnq05.mjs} +3 -0
  73. package/dist/{index-CZLwo1FS.mjs → index-CEm0MYiS.mjs} +3 -3
  74. package/dist/{index-B1ABQRrB.cjs → index-CrR4JISa.cjs} +4 -4
  75. package/dist/{index-D759ViMU.cjs → index-D9NoYc5I.cjs} +3 -3
  76. package/dist/{index-D3kI0hDR.cjs → index-DFPT4HOO.cjs} +3 -0
  77. package/dist/{index-boE-d8CM.mjs → index-DMy3OCBe.mjs} +8 -1
  78. package/dist/{index-BZdhwBKa.cjs → index-De8L5lFK.cjs} +8 -0
  79. package/dist/{index-DW1ONaGc.mjs → index-Dhl6_bw7.mjs} +4 -4
  80. package/dist/index.cjs +2 -2
  81. package/dist/index.mjs +2 -2
  82. package/dist/{install-KjIsK_EA.cjs → install-1qn-D9FS.cjs} +3 -3
  83. package/dist/{install-CmojqnLK.mjs → install-BDIUtPXi.mjs} +3 -3
  84. package/dist/lib.cjs +12 -12
  85. package/dist/lib.d.cts +7 -1
  86. package/dist/lib.d.mts +7 -1
  87. package/dist/lib.mjs +13 -13
  88. package/dist/{lidState-CL1NdKfQ.mjs → lidState-BqVsw7H1.mjs} +1 -1
  89. package/dist/{lidState-BmJp2pLt.cjs → lidState-DxbK0qfu.cjs} +1 -1
  90. package/dist/{localHappyAgentAuth-B7f4Ysn0.mjs → localHappyAgentAuth-Ce8kO2yc.mjs} +1 -1
  91. package/dist/{localHappyAgentAuth-9SP7hdiw.cjs → localHappyAgentAuth-D5tANdRD.cjs} +1 -1
  92. package/dist/{logger-D5EzMy30.mjs → logger-13cBr_ew.mjs} +2 -2
  93. package/dist/{logger-C7dRaCkE.cjs → logger-LvwVeATU.cjs} +2 -2
  94. package/dist/{machineMetadata-DYYuK_0c.cjs → machineMetadata-29h7vgf4.cjs} +3 -3
  95. package/dist/{machineMetadata-DqplCWue.mjs → machineMetadata-dMida2qq.mjs} +3 -3
  96. package/dist/{main-kgCQgknK.cjs → main-DpM5jaFH.cjs} +44 -44
  97. package/dist/{main-CnV62agu.mjs → main-x4nAhdH5.mjs} +44 -44
  98. package/dist/{mcp-bDPaj-tM.mjs → mcp-DMiFGYMT.mjs} +15 -15
  99. package/dist/{mcp-BV0vxHtz.cjs → mcp-DQv3caXs.cjs} +14 -14
  100. package/dist/{mirrorProtocol-BSHVZ8Nf.cjs → mirrorProtocol-BfrERW7Z.cjs} +3 -3
  101. package/dist/{mirrorProtocol-ClKhNXYe.mjs → mirrorProtocol-Bz8tEabR.mjs} +3 -3
  102. package/dist/{package-VqWv7EI5.cjs → package-Ch9WGDV_.cjs} +7 -7
  103. package/dist/{package-D0dxZ-W8.mjs → package-CjlsAaRe.mjs} +7 -7
  104. package/dist/{peerTools-B_eiNB3P.mjs → peerTools-CxmrKnfV.mjs} +4 -4
  105. package/dist/{peerTools-BktGmlpd.cjs → peerTools-DtGKWli5.cjs} +4 -4
  106. package/dist/{persistence-CIIhP0Uw.mjs → persistence-C_tYtOqK.mjs} +2 -2
  107. package/dist/{persistence-DweHi8xa.cjs → persistence-DXbKOHxl.cjs} +2 -2
  108. package/dist/{piRunnerArgs-BNzWTNRV.cjs → piRunnerArgs-BVRZe2AR.cjs} +1 -1
  109. package/dist/{piRunnerArgs-cQafsadv.mjs → piRunnerArgs-BpHc-JZl.mjs} +1 -1
  110. package/dist/{piRuntime-VZLSwW-4.cjs → piRuntime-D7eio8Ix.cjs} +1 -1
  111. package/dist/{piRuntime-Bel5lOLb.mjs → piRuntime-DOdGF395.mjs} +1 -1
  112. package/dist/{piTerminal-CS5SDi_H.mjs → piTerminal-dpxz4Q8D.mjs} +17 -17
  113. package/dist/{piTerminal-DkR8sPv-.cjs → piTerminal-y_PRo2NY.cjs} +16 -16
  114. package/dist/processTree-CMHWlVse.cjs +66 -0
  115. package/dist/processTree-CP5IvQ2Z.mjs +61 -0
  116. package/dist/{rateLimitWindows-Bp4T21RI.cjs → rateLimitWindows-DFnMU2Vt.cjs} +1 -1
  117. package/dist/{rateLimitWindows-Bo6XVnie.mjs → rateLimitWindows-DYHDGuzQ.mjs} +1 -1
  118. package/dist/{registerCommonHandlers-B7QZxkCL.cjs → registerCommonHandlers-60VuTkdg.cjs} +2 -2
  119. package/dist/{registerCommonHandlers-CR5jpiSx.mjs → registerCommonHandlers-D8OMpBbQ.mjs} +2 -2
  120. package/dist/{registerKillSessionHandler-DLiu24CQ.mjs → registerKillSessionHandler-Drhf7-Vz.mjs} +6 -6
  121. package/dist/{registerKillSessionHandler-CcX84g-T.cjs → registerKillSessionHandler-pqChBKwO.cjs} +6 -6
  122. package/dist/{remoteSessionClient-CL3akj0K.cjs → remoteSessionClient-B7NvjHD3.cjs} +5 -5
  123. package/dist/{remoteSessionClient-CUjw1COc.mjs → remoteSessionClient-D01Hso2-.mjs} +5 -5
  124. package/dist/{reportProgressTool-BLLwMQrN.mjs → reportProgressTool-B203EZCR.mjs} +2 -2
  125. package/dist/{reportProgressTool-DzMi4mvH.cjs → reportProgressTool-Du_zAK4h.cjs} +2 -2
  126. package/dist/{run-DGokR_6q.mjs → run-DX4Zs3Ug.mjs} +34 -34
  127. package/dist/{run-5pmOElaW.cjs → run-DZ5jU53c.cjs} +34 -34
  128. package/dist/{runClaude-BFlpZQds.mjs → runClaude-CgPHXP0L.mjs} +27 -23
  129. package/dist/{runClaude-EnYNvkV0.cjs → runClaude-ClRhHpwR.cjs} +26 -22
  130. package/dist/{runClaudeDeps-CUDebE9e.cjs → runClaudeDeps-D2v_WDSL.cjs} +387 -89
  131. package/dist/{runClaudeDeps-D1M1dzlZ.mjs → runClaudeDeps-Dz2iydq4.mjs} +393 -95
  132. package/dist/{runGemini-Bu69Zu1u.cjs → runGemini-BtZqGFkp.cjs} +208 -193
  133. package/dist/{runGemini-Bub8T5cM.mjs → runGemini-DBXxpoY8.mjs} +208 -193
  134. package/dist/{runOpenClaw-DVu73F_i.mjs → runOpenClaw-BOHpzCEU.mjs} +19 -19
  135. package/dist/{runOpenClaw-Cob5F3FC.cjs → runOpenClaw-D8q8G57u.cjs} +18 -18
  136. package/dist/{sandbox-9EKOFyQF.mjs → sandbox-C452Vrsc.mjs} +4 -4
  137. package/dist/{sandbox-GDqMagSF.cjs → sandbox-Cu9mMzjx.cjs} +4 -4
  138. package/dist/selfCheck-BAvqBwBR.mjs +84 -0
  139. package/dist/{selfCheck-DiNo34da.cjs → selfCheck-gKa3uVr1.cjs} +35 -35
  140. package/dist/{send-ThC80164.cjs → send-2Vb5eppI.cjs} +8 -8
  141. package/dist/{send-wgtHphq8.mjs → send-B8HARi7x.mjs} +9 -9
  142. package/dist/{server-Bb8v2fOj.mjs → server-BBWCIZyS.mjs} +4 -4
  143. package/dist/{server-bidHnstE.cjs → server-Db9Wuam3.cjs} +6 -6
  144. package/dist/{sessionLock-BWBcBZKh.cjs → sessionLock-6qL_N6Rn.cjs} +3 -3
  145. package/dist/{sessionLock-gb32sVPR.mjs → sessionLock-ZfvFVdUi.mjs} +3 -3
  146. package/dist/{sessionModeFile-C-fr1M1h.mjs → sessionModeFile-CWVq8AT9.mjs} +1 -1
  147. package/dist/{sessionModeFile-DhuTNcJr.cjs → sessionModeFile-CsLtn_PL.cjs} +1 -1
  148. package/dist/{sessionOps-ByZJbkMq.mjs → sessionOps-CdgbEJgf.mjs} +5 -5
  149. package/dist/{sessionOps-9MChM9Op.cjs → sessionOps-Dmt7WUUs.cjs} +4 -4
  150. package/dist/{sessionScanner-CxXPAVyS.mjs → sessionScanner-CNVaSNOn.mjs} +34 -4
  151. package/dist/{sessionScanner-BpegdnXK.cjs → sessionScanner-CQL_WSaC.cjs} +34 -3
  152. package/dist/{sessions-C1X4z_Lm.cjs → sessions-BJblG_Hx.cjs} +9 -9
  153. package/dist/{sessions-l-UgJGjV.mjs → sessions-DTomHfFg.mjs} +10 -10
  154. package/dist/{setupOfflineReconnection-CgtXlV74.mjs → setupOfflineReconnection-C5trsV-j.mjs} +2 -2
  155. package/dist/{setupOfflineReconnection-CS_8Da8R.cjs → setupOfflineReconnection-DVA0VpQL.cjs} +2 -2
  156. package/dist/{spawn-FyoHqYWo.mjs → spawn-CQJFgoOq.mjs} +15 -14
  157. package/dist/{spawn-D2BlNdZu.cjs → spawn-DRyNAqD8.cjs} +14 -13
  158. package/dist/{spawnAgents-BhsbJ253.mjs → spawnAgents-BjtmjBvP.mjs} +1 -1
  159. package/dist/{spawnAgents-CgMKuOhZ.cjs → spawnAgents-CCjJifAW.cjs} +1 -1
  160. package/dist/{spawnHappyCLI-DsC256j_.mjs → spawnHappyCLI-B_0RWxD4.mjs} +1 -1
  161. package/dist/{spawnHappyCLI-DByQcqEN.cjs → spawnHappyCLI-ChniczJ5.cjs} +1 -1
  162. package/dist/{specialCommands-DGUeZqdm.cjs → specialCommands-DbntVs0d.cjs} +3 -3
  163. package/dist/{specialCommands-DUUBqzvd.mjs → specialCommands-DkdFJi4N.mjs} +3 -3
  164. package/dist/{startFileWatcher-BtBaahTn.cjs → startFileWatcher-C292fhra.cjs} +1 -1
  165. package/dist/{startFileWatcher-CaYRObJu.mjs → startFileWatcher-UQyTSRAP.mjs} +1 -1
  166. package/dist/{streamRelay-DqPFsCgx.cjs → streamRelay-Cx01enfe.cjs} +1 -1
  167. package/dist/{streamRelay-C8zI7OnR.mjs → streamRelay-_qCd873P.mjs} +1 -1
  168. package/dist/{sync-D5YqUVjS.mjs → sync-C3p7-KLn.mjs} +1 -1
  169. package/dist/{sync-BK-IBkuB.cjs → sync-C7sxoUYG.cjs} +1 -1
  170. package/dist/{systemPrompt-e-qeag_h.mjs → systemPrompt-CdHOlyVW.mjs} +2 -2
  171. package/dist/{systemPrompt-DaTKLEb-.cjs → systemPrompt-DtibzbRU.cjs} +2 -2
  172. package/dist/{teams-D9xwa_d3.cjs → teams-D7O7TpVU.cjs} +6 -6
  173. package/dist/{teams-ClrppvKu.mjs → teams-ujXr3AFn.mjs} +6 -6
  174. package/dist/{time-0szhiPo4.cjs → time-Dg5tVB8S.cjs} +1 -1
  175. package/dist/{time-CvrpeD3S.mjs → time-yEL6wHUF.mjs} +1 -1
  176. package/dist/{titleGenerator-Dz5P7sE1.cjs → titleGenerator-BMEaDTwU.cjs} +2 -2
  177. package/dist/{titleGenerator-BZ5770wq.mjs → titleGenerator-Dr-BtjzO.mjs} +1 -1
  178. package/dist/{todo-CkmNJQey.cjs → todo-CUcFamGs.cjs} +6 -6
  179. package/dist/{todo-o-miKcN2.mjs → todo-CvJe4M2C.mjs} +6 -6
  180. package/dist/{tools-Cp0qJeBq.mjs → tools-BrM3bZW5.mjs} +1 -1
  181. package/dist/{tools-C77-Ssan.cjs → tools-DDKTB5aQ.cjs} +1 -1
  182. package/dist/{uninstall-DGUPERDX.cjs → uninstall-7oLuhYIu.cjs} +3 -3
  183. package/dist/{uninstall-jNJDCLD_.mjs → uninstall-CEcMMQGz.mjs} +3 -3
  184. package/package.json +7 -7
  185. package/dist/selfCheck-CNo4uzGB.mjs +0 -84
@@ -3,10 +3,11 @@
3
3
  var node_child_process = require('node:child_process');
4
4
  var sdk = require('@agentclientprotocol/sdk');
5
5
  var node_crypto = require('node:crypto');
6
- var logger = require('./logger-C7dRaCkE.cjs');
7
- var time = require('./time-0szhiPo4.cjs');
6
+ var logger = require('./logger-LvwVeATU.cjs');
7
+ var time = require('./time-Dg5tVB8S.cjs');
8
8
  var contentLogMetadata = require('./contentLogMetadata-ZSFk_NjQ.cjs');
9
- var _package = require('./package-VqWv7EI5.cjs');
9
+ var processTree = require('./processTree-CMHWlVse.cjs');
10
+ var _package = require('./package-Ch9WGDV_.cjs');
10
11
 
11
12
  function acpImageBlocks(attachments, supportsImages) {
12
13
  return attachments.filter((file) => ["image/jpeg", "image/png", "image/gif", "image/webp"].includes(file.mimeType)).map((file) => {
@@ -15,6 +16,19 @@ function acpImageBlocks(attachments, supportsImages) {
15
16
  });
16
17
  }
17
18
 
19
+ function isAgentExitError(error) {
20
+ return error instanceof Error && error.agentExited === true;
21
+ }
22
+ function agentExitError(agentName, code, signal, tail) {
23
+ const exited = `${agentName} process exited (code=${code ?? "null"}${signal ? `, signal=${signal}` : ""})`;
24
+ return Object.assign(new Error(tail ? `${exited}: ${tail}` : exited), {
25
+ agentExited: true,
26
+ agentExitCode: code,
27
+ agentExitSignal: signal,
28
+ agentStderrTail: tail
29
+ });
30
+ }
31
+
18
32
  const DEFAULT_TIMEOUTS = {
19
33
  /** Default initialization timeout: 60 seconds */
20
34
  init: 6e4,
@@ -187,6 +201,48 @@ function buildAcpPermissionMeta(toolCall) {
187
201
  return meta;
188
202
  }
189
203
 
204
+ const PI_ACP_RETRY = /^Retrying(?: \(attempt \d+\/\d+, waiting \d+s\))?\.\.\.$/;
205
+ const PI_ACP_RETRY_END = "Retry finished, resuming.";
206
+ const PI_ACP_COMPACTION = "Context nearing limit, running automatic compaction...";
207
+ const PI_ACP_COMPACTION_END = "Automatic compaction finished; context was summarized to continue the session.";
208
+ const PI_ACP_UNSUPPORTED = /^Pi (input|editor) UI request is not supported in ACP yet; cancelling it\.$/;
209
+ function notifyMeta(meta) {
210
+ if (!meta || typeof meta !== "object") return null;
211
+ const piAcp = meta.piAcp;
212
+ if (!piAcp || typeof piAcp !== "object") return null;
213
+ const notify = piAcp.notify;
214
+ if (!notify || typeof notify !== "object") return null;
215
+ const level = notify.level;
216
+ return { ...typeof level === "string" ? { level } : {} };
217
+ }
218
+ function classifyPiAcpNotice(text, meta) {
219
+ const notify = notifyMeta(meta);
220
+ if (notify) return { kind: "notify", text: text.trim(), ...notify.level ? { level: notify.level } : {} };
221
+ const trimmed = text.trim();
222
+ if (PI_ACP_RETRY.test(trimmed)) return { kind: "retry", text: trimmed };
223
+ if (trimmed === PI_ACP_RETRY_END) return { kind: "retry-end", text: trimmed };
224
+ if (trimmed === PI_ACP_COMPACTION) return { kind: "compaction", text: trimmed };
225
+ if (trimmed === PI_ACP_COMPACTION_END) return { kind: "compaction-end", text: trimmed };
226
+ if (PI_ACP_UNSUPPORTED.test(trimmed)) return { kind: "unsupported", text: trimmed };
227
+ return null;
228
+ }
229
+ function acpNoticeMessage(agentName, notice) {
230
+ switch (notice.kind) {
231
+ case "retry":
232
+ return `${agentName} is retrying the model request${notice.text.startsWith("Retrying (") ? ` ${notice.text.slice("Retrying ".length).replace(/\.\.\.$/, "")}` : ""}`;
233
+ case "retry-end":
234
+ return `${agentName} retry finished, resuming`;
235
+ case "compaction":
236
+ return `${agentName} is compacting its context (nearing the limit)`;
237
+ case "compaction-end":
238
+ return `${agentName} compacted its context; the session continues on a summary`;
239
+ case "unsupported":
240
+ return `${agentName}: ${notice.text}`;
241
+ case "notify":
242
+ return `${agentName}${notice.level && notice.level !== "info" ? ` ${notice.level}` : ""}: ${notice.text}`;
243
+ }
244
+ }
245
+
190
246
  const DEFAULT_IDLE_TIMEOUT_MS = 500;
191
247
  const DEFAULT_TOOL_CALL_TIMEOUT_MS = 12e4;
192
248
  function parseArgsFromContent(content) {
@@ -240,6 +296,13 @@ function handleAgentMessageChunk(update, ctx) {
240
296
  if (typeof text !== "string") {
241
297
  return { handled: false };
242
298
  }
299
+ if (ctx.transport.agentName === "pi") {
300
+ const notice = classifyPiAcpNotice(text, update._meta);
301
+ if (notice) {
302
+ ctx.emit({ type: "event", name: "notice", payload: notice });
303
+ return { handled: true };
304
+ }
305
+ }
243
306
  const isThinking = /^\*\*[^*]+\*\*\n/.test(text);
244
307
  if (isThinking) {
245
308
  ctx.emit({
@@ -302,25 +365,6 @@ function startToolCall(toolCallId, toolKind, update, ctx, source) {
302
365
  if (isInvestigation) {
303
366
  logger.logger.debug(`[AcpBackend] \u{1F50D} Investigation tool detected - extended timeout (10min) will be used`);
304
367
  }
305
- const timeoutMs = ctx.transport.getToolCallTimeout?.(toolCallId, toolKindStr) ?? DEFAULT_TOOL_CALL_TIMEOUT_MS;
306
- if (!ctx.toolCallTimeouts.has(toolCallId)) {
307
- const timeout = setTimeout(() => {
308
- const duration = formatDuration(ctx.toolCallStartTimes.get(toolCallId));
309
- logger.logger.debug(`[AcpBackend] Tool call TIMEOUT (from ${source}): ${toolCallId} after ${(timeoutMs / 1e3).toFixed(0)}s - Duration: ${duration}, removing from active set`);
310
- ctx.activeToolCalls.delete(toolCallId);
311
- ctx.toolCallStartTimes.delete(toolCallId);
312
- ctx.toolCallTimeouts.delete(toolCallId);
313
- ctx.toolCallOutputs.delete(toolCallId);
314
- if (ctx.activeToolCalls.size === 0) {
315
- logger.logger.debug("[AcpBackend] No more active tool calls after timeout, emitting idle status");
316
- ctx.emitIdleStatus();
317
- }
318
- }, timeoutMs);
319
- ctx.toolCallTimeouts.set(toolCallId, timeout);
320
- logger.logger.debug(`[AcpBackend] \u23F1\uFE0F Set timeout for ${toolCallId}: ${(timeoutMs / 1e3).toFixed(0)}s${isInvestigation ? " (investigation tool)" : ""}`);
321
- } else {
322
- logger.logger.debug(`[AcpBackend] Timeout already set for ${toolCallId}, skipping`);
323
- }
324
368
  ctx.clearIdleTimeout();
325
369
  ctx.emit({ type: "status", status: "running" });
326
370
  const args = parseArgsFromContent(update.content);
@@ -633,6 +677,23 @@ class AcpBackend {
633
677
  toolCallCountSincePrompt = 0;
634
678
  /** Timeout for emitting 'idle' status after last message chunk */
635
679
  idleTimeout = null;
680
+ // B-629 (approach from Orca, src/main/acp/acp-agent-connection.ts): the agent process is
681
+ // part of the turn. Its last stderr lines are kept so its death can be explained, any exit
682
+ // (code or signal) is announced as `stopped`, and a request in flight when it dies rejects
683
+ // at once instead of waiting forever on a stream that will never answer.
684
+ /** Last stderr output of the agent process, bounded. */
685
+ stderrRing = "";
686
+ static STDERR_TAIL_CHARS = 2e3;
687
+ /** Set when the current agent process exited; the backend takes no further prompt. */
688
+ exited = null;
689
+ /** Rejects with the exit error when the current agent process exits (one per spawn). */
690
+ processGone = null;
691
+ /** Fails the request in flight (an oversized frame that was its answer, see MAX_FRAME_CHARS). */
692
+ inflightReject = null;
693
+ /** A single JSON-RPC line longer than this is dropped rather than buffered (Orca: 16 MiB). */
694
+ static MAX_FRAME_CHARS = 16 * 1024 * 1024;
695
+ /** How long the graceful stop gets on dispose before the process tree is killed. */
696
+ static DISPOSE_GRACE_MS = 4e3;
636
697
  /** Transport handler for agent-specific behavior */
637
698
  transport;
638
699
  onMessage(handler) {
@@ -644,6 +705,23 @@ class AcpBackend {
644
705
  this.listeners.splice(index, 1);
645
706
  }
646
707
  }
708
+ /** B-629: the agent's last stderr lines, one line, for a message a person reads. */
709
+ stderrTail() {
710
+ return processTree.readableStderrTail(this.stderrRing);
711
+ }
712
+ /** B-629: the agent process exited; this backend cannot take another prompt. */
713
+ get hasExited() {
714
+ return this.exited !== null;
715
+ }
716
+ /** B-629: a frame that cannot be read in full. One that answers a request fails that request. */
717
+ onOversizedFrame(head, chars) {
718
+ const looksLikeResponse = /"id"\s*:\s*\d+/.test(head) && /"(result|error)"\s*:/.test(head);
719
+ logger.logger.debug(`[AcpBackend] Dropped an oversized ${this.transport.agentName} frame (${Math.round(chars / 1024 / 1024)} MiB${looksLikeResponse ? ", a response" : ""})`);
720
+ if (!looksLikeResponse) return;
721
+ const error = new Error(`${this.transport.agentName} sent a ${Math.round(chars / 1024 / 1024)} MiB response frame that cannot be read; the turn was given up`);
722
+ this.inflightReject?.(error);
723
+ this.emit({ type: "status", status: "error", detail: error.message });
724
+ }
647
725
  emit(msg) {
648
726
  if (this.disposed) return;
649
727
  for (const listener of this.listeners) {
@@ -686,6 +764,15 @@ class AcpBackend {
686
764
  if (!this.process.stdin || !this.process.stdout || !this.process.stderr) {
687
765
  throw new Error("Failed to create stdio pipes");
688
766
  }
767
+ const child = this.process;
768
+ let rejectGone;
769
+ const processGone = new Promise((_, reject) => {
770
+ rejectGone = reject;
771
+ });
772
+ processGone.catch(() => void 0);
773
+ this.processGone = processGone;
774
+ this.exited = null;
775
+ this.stderrRing = "";
689
776
  let startupFailure = null;
690
777
  let startupFailureSettled = false;
691
778
  let rejectStartupFailure = null;
@@ -705,6 +792,9 @@ class AcpBackend {
705
792
  this.process.stderr.on("data", (data) => {
706
793
  const text = data.toString();
707
794
  if (!text.trim()) return;
795
+ if (this.process === child) {
796
+ this.stderrRing = processTree.appendStderrRing(this.stderrRing, text, AcpBackend.STDERR_TAIL_CHARS);
797
+ }
708
798
  const hasActiveInvestigation = this.transport.isInvestigationTool ? Array.from(this.activeToolCalls).some((id) => this.transport.isInvestigationTool(id)) : false;
709
799
  const context = {
710
800
  activeToolCalls: this.activeToolCalls,
@@ -728,10 +818,14 @@ class AcpBackend {
728
818
  this.emit({ type: "status", status: "error", detail: err.message });
729
819
  });
730
820
  this.process.on("exit", (code, signal) => {
731
- if (!this.disposed && code !== 0 && code !== null) {
732
- signalStartupFailure(new Error(`Exit code: ${code}`));
733
- logger.logger.debug(`[AcpBackend] Process exited with code ${code}, signal ${signal}`);
734
- this.emit({ type: "status", status: "stopped", detail: `Exit code: ${code}` });
821
+ const error = agentExitError(this.transport.agentName, code, signal, this.stderrTail());
822
+ setTimeout(() => rejectGone(error), 50);
823
+ if (this.process !== child) return;
824
+ this.exited = { code, signal, error };
825
+ signalStartupFailure(error);
826
+ logger.logger.debug(`[AcpBackend] Process exited with code ${code}, signal ${signal}`);
827
+ if (!this.disposed) {
828
+ this.emit({ type: "status", status: "stopped", detail: error.message });
735
829
  }
736
830
  });
737
831
  const streams = nodeToWebStreams(
@@ -741,6 +835,7 @@ class AcpBackend {
741
835
  const writable = streams.writable;
742
836
  const readable = streams.readable;
743
837
  const transport = this.transport;
838
+ const backend = this;
744
839
  const filteredReadable = new ReadableStream({
745
840
  async start(controller) {
746
841
  const reader = readable.getReader();
@@ -771,8 +866,18 @@ class AcpBackend {
771
866
  buffer += decoder.decode(value, { stream: true });
772
867
  const lines = buffer.split("\n");
773
868
  buffer = lines.pop() || "";
869
+ if (buffer.length > AcpBackend.MAX_FRAME_CHARS) {
870
+ backend.onOversizedFrame(buffer.slice(0, 200), buffer.length);
871
+ buffer = "";
872
+ filteredCount++;
873
+ }
774
874
  for (const line of lines) {
775
875
  if (!line.trim()) continue;
876
+ if (line.length > AcpBackend.MAX_FRAME_CHARS) {
877
+ backend.onOversizedFrame(line.slice(0, 200), line.length);
878
+ filteredCount++;
879
+ continue;
880
+ }
776
881
  const filtered = transport.filterStdoutLine?.(line);
777
882
  if (filtered === void 0) {
778
883
  controller.enqueue(encoder.encode(line + "\n"));
@@ -1182,6 +1287,11 @@ class AcpBackend {
1182
1287
  get supportsImageAttachments() {
1183
1288
  return this.supportsImagePrompt;
1184
1289
  }
1290
+ /**
1291
+ * B-629: the turn is over when ACP's `prompt` answers (the agent sends every update before
1292
+ * its response on the same ordered stream), never when the text goes quiet — the idle
1293
+ * heuristic below is only a status hint now. Resolves with the agent's `stopReason`.
1294
+ */
1185
1295
  async sendPrompt(sessionId, prompt, attachments = []) {
1186
1296
  const promptHasChangeTitle = this.options.hasChangeTitleInstruction?.(prompt) ?? false;
1187
1297
  this.toolCallCountSincePrompt = 0;
@@ -1192,11 +1302,18 @@ class AcpBackend {
1192
1302
  if (this.disposed) {
1193
1303
  throw new Error("Backend has been disposed");
1194
1304
  }
1305
+ if (this.exited) {
1306
+ throw this.exited.error;
1307
+ }
1195
1308
  if (!this.connection || !this.acpSessionId) {
1196
1309
  throw new Error("Session not started");
1197
1310
  }
1198
1311
  this.emit({ type: "status", status: "running" });
1199
1312
  this.waitingForResponse = true;
1313
+ const inflight = new Promise((_, reject) => {
1314
+ this.inflightReject = reject;
1315
+ });
1316
+ inflight.catch(() => void 0);
1200
1317
  try {
1201
1318
  logger.logger.debug("[AcpBackend] Sending prompt:", {
1202
1319
  sessionId,
@@ -1214,14 +1331,21 @@ class AcpBackend {
1214
1331
  sessionId: this.acpSessionId,
1215
1332
  blockCount: promptRequest.prompt.length
1216
1333
  });
1217
- const response = await this.connection.prompt(promptRequest);
1334
+ const response = await Promise.race([
1335
+ this.connection.prompt(promptRequest),
1336
+ this.processGone ?? new Promise(() => void 0),
1337
+ inflight
1338
+ ]);
1218
1339
  if (response.usage) {
1219
1340
  this.emit({ type: "token-count", ...response.usage });
1220
1341
  }
1221
- logger.logger.debug("[AcpBackend] Prompt request sent to ACP connection");
1342
+ const stopReason = typeof response.stopReason === "string" ? response.stopReason : void 0;
1343
+ logger.logger.debug(`[AcpBackend] Prompt answered (stopReason=${stopReason ?? "none"})`);
1344
+ this.finishTurn();
1345
+ return stopReason ? { stopReason } : {};
1222
1346
  } catch (error) {
1223
1347
  logger.logger.debug("[AcpBackend] Error sending prompt:", contentLogMetadata.errorLogMetadata(error));
1224
- this.waitingForResponse = false;
1348
+ this.finishTurn(false);
1225
1349
  let errorDetail;
1226
1350
  if (error instanceof Error) {
1227
1351
  errorDetail = error.message;
@@ -1244,7 +1368,29 @@ class AcpBackend {
1244
1368
  detail: errorDetail
1245
1369
  });
1246
1370
  throw error;
1371
+ } finally {
1372
+ this.inflightReject = null;
1373
+ }
1374
+ }
1375
+ /**
1376
+ * B-629: the turn's bookkeeping ends with the prompt answer: no response is awaited any
1377
+ * more, the idle timer and per-call timers are dropped, and the calls still marked active
1378
+ * belong to a turn that is over. `idle` is emitted once for status listeners.
1379
+ */
1380
+ finishTurn(announceIdle = true) {
1381
+ this.waitingForResponse = false;
1382
+ if (this.idleTimeout) {
1383
+ clearTimeout(this.idleTimeout);
1384
+ this.idleTimeout = null;
1385
+ }
1386
+ for (const timeout of this.toolCallTimeouts.values()) {
1387
+ clearTimeout(timeout);
1247
1388
  }
1389
+ this.toolCallTimeouts.clear();
1390
+ this.activeToolCalls.clear();
1391
+ this.toolCallStartTimes.clear();
1392
+ this.toolCallOutputs.clear();
1393
+ if (announceIdle) this.emitIdleStatus();
1248
1394
  }
1249
1395
  /**
1250
1396
  * Set a session config option value.
@@ -1389,7 +1535,7 @@ class AcpBackend {
1389
1535
  if (this.disposed) return;
1390
1536
  logger.logger.debug("[AcpBackend] Disposing backend");
1391
1537
  this.disposed = true;
1392
- if (this.connection && this.acpSessionId) {
1538
+ if (this.connection && this.acpSessionId && !this.exited) {
1393
1539
  try {
1394
1540
  await Promise.race([
1395
1541
  this.connection.cancel({ sessionId: this.acpSessionId }),
@@ -1401,16 +1547,19 @@ class AcpBackend {
1401
1547
  }
1402
1548
  }
1403
1549
  if (this.process) {
1404
- this.process.kill("SIGTERM");
1550
+ const proc = this.process;
1551
+ processTree.stopProcessGracefully(proc);
1405
1552
  await new Promise((resolve) => {
1553
+ if (proc.exitCode != null || proc.signalCode != null) {
1554
+ resolve();
1555
+ return;
1556
+ }
1406
1557
  const timeout = setTimeout(() => {
1407
- if (this.process) {
1408
- logger.logger.debug("[AcpBackend] Force killing process");
1409
- this.process.kill("SIGKILL");
1410
- }
1558
+ logger.logger.debug("[AcpBackend] Force killing process tree");
1559
+ processTree.killProcessTree(proc);
1411
1560
  resolve();
1412
- }, 1e3);
1413
- this.process?.once("exit", () => {
1561
+ }, AcpBackend.DISPOSE_GRACE_MS);
1562
+ proc.once("exit", () => {
1414
1563
  clearTimeout(timeout);
1415
1564
  resolve();
1416
1565
  });
@@ -1439,6 +1588,7 @@ exports.AcpBackend = AcpBackend;
1439
1588
  exports.DEFAULT_IDLE_TIMEOUT_MS = DEFAULT_IDLE_TIMEOUT_MS;
1440
1589
  exports.DEFAULT_TOOL_CALL_TIMEOUT_MS = DEFAULT_TOOL_CALL_TIMEOUT_MS;
1441
1590
  exports.DefaultTransport = DefaultTransport;
1591
+ exports.acpNoticeMessage = acpNoticeMessage;
1442
1592
  exports.extractErrorDetail = extractErrorDetail;
1443
1593
  exports.formatDuration = formatDuration;
1444
1594
  exports.formatDurationMinutes = formatDurationMinutes;
@@ -1449,4 +1599,5 @@ exports.handlePlanUpdate = handlePlanUpdate;
1449
1599
  exports.handleThinkingUpdate = handleThinkingUpdate;
1450
1600
  exports.handleToolCall = handleToolCall;
1451
1601
  exports.handleToolCallUpdate = handleToolCallUpdate;
1602
+ exports.isAgentExitError = isAgentExitError;
1452
1603
  exports.parseArgsFromContent = parseArgsFromContent;