very-happy-cli 0.2.160 → 0.2.162

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 (176) hide show
  1. package/dist/{AcpBackend-mzv8Dhba.mjs → AcpBackend--TmFHgRH.mjs} +3 -3
  2. package/dist/{AcpBackend-Bm2rdke8.cjs → AcpBackend-9asD_DL7.cjs} +3 -3
  3. package/dist/{AcpSessionManager-CoMWFVw3.mjs → AcpSessionManager-BSIBnWUb.mjs} +1 -1
  4. package/dist/{AcpSessionManager-BAY1Pggx.cjs → AcpSessionManager-BvIuBzoO.cjs} +1 -1
  5. package/dist/{BasePermissionHandler-CFHAxumV.cjs → BasePermissionHandler-D4B-NNu2.cjs} +1 -1
  6. package/dist/{BasePermissionHandler-m3WVholL.mjs → BasePermissionHandler-DUBySe0f.mjs} +1 -1
  7. package/dist/{BaseReasoningProcessor-CYrKBXGm.mjs → BaseReasoningProcessor-9TybUGTq.mjs} +1 -1
  8. package/dist/{BaseReasoningProcessor-BFa9_rZA.cjs → BaseReasoningProcessor-CqLl-ikP.cjs} +1 -1
  9. package/dist/{agentHome-CboCeKWq.cjs → agentHome-BohNUYnE.cjs} +4 -4
  10. package/dist/{agentHome-Dj1C43aJ.mjs → agentHome-DQrq_FG1.mjs} +4 -4
  11. package/dist/{api-CgundNNX.cjs → api-CQnLOqRS.cjs} +10 -10
  12. package/dist/{api-CLMUr-SX.mjs → api-D57dsd6_.mjs} +10 -10
  13. package/dist/{apiMachine-B9dLW_p5.mjs → apiMachine-78Aqzg--.mjs} +21 -14
  14. package/dist/{apiMachine-Bn8482VM.cjs → apiMachine-fFFaWxYy.cjs} +33 -26
  15. package/dist/{assistantTools-BTqPnlFl.cjs → assistantTools-CwESq24n.cjs} +6 -6
  16. package/dist/{assistantTools-D6tuc6o4.mjs → assistantTools-mEz6uNqL.mjs} +6 -6
  17. package/dist/{attachmentContent-DpiTJZb4.cjs → attachmentContent-GHOk6Muq.cjs} +2 -2
  18. package/dist/{attachmentContent-_kxRznNf.mjs → attachmentContent-s1xPha4Q.mjs} +2 -2
  19. package/dist/{attachmentLimits-yba1uHFO.mjs → attachmentLimits-D5pgmASK.mjs} +1 -1
  20. package/dist/{attachmentLimits-CzVrqgLR.cjs → attachmentLimits-DzlBPyJP.cjs} +1 -1
  21. package/dist/{auth-BDOVh5h5.cjs → auth-B8EagV6G.cjs} +8 -8
  22. package/dist/{auth-PYHZQNPp.mjs → auth-BOaHWquu.mjs} +8 -8
  23. package/dist/{auth-ba4WMYrN.cjs → auth-BbSdXMQ_.cjs} +5 -5
  24. package/dist/{auth-Cwutmdsa.mjs → auth-C8V7-oUT.mjs} +5 -5
  25. package/dist/{auto-BOX_fgmR.cjs → auto-Bw_h0yVc.cjs} +15 -14
  26. package/dist/{auto-BXu14yP_.mjs → auto-CWDOX35m.mjs} +15 -14
  27. package/dist/{bootstrap-hxXPCFMx.mjs → bootstrap-BKmsYSwh.mjs} +2 -2
  28. package/dist/{bootstrap-B5G1TijC.cjs → bootstrap-DvZjEa9_.cjs} +2 -2
  29. package/dist/{browser-Y6Bl8L_O.cjs → browser-CBZj-1Wx.cjs} +1 -1
  30. package/dist/{browser-jh2P0UVZ.mjs → browser-CrMAr5fI.mjs} +1 -1
  31. package/dist/{claudeLocal-CRGG4Pea.cjs → claudeLocal-Bpw-u9et.cjs} +5 -5
  32. package/dist/{claudeLocal-BaY4fZKi.mjs → claudeLocal-dhdlcQ6F.mjs} +5 -5
  33. package/dist/{claudeLocalLauncher-D4T7MTqd.mjs → claudeLocalLauncher-BFfGT4eY.mjs} +10 -10
  34. package/dist/{claudeLocalLauncher-DyEbVzUN.cjs → claudeLocalLauncher-DWFWuLhY.cjs} +10 -10
  35. package/dist/{codexThreadFork-BH9IZPqD.cjs → claudeSessionFork-D9-mANmu.cjs} +1 -137
  36. package/dist/{codexThreadFork-slzAseLx.mjs → claudeSessionFork-_DUrXaqd.mjs} +2 -134
  37. package/dist/{client-BPNbmtvO.cjs → client-CVQJWqjx.cjs} +2 -2
  38. package/dist/{client-3Ac-O4pw.cjs → client-DiBTHWNU.cjs} +3 -3
  39. package/dist/{client-CeGKqqcJ.mjs → client-Dk7x-s-O.mjs} +3 -3
  40. package/dist/{client-ClR0K8zX.mjs → client-DwqHDsLb.mjs} +2 -2
  41. package/dist/codex/happyMcpStdioBridge.cjs +15 -15
  42. package/dist/codex/happyMcpStdioBridge.mjs +15 -15
  43. package/dist/{codexAppServerClient-I3teiV-N.mjs → codexAppServerClient-C2ybs2mZ.mjs} +2 -2
  44. package/dist/{codexAppServerClient-q2FjnRcK.cjs → codexAppServerClient-DlKv5TjG.cjs} +2 -2
  45. package/dist/{codexCommand-4zcccIoq.cjs → codexCommand-4vLE31fj.cjs} +45 -40
  46. package/dist/{codexCommand-Cc9gcbdX.mjs → codexCommand-DnmFr9Qx.mjs} +45 -40
  47. package/dist/codexThreadFork-DNekT4nQ.cjs +138 -0
  48. package/dist/codexThreadFork-R76RU5H0.mjs +133 -0
  49. package/dist/{config-Ci9Kpgwa.cjs → config-Btd4B05_.cjs} +3 -3
  50. package/dist/{config-CTx_jb-C.mjs → config-CSOG_ZcP.mjs} +3 -3
  51. package/dist/{configuration-RfeNjFmd.mjs → configuration-A5gW_0GE.mjs} +1 -1
  52. package/dist/{configuration-BSYpcPwE.cjs → configuration-UsI0sxEv.cjs} +1 -1
  53. package/dist/{connect-C2CiOUFs.cjs → connect-C9yxp8Om.cjs} +13 -13
  54. package/dist/{connect-BpOdzNbE.mjs → connect-DWYj8LP_.mjs} +13 -13
  55. package/dist/{context-DsDr6E2t.cjs → context-0FjjA4vJ.cjs} +1 -1
  56. package/dist/{context-H0Bcb9S_.mjs → context-BXnxalWW.mjs} +1 -1
  57. package/dist/{controlClient-Bcwv3D21.cjs → controlClient-BXktrQ4z.cjs} +3 -3
  58. package/dist/{controlClient-BGbDcgWS.mjs → controlClient-CYzHrh3e.mjs} +3 -3
  59. package/dist/{createSessionMetadata-CVVkGjxV.mjs → createSessionMetadata-Dyg33ZlU.mjs} +2 -2
  60. package/dist/{createSessionMetadata-BJxEnM-o.cjs → createSessionMetadata-EX1eAlHx.cjs} +2 -2
  61. package/dist/{deterministicJson-CzkFJWw1.mjs → deterministicJson-DiR7EOMO.mjs} +9 -9
  62. package/dist/{deterministicJson-C5CYTVpm.cjs → deterministicJson-eha_oMZ2.cjs} +9 -9
  63. package/dist/{doctor-D2YJ-Yn2.cjs → doctor-DunLBgVi.cjs} +6 -6
  64. package/dist/{doctor-DOvByjbk.mjs → doctor-FuCvKdRa.mjs} +6 -6
  65. package/dist/{ensureDaemonRunning-BCwNrMyv.cjs → ensureDaemonRunning-B4dZFmUy.cjs} +5 -5
  66. package/dist/{ensureDaemonRunning-Dqa2pOjY.mjs → ensureDaemonRunning-EZkb-CAF.mjs} +5 -5
  67. package/dist/{handleResumeCommand-C2cKchpX.cjs → handleResumeCommand-CKMIw4pE.cjs} +5 -5
  68. package/dist/{handleResumeCommand-BvXYf5El.mjs → handleResumeCommand-CsXendKb.mjs} +5 -5
  69. package/dist/{index-DMZqWwsP.mjs → index-9L39wqYR.mjs} +37 -37
  70. package/dist/{index-qdS1friN.mjs → index-BBg9j0XK.mjs} +8 -1
  71. package/dist/{index-B6pAdvJx.cjs → index-BOhgL3rh.cjs} +36 -36
  72. package/dist/{index-Bu5Zi_a9.cjs → index-CZWAiydF.cjs} +4 -4
  73. package/dist/{index-DVkMGPyS.mjs → index-CvXcVQ06.mjs} +3 -3
  74. package/dist/{index-DA7yINuk.cjs → index-DJ-oV52i.cjs} +8 -1
  75. package/dist/{index-DKLU_fD0.mjs → index-DK2JpTJf.mjs} +4 -4
  76. package/dist/{index-DDeHXrIX.cjs → index-DRhWHEuW.cjs} +3 -3
  77. package/dist/index.cjs +2 -2
  78. package/dist/index.mjs +2 -2
  79. package/dist/{install-CFY3tYtJ.mjs → install-B2duVo9a.mjs} +3 -3
  80. package/dist/{install-BgoC2e_2.cjs → install-C8WyZI9K.cjs} +3 -3
  81. package/dist/lib.cjs +12 -12
  82. package/dist/lib.d.cts +5 -0
  83. package/dist/lib.d.mts +5 -0
  84. package/dist/lib.mjs +12 -12
  85. package/dist/{lidState-CeEt442o.mjs → lidState-CigXWxhe.mjs} +1 -1
  86. package/dist/{lidState-BeDfxxEX.cjs → lidState-Ds-6ytZV.cjs} +1 -1
  87. package/dist/{localHappyAgentAuth-C-HQyiv6.mjs → localHappyAgentAuth-CaCyKzYp.mjs} +1 -1
  88. package/dist/{localHappyAgentAuth-D6rFhaoc.cjs → localHappyAgentAuth-l0Na-5Ys.cjs} +1 -1
  89. package/dist/{logger-CS0mw3fa.cjs → logger-7ucWm9wp.cjs} +2 -2
  90. package/dist/{logger-6HYUEXNk.mjs → logger-CGE4C8ho.mjs} +2 -2
  91. package/dist/{machineMetadata-DyDbODYd.cjs → machineMetadata-lMPtpF16.cjs} +3 -3
  92. package/dist/{machineMetadata-oOzBfDfs.mjs → machineMetadata-ue1nkowa.mjs} +3 -3
  93. package/dist/{main-BwNIAI1A.mjs → main-3fIFXD-t.mjs} +44 -44
  94. package/dist/{main-BkxJP6JQ.cjs → main-CFI0datL.cjs} +44 -44
  95. package/dist/{mcp-B1A4I3TK.mjs → mcp-DARQBZ7l.mjs} +14 -14
  96. package/dist/{mcp-Hszd7qpS.cjs → mcp-DfxLAc1G.cjs} +14 -14
  97. package/dist/{package-BwMrPwqH.cjs → package-D1A-8ZJy.cjs} +7 -7
  98. package/dist/{package-BhaKlnxz.mjs → package-DQsvY1XN.mjs} +7 -7
  99. package/dist/{peerTools-BTqw97Gb.mjs → peerTools-D19hhSQF.mjs} +4 -4
  100. package/dist/{peerTools-BvKtHXj8.cjs → peerTools-DLwNaEEV.cjs} +4 -4
  101. package/dist/{permissionMode-Cr5JCbB7.mjs → permissionMode-CH4FoZfU.mjs} +1 -1
  102. package/dist/{persistence-HGW_ZVs9.mjs → persistence-Cw8aLoyL.mjs} +3 -3
  103. package/dist/{persistence-yKTH3-5X.cjs → persistence-i0nQMLlk.cjs} +3 -3
  104. package/dist/{piRunnerArgs-BuX1UFWy.mjs → piRunnerArgs-58t454gw.mjs} +1 -1
  105. package/dist/{piRunnerArgs-BNloJCCg.cjs → piRunnerArgs-BUyxPxjZ.cjs} +1 -1
  106. package/dist/{piRuntime-CSGkwCKQ.mjs → piRuntime-DVPixFjl.mjs} +1 -1
  107. package/dist/{piRuntime-C_H7MJCM.cjs → piRuntime-Dff73XCb.cjs} +1 -1
  108. package/dist/{piTerminal-DNCZ6yTM.cjs → piTerminal-Dz1RrO70.cjs} +16 -16
  109. package/dist/{piTerminal-C8a1OrNQ.mjs → piTerminal-gHWFAyzq.mjs} +16 -16
  110. package/dist/{registerCommonHandlers-DskirN-_.cjs → registerCommonHandlers-CMROPdJz.cjs} +2 -2
  111. package/dist/{registerCommonHandlers-Ccvsz7Ou.mjs → registerCommonHandlers-Ckv5boQI.mjs} +2 -2
  112. package/dist/{registerKillSessionHandler-DZeLXWcB.cjs → registerKillSessionHandler-CA9-oelM.cjs} +19 -10
  113. package/dist/{registerKillSessionHandler-GYvHdipX.mjs → registerKillSessionHandler-Cll4-o8Y.mjs} +19 -10
  114. package/dist/{remoteSessionClient-CYnXRynE.mjs → remoteSessionClient-BMjsbuBh.mjs} +5 -5
  115. package/dist/{remoteSessionClient-B0LraSB9.cjs → remoteSessionClient-DX9jHLeW.cjs} +5 -5
  116. package/dist/{run-CJzxoHVh.cjs → run-CjbGo2wb.cjs} +36 -32
  117. package/dist/{run-D3ifupU3.mjs → run-CrunzDlt.mjs} +35 -31
  118. package/dist/{runClaude-Da3RirzE.cjs → runClaude-KN-4Y4LH.cjs} +184 -140
  119. package/dist/{runClaude-Ba01qT-u.mjs → runClaude-WDBWRtnF.mjs} +185 -141
  120. package/dist/{runClaudeDeps-DOzEBMls.cjs → runClaudeDeps-DW-8lnHv.cjs} +821 -125
  121. package/dist/{runClaudeDeps-DOt79DjU.mjs → runClaudeDeps-QaEx8y5r.mjs} +811 -129
  122. package/dist/{runGemini-DSr9LIxL.cjs → runGemini-Djmwjdv1.cjs} +32 -32
  123. package/dist/{runGemini-BGeTz57m.mjs → runGemini-Nf6SKBpw.mjs} +32 -32
  124. package/dist/{runOpenClaw-CogSedIc.mjs → runOpenClaw-9nHtmYbN.mjs} +18 -18
  125. package/dist/{runOpenClaw-B1mTxN35.cjs → runOpenClaw-CAqP5KFH.cjs} +18 -18
  126. package/dist/{sandbox-CG7IyDTU.cjs → sandbox-C8Dd8GPM.cjs} +4 -4
  127. package/dist/{sandbox-DTe6d54R.mjs → sandbox-SP0THMt0.mjs} +4 -4
  128. package/dist/selfCheck-7FaZtVu2.mjs +84 -0
  129. package/dist/{selfCheck-Dc-mNSLb.cjs → selfCheck-D9ZXrK7h.cjs} +34 -34
  130. package/dist/{send-CBXJKc6O.mjs → send-DOx9aQsx.mjs} +8 -8
  131. package/dist/{send-B7J_eaG3.cjs → send-LPk6Q5HI.cjs} +8 -8
  132. package/dist/{server-DcVBv04l.mjs → server-BZNi8Hq_.mjs} +4 -4
  133. package/dist/{server-CZTP_iOn.cjs → server-CxT8jNyn.cjs} +6 -6
  134. package/dist/{sessionLock-D-EG2CfG.mjs → sessionLock-CfLqJfeI.mjs} +2 -2
  135. package/dist/{sessionLock-Bys1PNSo.cjs → sessionLock-y9rnA4LK.cjs} +2 -2
  136. package/dist/{sessionModeFile-RSm0NQkH.cjs → sessionModeFile-B5YeoQJh.cjs} +1 -1
  137. package/dist/{sessionModeFile-DMl3dw3r.mjs → sessionModeFile-BKxgNH3P.mjs} +1 -1
  138. package/dist/{sessionOps-SuHW8Dfe.mjs → sessionOps-CdwVPSZz.mjs} +4 -4
  139. package/dist/{sessionOps-Dn8z85h_.cjs → sessionOps-GsELm2PZ.cjs} +4 -4
  140. package/dist/{sessionScanner-CX3onqXh.mjs → sessionScanner-Cdukzo70.mjs} +3 -3
  141. package/dist/{sessionScanner-BOrGjMXL.cjs → sessionScanner-aLEv7mD3.cjs} +3 -3
  142. package/dist/{sessions-D74aJbhL.cjs → sessions-CfG4WGN0.cjs} +9 -9
  143. package/dist/{sessions-BEG_HTSi.mjs → sessions-Dne-OiRL.mjs} +9 -9
  144. package/dist/{setupOfflineReconnection-ByElY60m.cjs → setupOfflineReconnection-CFwltTcP.cjs} +2 -2
  145. package/dist/{setupOfflineReconnection-DpvWTt69.mjs → setupOfflineReconnection-DiQma2Cc.mjs} +2 -2
  146. package/dist/{spawn-DgR0RKRs.cjs → spawn-BI_sdgWs.cjs} +24 -15
  147. package/dist/{spawn-B7yro0b2.mjs → spawn-DkgP2BGF.mjs} +22 -14
  148. package/dist/{spawnAgents-DZzZ9jMI.mjs → spawnAgents-Y1LjnCt9.mjs} +1 -1
  149. package/dist/{spawnAgents-BGQiEF-w.cjs → spawnAgents-iSu1Xzs5.cjs} +1 -1
  150. package/dist/{spawnHappyCLI-B2H5s4B_.mjs → spawnHappyCLI-9mx4lPxh.mjs} +1 -1
  151. package/dist/{spawnHappyCLI-DBhwZT7O.cjs → spawnHappyCLI-BRdx0sAX.cjs} +1 -1
  152. package/dist/{startFileWatcher-B4VsLgjD.cjs → startFileWatcher-C2HC2_Dg.cjs} +1 -1
  153. package/dist/{startFileWatcher-DErVWZE4.mjs → startFileWatcher-COD5UKNs.mjs} +1 -1
  154. package/dist/{streamRelay-FPVbHpbM.mjs → streamRelay-BLgU9X3R.mjs} +1 -1
  155. package/dist/{streamRelay-BiKw59Cc.cjs → streamRelay-DnObXZZj.cjs} +1 -1
  156. package/dist/{sync-C8gyQFMc.mjs → sync-BpLasLu2.mjs} +1 -1
  157. package/dist/{sync-DccIKZ5_.cjs → sync-Dj92ZJ8Y.cjs} +1 -1
  158. package/dist/{systemPrompt-BwTPWfMu.cjs → systemPrompt-CyEz_IfR.cjs} +2 -2
  159. package/dist/{systemPrompt-DX521JJz.mjs → systemPrompt-DsQoUgQw.mjs} +2 -2
  160. package/dist/{teams-C32F1hqd.mjs → teams-BETNMjpZ.mjs} +6 -6
  161. package/dist/{teams-Dl8g8kTI.cjs → teams-Ctx9zXn4.cjs} +6 -6
  162. package/dist/{time-DCuTyook.cjs → time-CLwVAz6s.cjs} +1 -1
  163. package/dist/{time-D0XyHOid.mjs → time-CVvxdEDh.mjs} +1 -1
  164. package/dist/{titleGenerator-CQ8CoGhg.mjs → titleGenerator-B4AW3dLr.mjs} +12 -2
  165. package/dist/{titleGenerator-ChzMJsyg.cjs → titleGenerator-FDpdizn7.cjs} +13 -3
  166. package/dist/{todo-BvUOTa8G.cjs → todo-C3tyFeq1.cjs} +6 -6
  167. package/dist/{todo-CZ6cFrrn.mjs → todo-Jk4Vs7hP.mjs} +6 -6
  168. package/dist/{tools-BZtHF_qQ.mjs → tools-BA1qkiV1.mjs} +2 -2
  169. package/dist/{tools-DQj0AeLk.cjs → tools-CGxq3I52.cjs} +2 -2
  170. package/dist/{tools-Be3AoAwu.cjs → tools-O5beDK-s.cjs} +1 -1
  171. package/dist/{tools-DkluDcG4.mjs → tools-_kFe4m_l.mjs} +1 -1
  172. package/dist/{uninstall-BkLzaJ6I.mjs → uninstall-C_mdAZlm.mjs} +3 -3
  173. package/dist/{uninstall-x-TUtf5H.cjs → uninstall-DHKF90lo.cjs} +3 -3
  174. package/package.json +7 -7
  175. package/scripts/session_hook_forwarder.cjs +9 -2
  176. package/dist/selfCheck-C9mVrQwf.mjs +0 -84
@@ -1,46 +1,48 @@
1
1
  'use strict';
2
2
 
3
- var logger = require('./logger-CS0mw3fa.cjs');
4
- var controlClient = require('./controlClient-Bcwv3D21.cjs');
3
+ var logger = require('./logger-7ucWm9wp.cjs');
4
+ var controlClient = require('./controlClient-BXktrQ4z.cjs');
5
5
  var backgroundTaskActivity = require('./backgroundTaskActivity-CBvUdj39.cjs');
6
6
  var node_crypto = require('node:crypto');
7
7
  var messageBuffer = require('./messageBuffer-fJMH6uY8.cjs');
8
8
  var index = require('./index-D3kI0hDR.cjs');
9
9
  var claudeAgentSdk = require('@anthropic-ai/claude-agent-sdk');
10
10
  var permissionMode = require('./permissionMode-CrV-XuMs.cjs');
11
- var systemPrompt = require('./systemPrompt-BwTPWfMu.cjs');
11
+ var systemPrompt = require('./systemPrompt-CyEz_IfR.cjs');
12
12
  var path$1 = require('node:path');
13
13
  var specialCommands = require('./specialCommands-DSsTeRej.cjs');
14
14
  require('axios');
15
15
  require('node:events');
16
16
  require('socket.io-client');
17
- var attachmentLimits = require('./attachmentLimits-CzVrqgLR.cjs');
17
+ var attachmentLimits = require('./attachmentLimits-DzlBPyJP.cjs');
18
18
  require('tweetnacl');
19
- var configuration = require('./configuration-BSYpcPwE.cjs');
20
- require('./index-DA7yINuk.cjs');
21
- require('./registerCommonHandlers-DskirN-_.cjs');
19
+ var configuration = require('./configuration-UsI0sxEv.cjs');
20
+ require('./index-DJ-oV52i.cjs');
21
+ require('./registerCommonHandlers-CMROPdJz.cjs');
22
22
  require('os');
23
23
  require('child_process');
24
24
  require('@paralleldrive/cuid2');
25
- require('./persistence-yKTH3-5X.cjs');
25
+ require('./persistence-i0nQMLlk.cjs');
26
26
  var contentLogMetadata = require('./contentLogMetadata-ZSFk_NjQ.cjs');
27
27
  require('chalk');
28
28
  var types = require('./types-CRS-srZK.cjs');
29
29
  var path = require('./path-B7zW-WwE.cjs');
30
30
  var fs = require('fs/promises');
31
- var time = require('./time-DCuTyook.cjs');
32
- var sessionScanner = require('./sessionScanner-BOrGjMXL.cjs');
31
+ var time = require('./time-CLwVAz6s.cjs');
32
+ var node_fs = require('node:fs');
33
+ var deterministicJson = require('./deterministicJson-eha_oMZ2.cjs');
34
+ var sessionScanner = require('./sessionScanner-aLEv7mD3.cjs');
33
35
  var node_child_process = require('node:child_process');
34
- var streamRelay = require('./streamRelay-BiKw59Cc.cjs');
35
- var attachmentContent = require('./attachmentContent-DpiTJZb4.cjs');
36
- var registerKillSessionHandler = require('./registerKillSessionHandler-DZeLXWcB.cjs');
37
- var deterministicJson = require('./deterministicJson-C5CYTVpm.cjs');
38
- var doctor = require('./doctor-D2YJ-Yn2.cjs');
36
+ var streamRelay = require('./streamRelay-DnObXZZj.cjs');
37
+ var attachmentContent = require('./attachmentContent-GHOk6Muq.cjs');
38
+ var promises = require('node:fs/promises');
39
+ var claudeSessionFork = require('./claudeSessionFork-D9-mANmu.cjs');
40
+ var registerKillSessionHandler = require('./registerKillSessionHandler-CA9-oelM.cjs');
41
+ var doctor = require('./doctor-DunLBgVi.cjs');
39
42
  var node_http = require('node:http');
40
43
  var editPaths = require('./editPaths-Bqp4OFPw.cjs');
41
- var node_fs = require('node:fs');
42
44
  var projectPath = require('./projectPath-ChLhdOyt.cjs');
43
- var titleGenerator = require('./titleGenerator-ChzMJsyg.cjs');
45
+ var titleGenerator = require('./titleGenerator-FDpdizn7.cjs');
44
46
  var oneShotPrompts = require('./oneShotPrompts-CL0dip9C.cjs');
45
47
  require('node:util');
46
48
  require('./smallFastModel-D_uxGMo3.cjs');
@@ -48,34 +50,34 @@ require('./trimIdent-4gvk9Wk6.cjs');
48
50
  require('node:os');
49
51
  require('./agentGuidance-B5NATuFa.cjs');
50
52
  require('zod');
51
- require('./package-BwMrPwqH.cjs');
52
- require('node:fs/promises');
53
+ require('./package-D1A-8ZJy.cjs');
53
54
  require('util');
54
55
  require('crypto');
55
56
  require('path');
56
57
  require('cross-spawn');
57
58
  require('./authRelay-BdYkC1Po.cjs');
58
- require('./sync-DccIKZ5_.cjs');
59
- require('./startFileWatcher-B4VsLgjD.cjs');
60
- require('./client-3Ac-O4pw.cjs');
61
- require('./context-DsDr6E2t.cjs');
62
- require('./sessionOps-Dn8z85h_.cjs');
59
+ require('./client-DiBTHWNU.cjs');
60
+ require('./context-0FjjA4vJ.cjs');
61
+ require('./sessionOps-GsELm2PZ.cjs');
63
62
  require('./resources-JDPugcDq.cjs');
64
- require('./tools-Be3AoAwu.cjs');
65
- require('./tools-DQj0AeLk.cjs');
66
- require('./client-BPNbmtvO.cjs');
67
- require('./peerTools-BvKtHXj8.cjs');
63
+ require('./tools-O5beDK-s.cjs');
64
+ require('./tools-CGxq3I52.cjs');
65
+ require('./client-CVQJWqjx.cjs');
66
+ require('./peerTools-DLwNaEEV.cjs');
68
67
  require('./ids-B6ZC0HGt.cjs');
69
- require('./remoteSessionClient-B0LraSB9.cjs');
68
+ require('./remoteSessionClient-DX9jHLeW.cjs');
70
69
  require('@modelcontextprotocol/sdk/server/mcp.js');
71
70
  require('@modelcontextprotocol/sdk/server/streamableHttp.js');
72
71
  require('./limits-C-a7gr04.cjs');
73
- require('./assistantTools-BTqPnlFl.cjs');
72
+ require('./assistantTools-CwESq24n.cjs');
74
73
  require('./terminals-B_bfC9c2.cjs');
75
74
  require('./terminalTitleSuggest-DhvRFX3H.cjs');
76
75
  require('./tmuxSocket-D-Xt6Vn-.cjs');
77
- require('./bootstrap-B5G1TijC.cjs');
76
+ require('./bootstrap-DvZjEa9_.cjs');
78
77
  require('./previewPath-B0rBdhy1.cjs');
78
+ require('./sync-Dj92ZJ8Y.cjs');
79
+ require('./startFileWatcher-C2HC2_Dg.cjs');
80
+ require('node:readline');
79
81
  require('./doctor-u46qYYKX.cjs');
80
82
  require('ps-list');
81
83
  require('./doctorReadiness-BCZGcN0a.cjs');
@@ -143,6 +145,20 @@ class Session {
143
145
  steerHandler = null;
144
146
  /** B-482: the live remote Query's in-process side-question entry; null between Queries and in local mode. */
145
147
  sideQuestionLive = null;
148
+ /** B-515: consumed by the first remote launch; later launches never prewarm. */
149
+ claudePrewarm = null;
150
+ /** Hand the prewarm lease to the first remote launch — once per process. */
151
+ takeClaudePrewarm = () => {
152
+ const factory = this.claudePrewarm;
153
+ this.claudePrewarm = null;
154
+ if (!factory || this.sessionId) return null;
155
+ try {
156
+ return factory();
157
+ } catch (error) {
158
+ logger.logger.debug("[Session] Claude prewarm setup failed:", error);
159
+ return null;
160
+ }
161
+ };
146
162
  /** Callbacks to be notified when session ID is found/changed */
147
163
  sessionFoundCallbacks = [];
148
164
  /** Keep alive interval reference for cleanup */
@@ -163,6 +179,7 @@ class Session {
163
179
  this._onAbort = opts.onAbort;
164
180
  this.hookSettingsPath = opts.hookSettingsPath;
165
181
  this.jsRuntime = opts.jsRuntime ?? "node";
182
+ this.claudePrewarm = opts.claudePrewarm ?? null;
166
183
  try {
167
184
  this.notificationProducer = opts.api.notificationProducer(
168
185
  opts.client.sessionId,
@@ -697,6 +714,285 @@ function modelSwitchFailureNotice(model, error) {
697
714
  return `\u26A0\uFE0F Could not switch to model "${name}" \u2014 continuing with the previous model. ${detail}`;
698
715
  }
699
716
 
717
+ const SDK_TIMING_FIELDS = ["ttft_ms", "time_to_request_ms", "time_to_request_from_spawn_ms"];
718
+ function delta(from, to) {
719
+ if (typeof from !== "number" || typeof to !== "number" || to < from) return "-";
720
+ return `${Math.round(to - from)}ms`;
721
+ }
722
+ function sdkField(result, key) {
723
+ if (!result || typeof result !== "object") return "-";
724
+ const value = result[key];
725
+ return typeof value === "number" && Number.isFinite(value) ? `${Math.round(value)}` : "-";
726
+ }
727
+ function formatClaudeTimingLine(input) {
728
+ const m = input.marks;
729
+ const sdk = SDK_TIMING_FIELDS.map((key) => `${key}=${sdkField(input.result, key)}`).join(",");
730
+ return [
731
+ "[CLAUDE TIMING]",
732
+ `turn=${input.turn}`,
733
+ `firstTurnOfProcess=${input.firstTurnOfProcess}`,
734
+ `pushed\u2192spawn=${delta(m.pushedAt, m.spawnAt)}`,
735
+ `spawn\u2192handshake=${delta(m.spawnAt, m.handshakeAt)}`,
736
+ `handshake\u2192init=${delta(m.handshakeAt, m.initAt)}`,
737
+ `init\u2192firstAssistant=${delta(m.initAt, m.firstAssistantAt)}`,
738
+ `pushed\u2192firstAssistant=${delta(m.pushedAt, m.firstAssistantAt)}`,
739
+ `sdk{${sdk}}`,
740
+ ...input.prewarm ? [`prewarm=${input.prewarm}`] : []
741
+ ].join(" ");
742
+ }
743
+
744
+ function claudeModeHash(mode) {
745
+ return deterministicJson.hashObject({
746
+ isPlan: mode.permissionMode === "plan",
747
+ fallbackModel: mode.fallbackModel,
748
+ customSystemPrompt: mode.customSystemPrompt,
749
+ appendSystemPrompt: mode.appendSystemPrompt,
750
+ allowedTools: mode.allowedTools,
751
+ disallowedTools: mode.disallowedTools,
752
+ effort: mode.effort
753
+ });
754
+ }
755
+
756
+ const CLAUDE_PREWARM_IDLE_MS = 15 * 60 * 1e3;
757
+ const CLAUDE_PREWARM_MAX_CONCURRENT = 2;
758
+ const CLAUDE_PREWARM_ADOPT_TIMEOUT_MS = 5e3;
759
+ const PREWARM_HOOK_SOURCE_PREFIX = "prewarm-";
760
+ const BAD_AUTH_STATUSES = /* @__PURE__ */ new Set(["not-logged-in", "error", "claude-missing"]);
761
+ const RESUME_ARGS = /* @__PURE__ */ new Set(["--resume", "-r", "--continue", "-c", "--fork-session", "--session-id"]);
762
+ const CLAUDE_PREWARM_MAX_CONSECUTIVE_MISSES = 5;
763
+ function claudePrewarmSessionEligibility(input) {
764
+ const { env } = input;
765
+ const no = (reason) => ({ eligible: false, reason });
766
+ if (env.HAPPY_CLAUDE_PREWARM === "0") return no("env-off");
767
+ if (input.setting === "off") return no("setting-off");
768
+ if (input.startedBy !== "daemon") return no("not-daemon");
769
+ if (input.startingMode !== "remote") return no("not-remote");
770
+ if (env.HAPPY_RECONNECT_SESSION_ID) return no("reconnect");
771
+ if (env.HAPPY_FORK_CLAUDE_SESSION_ID || env.HAPPY_FORKED_FROM_SESSION_ID) return no("fork");
772
+ if (env.HAPPY_IMPORTED_FROM_CLAUDE_SESSION_ID) return no("import");
773
+ if (env.HAPPY_SESSION_VARIANT === "assistant") return no("assistant");
774
+ if (env.VH_TEAM_OPERATION_ID) return no("teams");
775
+ if (env.VH_AUTOMATION_RUN_ID) return no("automation");
776
+ if (env.HAPPY_SPAWNED_BY) return no("spawned-by");
777
+ if (env.HAPPY_FIRST_MESSAGE_FROM_CLI === "1") return no("cli-first-message");
778
+ if (input.claudeArgs?.some((arg) => RESUME_ARGS.has(arg))) return no("resume-args");
779
+ if (env.HAPPY_CLAUDE_AUTH_STATUS && BAD_AUTH_STATUSES.has(env.HAPPY_CLAUDE_AUTH_STATUS)) return no("claude-auth");
780
+ return { eligible: true };
781
+ }
782
+ function claudePrewarmEligibility(input) {
783
+ const session = claudePrewarmSessionEligibility(input);
784
+ if (!session.eligible) return session;
785
+ if (!input.cache?.appendSystemPrompt) return { eligible: false, reason: "no-cached-system-prompt" };
786
+ if (input.cache.consecutiveMisses >= CLAUDE_PREWARM_MAX_CONSECUTIVE_MISSES) return { eligible: false, reason: "recent-misses" };
787
+ return { eligible: true };
788
+ }
789
+ function prewarmCacheFile(happyHomeDir) {
790
+ return path$1.join(happyHomeDir, "claude-prewarm.json");
791
+ }
792
+ function readPrewarmCache(file) {
793
+ try {
794
+ const raw = JSON.parse(node_fs.readFileSync(file, "utf8"));
795
+ if (typeof raw?.appendSystemPrompt !== "string" || raw.appendSystemPrompt.length === 0) return null;
796
+ const misses = typeof raw.consecutiveMisses === "number" && Number.isFinite(raw.consecutiveMisses) && raw.consecutiveMisses > 0 ? Math.floor(raw.consecutiveMisses) : 0;
797
+ return {
798
+ appendSystemPrompt: raw.appendSystemPrompt,
799
+ ...typeof raw.effort === "string" || raw.effort === null ? { effort: raw.effort } : {},
800
+ consecutiveMisses: misses
801
+ };
802
+ } catch {
803
+ return null;
804
+ }
805
+ }
806
+ function writePrewarmCache(file, cache) {
807
+ try {
808
+ const tmp = `${file}.${process.pid}.tmp`;
809
+ node_fs.writeFileSync(tmp, JSON.stringify({ ...cache, updatedAt: Date.now() }), { mode: 384 });
810
+ node_fs.renameSync(tmp, file);
811
+ return true;
812
+ } catch {
813
+ return false;
814
+ }
815
+ }
816
+ function prewarmPredictionMeta(cache) {
817
+ return {
818
+ appendSystemPrompt: cache.appendSystemPrompt,
819
+ ...cache.effort !== void 0 ? { effort: cache.effort } : {}
820
+ };
821
+ }
822
+ function evaluatePrewarmPrediction(input) {
823
+ const outcome = input.predicted === null ? "no-prediction" : claudeModeHash(input.predicted) === claudeModeHash(input.actual) ? "hit" : "miss";
824
+ const append = input.meta?.appendSystemPrompt;
825
+ const misses = outcome === "miss" ? (input.previous?.consecutiveMisses ?? 0) + 1 : 0;
826
+ if (typeof append !== "string" || append.length === 0) {
827
+ return { outcome, next: input.previous ? { ...input.previous, consecutiveMisses: misses } : null };
828
+ }
829
+ const hasEffort = !!input.meta && Object.prototype.hasOwnProperty.call(input.meta, "effort");
830
+ return {
831
+ outcome,
832
+ next: {
833
+ appendSystemPrompt: append,
834
+ ...hasEffort ? { effort: input.meta.effort ?? null } : {},
835
+ consecutiveMisses: misses
836
+ }
837
+ };
838
+ }
839
+ function prewarmSlotDir(happyHomeDir) {
840
+ return path$1.join(happyHomeDir, "tmp", "claude-prewarm");
841
+ }
842
+ function acquirePrewarmSlot(dir, opts = {}) {
843
+ const max = opts.max ?? CLAUDE_PREWARM_MAX_CONCURRENT;
844
+ const pid = opts.pid ?? process.pid;
845
+ const isAlive = opts.isAlive ?? pidAlive;
846
+ const now = opts.now ?? Date.now();
847
+ const staleMs = opts.staleMs ?? CLAUDE_PREWARM_IDLE_MS + 6e4;
848
+ try {
849
+ node_fs.mkdirSync(dir, { recursive: true, mode: 448 });
850
+ } catch {
851
+ return null;
852
+ }
853
+ for (let i = 0; i < max; i++) {
854
+ const path = path$1.join(dir, `slot-${i}.lock`);
855
+ for (let attempt = 0; attempt < 2; attempt++) {
856
+ try {
857
+ node_fs.writeFileSync(path, String(pid), { flag: "wx", mode: 384 });
858
+ let released = false;
859
+ return {
860
+ path,
861
+ release: () => {
862
+ if (released) return;
863
+ released = true;
864
+ try {
865
+ if (node_fs.readFileSync(path, "utf8").trim() === String(pid)) node_fs.unlinkSync(path);
866
+ } catch {
867
+ }
868
+ }
869
+ };
870
+ } catch (error) {
871
+ if (error?.code !== "EEXIST") return null;
872
+ if (!slotIsStale(path, { isAlive, now, staleMs }) || attempt > 0) break;
873
+ try {
874
+ node_fs.unlinkSync(path);
875
+ } catch {
876
+ }
877
+ }
878
+ }
879
+ }
880
+ return null;
881
+ }
882
+ function slotIsStale(path, opts) {
883
+ try {
884
+ const owner = Number(node_fs.readFileSync(path, "utf8").trim());
885
+ if (!Number.isInteger(owner) || owner <= 0 || !opts.isAlive(owner)) return true;
886
+ return opts.now - node_fs.statSync(path).mtimeMs > opts.staleMs;
887
+ } catch {
888
+ return !node_fs.existsSync(path);
889
+ }
890
+ }
891
+ function pidAlive(pid) {
892
+ try {
893
+ process.kill(pid, 0);
894
+ return true;
895
+ } catch (error) {
896
+ return error?.code === "EPERM";
897
+ }
898
+ }
899
+ class PrewarmHookGate {
900
+ next = 0;
901
+ adopted = /* @__PURE__ */ new Set();
902
+ newTag() {
903
+ return `${PREWARM_HOOK_SOURCE_PREFIX}${process.pid}-${this.next++}`;
904
+ }
905
+ adopt(tag) {
906
+ this.adopted.add(tag);
907
+ }
908
+ /** Untagged hooks (the ordinary per-process settings file) always pass. */
909
+ accepts(source) {
910
+ if (!source || !source.startsWith(PREWARM_HOOK_SOURCE_PREFIX)) return true;
911
+ return this.adopted.has(source);
912
+ }
913
+ }
914
+ function decideWarmAdoption(input) {
915
+ if (input.specialCommand === "clear") return { adopt: false, reason: "clear" };
916
+ if (input.specialCommand === "compact") return { adopt: false, reason: "compact" };
917
+ if (claudeModeHash(input.predicted) !== claudeModeHash(input.actual)) return { adopt: false, reason: "mode-mismatch" };
918
+ const warmPermission = permissionMode.mapToClaudeMode(input.predicted.permissionMode);
919
+ const wantedPermission = permissionMode.mapToClaudeMode(input.actual.permissionMode);
920
+ return {
921
+ adopt: true,
922
+ ...warmPermission !== wantedPermission ? { setPermissionMode: wantedPermission } : {},
923
+ switchModel: needsModelSwitch(input.predicted.model, input.actual.model)
924
+ };
925
+ }
926
+ function formatPrewarmLine(event, detail) {
927
+ if (event === "discarded" || event === "skipped") {
928
+ return `[CLAUDE PREWARM] ${event}(${typeof detail === "string" ? detail : "unknown"})`;
929
+ }
930
+ const fields = detail && typeof detail === "object" ? Object.entries(detail).filter(([, v]) => v !== void 0).map(([k, v]) => ` ${k}=${v}`).join("") : "";
931
+ return `[CLAUDE PREWARM] ${event}${fields}`;
932
+ }
933
+ const liveLeases = /* @__PURE__ */ new Set();
934
+ let exitHookInstalled = false;
935
+ function disposeAllClaudePrewarms(reason) {
936
+ for (const lease of [...liveLeases]) lease.discard(reason);
937
+ }
938
+ function createClaudePrewarmLease(input) {
939
+ let state = "warm";
940
+ let teardown = null;
941
+ const lease = {
942
+ mode: input.mode,
943
+ hookSettingsPath: input.hookSettingsPath,
944
+ tag: input.tag,
945
+ idleMs: input.idleMs ?? CLAUDE_PREWARM_IDLE_MS,
946
+ adoptTimeoutMs: input.adoptTimeoutMs ?? CLAUDE_PREWARM_ADOPT_TIMEOUT_MS,
947
+ adopt: () => {
948
+ if (state !== "warm") return;
949
+ state = "adopted";
950
+ teardown = null;
951
+ input.gate.adopt(input.tag);
952
+ input.slot.release();
953
+ liveLeases.delete(lease);
954
+ },
955
+ discard: (reason) => {
956
+ if (state !== "warm") return;
957
+ state = "closed";
958
+ const t = teardown;
959
+ teardown = null;
960
+ liveLeases.delete(lease);
961
+ try {
962
+ t?.(reason);
963
+ } catch {
964
+ }
965
+ input.slot.release();
966
+ input.cleanupHookSettings();
967
+ input.log(formatPrewarmLine("discarded", reason));
968
+ },
969
+ setTeardown: (next) => {
970
+ if (state === "warm") teardown = next;
971
+ }
972
+ };
973
+ liveLeases.add(lease);
974
+ if (!exitHookInstalled) {
975
+ exitHookInstalled = true;
976
+ process.once("exit", () => disposeAllClaudePrewarms("exit"));
977
+ }
978
+ return lease;
979
+ }
980
+
981
+ function withTimeout(promise, ms) {
982
+ promise.catch(() => {
983
+ });
984
+ let timer;
985
+ const timeout = new Promise((_, reject) => {
986
+ timer = setTimeout(() => reject(new Error(`timed out after ${ms}ms`)), ms);
987
+ });
988
+ return Promise.race([promise, timeout]).finally(() => {
989
+ if (timer) clearTimeout(timer);
990
+ });
991
+ }
992
+ const PROMPT_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
993
+ function promptUuid(uuid) {
994
+ return uuid && PROMPT_UUID_RE.test(uuid) ? { uuid } : {};
995
+ }
700
996
  async function claudeRemote(opts) {
701
997
  let startFrom = opts.sessionId;
702
998
  if (opts.sessionId && !systemPrompt.claudeCheckSession(opts.sessionId, opts.path)) {
@@ -727,13 +1023,153 @@ async function claudeRemote(opts) {
727
1023
  process.env[key] = value;
728
1024
  });
729
1025
  }
730
- const initial = await opts.nextMessage();
1026
+ let thinking = false;
1027
+ const updateThinking = (newThinking) => {
1028
+ if (thinking !== newThinking) {
1029
+ thinking = newThinking;
1030
+ logger.logger.debug(`[claudeRemote] Thinking state changed to: ${thinking}`);
1031
+ if (opts.onThinkingChange) {
1032
+ opts.onThinkingChange(thinking);
1033
+ }
1034
+ }
1035
+ };
1036
+ let callbackDepth = 0;
1037
+ const guardCallback = (callback) => (async (...args) => {
1038
+ callbackDepth++;
1039
+ try {
1040
+ return await callback(...args);
1041
+ } finally {
1042
+ setImmediate(() => {
1043
+ callbackDepth--;
1044
+ });
1045
+ }
1046
+ });
1047
+ let mode = opts.prewarm?.mode ?? { permissionMode: "default" };
1048
+ const buildSdkOptions = (creationMode, io) => {
1049
+ const sdkOptions = {
1050
+ cwd: opts.path,
1051
+ resume: startFrom ?? void 0,
1052
+ mcpServers: opts.mcpServers,
1053
+ permissionMode: permissionMode.mapToClaudeMode(creationMode.permissionMode),
1054
+ // This is only the SDK safety opt-in; permissionMode/canUseTool still
1055
+ // enforce the selected policy. It must be enabled at Query creation so
1056
+ // a later explicit live switch to bypassPermissions can succeed.
1057
+ allowDangerouslySkipPermissions: true,
1058
+ model: creationMode.model,
1059
+ fallbackModel: creationMode.fallbackModel,
1060
+ customSystemPrompt: creationMode.customSystemPrompt ? creationMode.customSystemPrompt + "\n\n" + systemPrompt.systemPrompt : void 0,
1061
+ appendSystemPrompt: creationMode.appendSystemPrompt ? creationMode.appendSystemPrompt + "\n\n" + systemPrompt.systemPrompt : systemPrompt.systemPrompt,
1062
+ allowedTools: creationMode.allowedTools ? creationMode.allowedTools.concat(opts.allowedTools) : opts.allowedTools,
1063
+ additionalDirectories: opts.additionalDirectories,
1064
+ disallowedTools: creationMode.disallowedTools,
1065
+ effort: creationMode.effort,
1066
+ canCallTool: (toolName, input, options) => opts.canCallTool(toolName, input, mode, options),
1067
+ onElicitation: opts.onElicitation,
1068
+ onUserDialog: opts.onUserDialog,
1069
+ supportedDialogKinds: opts.onUserDialog ? ["refusal_fallback_prompt"] : void 0,
1070
+ abort: io.abort,
1071
+ settingsPath: io.settingsPath,
1072
+ // B-309: token-level partials. Without this the SDK emits nothing
1073
+ // between "turn started" and "entire assistant message", which is
1074
+ // exactly why the web used to show a spinner where the terminal shows
1075
+ // the model thinking out loud. The partials do NOT enter the
1076
+ // transcript; they are split off below and relayed on a side channel.
1077
+ // Only pay for them when someone is listening.
1078
+ includePartialMessages: opts.onStreamFrame ? true : void 0
1079
+ };
1080
+ if (sdkOptions.canCallTool) sdkOptions.canCallTool = guardCallback(sdkOptions.canCallTool);
1081
+ if (sdkOptions.onElicitation) sdkOptions.onElicitation = guardCallback(sdkOptions.onElicitation);
1082
+ if (sdkOptions.onUserDialog) sdkOptions.onUserDialog = guardCallback(sdkOptions.onUserDialog);
1083
+ return sdkOptions;
1084
+ };
1085
+ const discoverModels = async (q) => {
1086
+ if (typeof q.supportedModels !== "function") return void 0;
1087
+ return (await q.supportedModels()).map((model) => ({
1088
+ code: model.value,
1089
+ value: model.displayName,
1090
+ description: model.description,
1091
+ resolvedModel: model.resolvedModel,
1092
+ ...model.supportsEffort === false ? { reasoningEfforts: [] } : model.supportedEffortLevels ? { reasoningEfforts: model.supportedEffortLevels } : {}
1093
+ }));
1094
+ };
1095
+ let warm = null;
1096
+ if (opts.prewarm && startFrom) {
1097
+ opts.prewarm.discard("resume");
1098
+ } else if (opts.prewarm && opts.signal?.aborted) {
1099
+ opts.prewarm.discard("aborted");
1100
+ } else if (opts.prewarm) {
1101
+ const lease = opts.prewarm;
1102
+ const abort = new AbortController();
1103
+ const onOuterAbort = () => abort.abort();
1104
+ opts.signal?.addEventListener("abort", onOuterAbort, { once: true });
1105
+ const messages2 = new PushableAsyncIterable();
1106
+ const startedAt = Date.now();
1107
+ try {
1108
+ const response2 = index.query({
1109
+ prompt: messages2,
1110
+ options: buildSdkOptions(lease.mode, { settingsPath: lease.hookSettingsPath, abort: abort.signal })
1111
+ });
1112
+ const handshake = discoverModels(response2).then(
1113
+ (models2) => ({ ok: true, models: models2, at: Date.now() }),
1114
+ () => ({ ok: false, at: Date.now() })
1115
+ );
1116
+ const w = { response: response2, messages: messages2, lease, startedAt, handshake };
1117
+ lease.setTeardown(() => {
1118
+ if (w.idleTimer) clearTimeout(w.idleTimer);
1119
+ try {
1120
+ w.offExit?.();
1121
+ } catch {
1122
+ }
1123
+ opts.signal?.removeEventListener("abort", onOuterAbort);
1124
+ if (warm === w) warm = null;
1125
+ messages2.end();
1126
+ abort.abort();
1127
+ });
1128
+ w.idleTimer = setTimeout(() => lease.discard("idle"), lease.idleMs);
1129
+ w.idleTimer.unref?.();
1130
+ void handshake.then((result) => {
1131
+ if (!result.ok) {
1132
+ lease.discard("handshake-failed");
1133
+ return;
1134
+ }
1135
+ if (warm !== w) return;
1136
+ try {
1137
+ const transport = response2.transport;
1138
+ const off = transport?.onExit?.(() => {
1139
+ if (warm === w) lease.discard("exited");
1140
+ });
1141
+ if (typeof off === "function") w.offExit = off;
1142
+ } catch {
1143
+ }
1144
+ });
1145
+ warm = w;
1146
+ logger.logger.debug(formatPrewarmLine("started", { tag: lease.tag }));
1147
+ } catch (error) {
1148
+ opts.signal?.removeEventListener("abort", onOuterAbort);
1149
+ logger.logger.debug(`[claudeRemote] prewarm query() threw: ${error instanceof Error ? error.message : String(error)}`);
1150
+ lease.discard("spawn-failed");
1151
+ }
1152
+ }
1153
+ const discardWarm = (reason) => {
1154
+ warm?.lease.discard(reason);
1155
+ };
1156
+ let initial;
1157
+ try {
1158
+ initial = await opts.nextMessage();
1159
+ } catch (error) {
1160
+ discardWarm("error");
1161
+ throw error;
1162
+ }
731
1163
  if (!initial) {
1164
+ discardWarm("exit");
732
1165
  return;
733
1166
  }
1167
+ let timingTurn = 1;
1168
+ let timingMarks = { pushedAt: initial.enqueuedAt ?? Date.now() };
734
1169
  const initialText = typeof initial.message === "string" ? initial.message : initial.message.find((b) => b.type === "text")?.text ?? "";
735
1170
  const specialCommand = specialCommands.parseSpecialCommand(initialText);
736
1171
  if (specialCommand.type === "clear") {
1172
+ discardWarm("clear");
737
1173
  if (opts.onCompletionEvent) {
738
1174
  opts.onCompletionEvent("Context was reset");
739
1175
  }
@@ -751,90 +1187,95 @@ async function claudeRemote(opts) {
751
1187
  opts.onCompletionEvent("Compaction started");
752
1188
  }
753
1189
  }
754
- let mode = initial.mode;
755
- const sdkOptions = {
756
- cwd: opts.path,
757
- resume: startFrom ?? void 0,
758
- mcpServers: opts.mcpServers,
759
- permissionMode: permissionMode.mapToClaudeMode(initial.mode.permissionMode),
760
- // This is only the SDK safety opt-in; permissionMode/canUseTool still
761
- // enforce the selected policy. It must be enabled at Query creation so
762
- // a later explicit live switch to bypassPermissions can succeed.
763
- allowDangerouslySkipPermissions: true,
764
- model: initial.mode.model,
765
- fallbackModel: initial.mode.fallbackModel,
766
- customSystemPrompt: initial.mode.customSystemPrompt ? initial.mode.customSystemPrompt + "\n\n" + systemPrompt.systemPrompt : void 0,
767
- appendSystemPrompt: initial.mode.appendSystemPrompt ? initial.mode.appendSystemPrompt + "\n\n" + systemPrompt.systemPrompt : systemPrompt.systemPrompt,
768
- allowedTools: initial.mode.allowedTools ? initial.mode.allowedTools.concat(opts.allowedTools) : opts.allowedTools,
769
- additionalDirectories: opts.additionalDirectories,
770
- disallowedTools: initial.mode.disallowedTools,
771
- effort: initial.mode.effort,
772
- canCallTool: (toolName, input, options) => opts.canCallTool(toolName, input, mode, options),
773
- onElicitation: opts.onElicitation,
774
- onUserDialog: opts.onUserDialog,
775
- supportedDialogKinds: opts.onUserDialog ? ["refusal_fallback_prompt"] : void 0,
776
- abort: opts.signal,
777
- settingsPath: opts.hookSettingsPath,
778
- // B-309: token-level partials. Without this the SDK emits nothing
779
- // between "turn started" and "entire assistant message", which is
780
- // exactly why the web used to show a spinner where the terminal shows
781
- // the model thinking out loud. The partials do NOT enter the
782
- // transcript; they are split off below and relayed on a side channel.
783
- // Only pay for them when someone is listening.
784
- includePartialMessages: opts.onStreamFrame ? true : void 0
785
- };
786
- let thinking = false;
787
- const updateThinking = (newThinking) => {
788
- if (thinking !== newThinking) {
789
- thinking = newThinking;
790
- logger.logger.debug(`[claudeRemote] Thinking state changed to: ${thinking}`);
791
- if (opts.onThinkingChange) {
792
- opts.onThinkingChange(thinking);
1190
+ let adopted = null;
1191
+ if (warm) {
1192
+ const w = warm;
1193
+ const adoptStart = Date.now();
1194
+ const decision = decideWarmAdoption({ predicted: w.lease.mode, actual: initial.mode, specialCommand: specialCommand.type });
1195
+ let reason = decision.adopt ? null : decision.reason;
1196
+ const hs = reason ? null : await w.handshake;
1197
+ if (!reason) {
1198
+ if (warm !== w) {
1199
+ reason = "closed";
1200
+ } else if (!hs?.ok) {
1201
+ reason = "handshake-failed";
1202
+ } else if (decision.adopt) {
1203
+ try {
1204
+ if (decision.setPermissionMode) {
1205
+ await withTimeout(w.response.setPermissionMode(decision.setPermissionMode), w.lease.adoptTimeoutMs);
1206
+ } else {
1207
+ await withTimeout(w.response.mcpServerStatus(), w.lease.adoptTimeoutMs);
1208
+ }
1209
+ } catch {
1210
+ reason = decision.setPermissionMode ? "set-permission-failed" : "not-alive";
1211
+ }
1212
+ if (!reason && decision.switchModel) {
1213
+ try {
1214
+ await withTimeout(w.response.setModel(modelTarget(initial.mode.model)), w.lease.adoptTimeoutMs);
1215
+ } catch {
1216
+ reason = "set-model-failed";
1217
+ }
1218
+ }
1219
+ if (!reason && warm !== w) reason = "closed";
793
1220
  }
794
1221
  }
795
- };
796
- let messages = new PushableAsyncIterable();
797
- messages.push({
1222
+ if (reason || !hs?.ok) {
1223
+ w.lease.discard(reason ?? "handshake-failed");
1224
+ warm = null;
1225
+ } else {
1226
+ if (w.idleTimer) clearTimeout(w.idleTimer);
1227
+ try {
1228
+ w.offExit?.();
1229
+ } catch {
1230
+ }
1231
+ warm = null;
1232
+ w.lease.adopt();
1233
+ adopted = { response: w.response, messages: w.messages, models: hs.models };
1234
+ logger.logger.debug(formatPrewarmLine("adopted", {
1235
+ warmForMs: adoptStart - w.startedAt,
1236
+ handshakeWaitMs: Math.max(0, hs.at - adoptStart),
1237
+ adoptMs: Date.now() - adoptStart,
1238
+ setPermissionMode: decision.adopt ? decision.setPermissionMode : void 0,
1239
+ setModel: decision.adopt && decision.switchModel ? true : void 0
1240
+ }));
1241
+ }
1242
+ }
1243
+ mode = initial.mode;
1244
+ const initialUserMessage = {
798
1245
  type: "user",
799
1246
  parent_tool_use_id: null,
800
1247
  origin: { kind: "human" },
1248
+ ...promptUuid(initial.uuid),
801
1249
  message: {
802
1250
  role: "user",
803
1251
  content: initial.message
804
1252
  }
805
- });
806
- let callbackDepth = 0;
807
- const guardCallback = (callback) => (async (...args) => {
808
- callbackDepth++;
809
- try {
810
- return await callback(...args);
811
- } finally {
812
- setImmediate(() => {
813
- callbackDepth--;
814
- });
815
- }
816
- });
817
- if (sdkOptions.canCallTool) sdkOptions.canCallTool = guardCallback(sdkOptions.canCallTool);
818
- if (sdkOptions.onElicitation) sdkOptions.onElicitation = guardCallback(sdkOptions.onElicitation);
819
- if (sdkOptions.onUserDialog) sdkOptions.onUserDialog = guardCallback(sdkOptions.onUserDialog);
820
- const response = index.query({
821
- prompt: messages,
822
- options: sdkOptions
823
- });
1253
+ };
1254
+ let messages;
1255
+ let response;
824
1256
  let models;
825
- if (typeof response.supportedModels === "function") {
1257
+ if (adopted) {
1258
+ messages = adopted.messages;
1259
+ response = adopted.response;
1260
+ models = adopted.models;
1261
+ timingMarks.handshakeAt = Date.now();
1262
+ messages.push(initialUserMessage);
1263
+ } else {
1264
+ messages = new PushableAsyncIterable();
1265
+ messages.push(initialUserMessage);
1266
+ timingMarks.spawnAt = Date.now();
1267
+ response = index.query({
1268
+ prompt: messages,
1269
+ options: buildSdkOptions(initial.mode, { settingsPath: opts.hookSettingsPath, abort: opts.signal })
1270
+ });
826
1271
  try {
827
- models = (await response.supportedModels()).map((model) => ({
828
- code: model.value,
829
- value: model.displayName,
830
- description: model.description,
831
- resolvedModel: model.resolvedModel,
832
- ...model.supportsEffort === false ? { reasoningEfforts: [] } : model.supportedEffortLevels ? { reasoningEfforts: model.supportedEffortLevels } : {}
833
- }));
1272
+ models = await discoverModels(response);
834
1273
  } catch (error) {
835
1274
  logger.logger.debug("[claudeRemote] Model capability discovery unavailable");
836
1275
  }
1276
+ timingMarks.handshakeAt = Date.now();
837
1277
  }
1278
+ const prewarmTiming = adopted ? "adopted" : void 0;
838
1279
  if (opts.onQueryReady) {
839
1280
  opts.onQueryReady({
840
1281
  canControl: () => callbackDepth === 0,
@@ -886,6 +1327,11 @@ async function claudeRemote(opts) {
886
1327
  if (message.type === "assistant" && message.error) {
887
1328
  lastAssistantError = message.error;
888
1329
  }
1330
+ if (message.type === "assistant" && timingMarks.firstAssistantAt === void 0) {
1331
+ timingMarks.firstAssistantAt = Date.now();
1332
+ } else if (message.type === "system" && message.subtype === "init" && timingMarks.initAt === void 0) {
1333
+ timingMarks.initAt = Date.now();
1334
+ }
889
1335
  if (opts.onStreamFrame && message.type === "system") {
890
1336
  const subtype = message.subtype;
891
1337
  if (subtype === "thinking_tokens") {
@@ -935,6 +1381,15 @@ async function claudeRemote(opts) {
935
1381
  if (message.type === "result") {
936
1382
  updateThinking(false);
937
1383
  logger.logger.debug("[claudeRemote] Result received");
1384
+ logger.logger.debug(formatClaudeTimingLine({
1385
+ turn: timingTurn,
1386
+ firstTurnOfProcess: timingTurn === 1,
1387
+ marks: timingMarks,
1388
+ result: message,
1389
+ prewarm: timingTurn === 1 ? prewarmTiming : void 0
1390
+ }));
1391
+ timingTurn++;
1392
+ timingMarks = {};
938
1393
  const denials = message.permission_denials;
939
1394
  if (denials && denials.length > 0) {
940
1395
  logger.logger.warn(`[claudeRemote] ${denials.length} tool call(s) auto-denied by Claude Code policy: ${denials.map((d) => d.tool_name ?? "?").join(", ")}`);
@@ -974,10 +1429,12 @@ async function claudeRemote(opts) {
974
1429
  }
975
1430
  mode = next.mode;
976
1431
  updateThinking(true);
1432
+ timingMarks = { pushedAt: next.enqueuedAt ?? Date.now() };
977
1433
  messages.push({
978
1434
  type: "user",
979
1435
  parent_tool_use_id: null,
980
1436
  origin: { kind: "human" },
1437
+ ...promptUuid(next.uuid),
981
1438
  message: { role: "user", content: next.message }
982
1439
  });
983
1440
  }).catch(() => {
@@ -2355,6 +2812,146 @@ class LaunchModeGate {
2355
2812
  }
2356
2813
  }
2357
2814
 
2815
+ class ConversationRewindError extends Error {
2816
+ constructor(code, message) {
2817
+ super(message);
2818
+ this.code = code;
2819
+ this.name = "ConversationRewindError";
2820
+ }
2821
+ }
2822
+ function transcriptPromptText(parsed) {
2823
+ if (parsed?.type !== "user" || parsed.isSidechain || parsed.isMeta || parsed.isSynthetic) return null;
2824
+ const content = parsed.message?.content;
2825
+ if (typeof content === "string") return content.trim() ? content : null;
2826
+ if (!Array.isArray(content) || content.some((block) => block?.type === "tool_result")) return null;
2827
+ const text = content.filter((block) => block?.type === "text" && typeof block.text === "string").map((block) => block.text).join("\n");
2828
+ if (!text.trim()) return content.length > 0 ? "" : null;
2829
+ return text;
2830
+ }
2831
+ function isConversationEntry(parsed) {
2832
+ return !parsed?.isSidechain && !parsed?.isMeta && !parsed?.isSynthetic && (parsed?.type === "user" || parsed?.type === "assistant");
2833
+ }
2834
+ function resolveRewindTarget(entries, target) {
2835
+ for (const uuid of target.uuids) {
2836
+ const index = entries.findIndex((entry) => entry.parsed?.uuid === uuid && transcriptPromptText(entry.parsed) !== null);
2837
+ if (index >= 0) return index;
2838
+ }
2839
+ const wanted = target.text?.trim();
2840
+ if (!wanted) throw new ConversationRewindError("not-found", "This message is not in the agent conversation");
2841
+ const matches = [];
2842
+ entries.forEach((entry, index) => {
2843
+ if (transcriptPromptText(entry.parsed)?.trim() === wanted) matches.push(index);
2844
+ });
2845
+ if (matches.length === 1) return matches[0];
2846
+ if (matches.length === 0) throw new ConversationRewindError("not-found", "This message is not in the agent conversation");
2847
+ throw new ConversationRewindError("ambiguous", "Several earlier messages have the same text; cannot tell which one to change");
2848
+ }
2849
+ function rewindTranscriptLines(lines, action, target) {
2850
+ const entries = [];
2851
+ for (const line of lines) {
2852
+ if (!line) continue;
2853
+ let parsed = null;
2854
+ try {
2855
+ parsed = JSON.parse(line);
2856
+ } catch {
2857
+ }
2858
+ entries.push({ line, parsed });
2859
+ }
2860
+ const cut = resolveRewindTarget(entries, target);
2861
+ let end = entries.length;
2862
+ for (let i = cut + 1; i < entries.length; i++) {
2863
+ if (transcriptPromptText(entries[i].parsed) !== null) {
2864
+ end = i;
2865
+ break;
2866
+ }
2867
+ }
2868
+ const before = entries.slice(0, cut);
2869
+ const after = action === "delete" ? entries.slice(end) : [];
2870
+ if (![...before, ...after].some((entry) => isConversationEntry(entry.parsed))) return null;
2871
+ if (before.some((entry) => isConversationEntry(entry.parsed)) && !before.some((entry) => transcriptPromptText(entry.parsed) !== null)) {
2872
+ throw new ConversationRewindError("unsafe", "Cannot safely rewind: earlier history has no user prompt");
2873
+ }
2874
+ if (after.length === 0) return before.map((entry) => entry.line);
2875
+ const dropped = /* @__PURE__ */ new Set();
2876
+ for (const entry of entries.slice(cut, end)) {
2877
+ if (typeof entry.parsed?.uuid === "string") dropped.add(entry.parsed.uuid);
2878
+ }
2879
+ const reparentTo = typeof entries[cut].parsed?.parentUuid === "string" ? entries[cut].parsed.parentUuid : null;
2880
+ const relinked = after.map((entry) => {
2881
+ const parsed = entry.parsed;
2882
+ if (!parsed || typeof parsed !== "object") return entry.line;
2883
+ let next = parsed;
2884
+ for (const key of ["parentUuid", "logicalParentUuid"]) {
2885
+ if (typeof parsed[key] === "string" && dropped.has(parsed[key])) {
2886
+ next = next === parsed ? { ...parsed } : next;
2887
+ next[key] = reparentTo;
2888
+ }
2889
+ }
2890
+ return next === parsed ? entry.line : JSON.stringify(next);
2891
+ });
2892
+ return [...before.map((entry) => entry.line), ...relinked];
2893
+ }
2894
+ async function rewindClaudeTranscript(projectDir, claudeSessionId, action, target) {
2895
+ const source = path$1.join(projectDir, `${claudeSessionId}.jsonl`);
2896
+ let raw;
2897
+ try {
2898
+ raw = await promises.readFile(source, "utf-8");
2899
+ } catch (error) {
2900
+ if (error.code === "ENOENT") throw new claudeSessionFork.ForkSourceMissingError(source);
2901
+ throw error;
2902
+ }
2903
+ const kept = rewindTranscriptLines(raw.split("\n"), action, target);
2904
+ if (kept === null) return null;
2905
+ const newId = node_crypto.randomUUID();
2906
+ const destination = path$1.join(projectDir, `${newId}.jsonl`);
2907
+ const temporary = `${destination}.tmp-${process.pid}`;
2908
+ try {
2909
+ await promises.writeFile(temporary, kept.join("\n") + "\n", { encoding: "utf-8", flag: "wx" });
2910
+ await promises.rename(temporary, destination);
2911
+ } catch (error) {
2912
+ await promises.unlink(temporary).catch(() => void 0);
2913
+ throw error;
2914
+ }
2915
+ return newId;
2916
+ }
2917
+
2918
+ const STOP_WAIT_MS = 8e3;
2919
+ function createConversationRewind(deps) {
2920
+ let inFlight = false;
2921
+ const rewrite = deps.rewrite ?? rewindClaudeTranscript;
2922
+ return async (input) => {
2923
+ const request = input && typeof input === "object" ? input : {};
2924
+ const action = request.action;
2925
+ const sourceId = typeof request.sourceId === "string" && request.sourceId.length > 0 && request.sourceId.length <= 200 ? request.sourceId : void 0;
2926
+ const text = typeof request.text === "string" && request.text.length <= 2e5 ? request.text : void 0;
2927
+ if (action !== "edit" && action !== "delete" || !sourceId && !text?.trim()) {
2928
+ return { ok: false, code: "invalid", error: "Invalid rewind request" };
2929
+ }
2930
+ if (inFlight) return { ok: false, code: "busy", error: "Another edit is still being applied" };
2931
+ inFlight = true;
2932
+ try {
2933
+ if (deps.isThinking()) {
2934
+ await deps.stopTurn();
2935
+ if (!await deps.waitIdle(STOP_WAIT_MS)) {
2936
+ return { ok: false, code: "running", error: "The agent did not stop; try again after it finishes" };
2937
+ }
2938
+ }
2939
+ const current = deps.claudeSessionId();
2940
+ if (!current) return { ok: false, code: "no-conversation", error: "The agent has no conversation to change yet" };
2941
+ const uuids = sourceId ? [sourceId, ...deps.aliases(sourceId)] : [];
2942
+ const next = await rewrite(deps.projectDir(), current, action, { uuids, text });
2943
+ await deps.switchConversation(next);
2944
+ return { ok: true, action, freshConversation: next === null };
2945
+ } catch (error) {
2946
+ if (error instanceof ConversationRewindError) return { ok: false, code: error.code, error: error.message };
2947
+ if (error instanceof claudeSessionFork.ForkSourceMissingError) return { ok: false, code: "no-conversation", error: "The agent conversation file is missing on this machine" };
2948
+ throw error;
2949
+ } finally {
2950
+ inFlight = false;
2951
+ }
2952
+ };
2953
+ }
2954
+
2358
2955
  const ABORT_INTERRUPT_GRACE_MS = 4e3;
2359
2956
  async function claudeRemoteLauncher(session, onPermissionModeChange, onEffectivePermissionMode, onPromptFinalized) {
2360
2957
  logger.logger.debug("[claudeRemoteLauncher] Starting remote launcher");
@@ -2449,6 +3046,31 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
2449
3046
  await turnSteering.steer();
2450
3047
  });
2451
3048
  session.client.rpcHandlerManager.registerHandler("switch", doSwitch);
3049
+ const promptAliases = /* @__PURE__ */ new Map();
3050
+ const promptUuidFor = (sourceIds) => {
3051
+ const [first, ...rest] = sourceIds ?? [];
3052
+ if (first) for (const id of rest) promptAliases.set(id, first);
3053
+ if (promptAliases.size > 2e3) promptAliases.delete(promptAliases.keys().next().value);
3054
+ return first;
3055
+ };
3056
+ let silentRelaunch = false;
3057
+ session.client.rpcHandlerManager.registerHandler("conversation-rewind", createConversationRewind({
3058
+ claudeSessionId: () => session.sessionId,
3059
+ projectDir: () => path.getProjectPath(session.path),
3060
+ isThinking: () => session.thinking,
3061
+ stopTurn: doAbort,
3062
+ waitIdle: waitForThinkingToStop,
3063
+ aliases: (sourceId) => {
3064
+ const alias = promptAliases.get(sourceId);
3065
+ return alias ? [alias] : [];
3066
+ },
3067
+ switchConversation: async (claudeSessionId) => {
3068
+ if (claudeSessionId) session.onSessionFound(claudeSessionId);
3069
+ else session.clearSessionId();
3070
+ silentRelaunch = true;
3071
+ await abort();
3072
+ }
3073
+ }));
2452
3074
  let livePermissionModeHandler = null;
2453
3075
  let idlePermissionModeHandler = null;
2454
3076
  session.client.rpcHandlerManager.registerHandler(
@@ -2634,10 +3256,13 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
2634
3256
  permissionHandler.setOnModeChanged((nextMode) => {
2635
3257
  commitPermissionMode(nextMode);
2636
3258
  });
3259
+ let launchPrewarm = null;
2637
3260
  try {
2638
3261
  const attachmentDirectory = attachmentContent.chatAttachmentDirectory(configuration.configuration.happyHomeDir, session.client.sessionId);
2639
3262
  await configuration.ensurePrivateDirectory(attachmentDirectory);
3263
+ launchPrewarm = session.takeClaudePrewarm();
2640
3264
  const remoteResult = await claudeRemote({
3265
+ prewarm: launchPrewarm ?? void 0,
2641
3266
  sessionId: session.sessionId,
2642
3267
  path: session.path,
2643
3268
  additionalDirectories: [attachmentDirectory],
@@ -2669,7 +3294,8 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
2669
3294
  }) : [];
2670
3295
  modeGate.park({
2671
3296
  message: parkedStaged.length > 0 ? attachmentContent.appendStagedAttachmentsToPrompt(msg.message, parkedStaged) : msg.message,
2672
- mode: msg.mode
3297
+ mode: msg.mode,
3298
+ uuid: promptUuidFor(msg.sourceIds)
2673
3299
  });
2674
3300
  return null;
2675
3301
  }
@@ -2686,13 +3312,17 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
2686
3312
  onPromptFinalized?.(withAttachments);
2687
3313
  return {
2688
3314
  message: withAttachments,
2689
- mode: msg.mode
3315
+ mode: msg.mode,
3316
+ enqueuedAt: msg.enqueuedAt,
3317
+ uuid: promptUuidFor(msg.sourceIds)
2690
3318
  };
2691
3319
  }
2692
3320
  onPromptFinalized?.(msg.message);
2693
3321
  return {
2694
3322
  message: msg.message,
2695
- mode: msg.mode
3323
+ mode: msg.mode,
3324
+ enqueuedAt: msg.enqueuedAt,
3325
+ uuid: promptUuidFor(msg.sourceIds)
2696
3326
  };
2697
3327
  }
2698
3328
  return null;
@@ -2793,7 +3423,7 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
2793
3423
  signal: abortController.signal
2794
3424
  });
2795
3425
  session.consumeOneTimeFlags();
2796
- if (!exitReason && abortController.signal.aborted) {
3426
+ if (!exitReason && abortController.signal.aborted && !silentRelaunch) {
2797
3427
  session.client.closeClaudeSessionTurn("cancelled");
2798
3428
  session.client.sendSessionEvent({ type: "message", message: "Aborted by user" });
2799
3429
  }
@@ -2810,6 +3440,7 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
2810
3440
  continue;
2811
3441
  }
2812
3442
  } finally {
3443
+ launchPrewarm?.discard("launch-ended");
2813
3444
  runtimeControls.setQuery(null);
2814
3445
  backgroundTasks.reset();
2815
3446
  session.setBackgroundTasks([]);
@@ -2835,6 +3466,7 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
2835
3466
  streamRelay$1.endTurn();
2836
3467
  streamRelay$1.dispose();
2837
3468
  abortController = null;
3469
+ silentRelaunch = false;
2838
3470
  abortFuture?.resolve(void 0);
2839
3471
  abortFuture = null;
2840
3472
  logger.logger.debug("[remote]: launch done");
@@ -2883,7 +3515,8 @@ async function loop(opts) {
2883
3515
  onModeChange: opts.onModeChange,
2884
3516
  onAbort: opts.onAbort,
2885
3517
  hookSettingsPath: opts.hookSettingsPath,
2886
- jsRuntime: opts.jsRuntime
3518
+ jsRuntime: opts.jsRuntime,
3519
+ claudePrewarm: opts.claudePrewarm
2887
3520
  });
2888
3521
  opts.onSessionReady?.(session);
2889
3522
  let mode = opts.startingMode ?? "local";
@@ -2891,7 +3524,7 @@ async function loop(opts) {
2891
3524
  logger.logger.debug(`[loop] Iteration with mode: ${mode}`);
2892
3525
  switch (mode) {
2893
3526
  case "local": {
2894
- const { claudeLocalLauncher } = await Promise.resolve().then(function () { return require('./claudeLocalLauncher-DyEbVzUN.cjs'); });
3527
+ const { claudeLocalLauncher } = await Promise.resolve().then(function () { return require('./claudeLocalLauncher-DWFWuLhY.cjs'); });
2895
3528
  const result = await claudeLocalLauncher(session);
2896
3529
  switch (result.type) {
2897
3530
  case "switch":
@@ -2919,18 +3552,18 @@ async function loop(opts) {
2919
3552
  }
2920
3553
  }
2921
3554
 
2922
- function claudeModeHash(mode) {
2923
- return deterministicJson.hashObject({
2924
- isPlan: mode.permissionMode === "plan",
2925
- fallbackModel: mode.fallbackModel,
2926
- customSystemPrompt: mode.customSystemPrompt,
2927
- appendSystemPrompt: mode.appendSystemPrompt,
2928
- allowedTools: mode.allowedTools,
2929
- disallowedTools: mode.disallowedTools,
2930
- effort: mode.effort
2931
- });
3555
+ function parseSessionHookTarget(url) {
3556
+ if (!url) return null;
3557
+ let parsed;
3558
+ try {
3559
+ parsed = new URL(url, "http://127.0.0.1");
3560
+ } catch {
3561
+ return null;
3562
+ }
3563
+ if (parsed.pathname !== "/hook/session-start") return null;
3564
+ const source = parsed.searchParams.get("source");
3565
+ return source && /^[A-Za-z0-9_.-]{1,64}$/.test(source) ? { source } : {};
2932
3566
  }
2933
-
2934
3567
  function hookRequestLogMetadata(body, data) {
2935
3568
  return {
2936
3569
  bodyBytes: Buffer.byteLength(body, "utf8"),
@@ -2952,7 +3585,8 @@ async function startHookServer(options) {
2952
3585
  const { onSessionHook } = options;
2953
3586
  return new Promise((resolve, reject) => {
2954
3587
  const server = node_http.createServer(async (req, res) => {
2955
- if (req.method === "POST" && req.url === "/hook/session-start") {
3588
+ const hookMeta = req.method === "POST" ? parseSessionHookTarget(req.url) : null;
3589
+ if (hookMeta) {
2956
3590
  const timeout = setTimeout(() => {
2957
3591
  if (!res.headersSent) {
2958
3592
  logger.logger.debug("[hookServer] Request timeout");
@@ -2976,7 +3610,7 @@ async function startHookServer(options) {
2976
3610
  const sessionId = data?.session_id || data?.sessionId;
2977
3611
  if (sessionId && data) {
2978
3612
  logger.logger.debug(`[hookServer] Session hook received session ID: ${sessionId}`);
2979
- onSessionHook(sessionId, data);
3613
+ onSessionHook(sessionId, data, hookMeta);
2980
3614
  } else {
2981
3615
  logger.logger.debug("[hookServer] Session hook received but no session_id found in data");
2982
3616
  }
@@ -3015,13 +3649,16 @@ async function startHookServer(options) {
3015
3649
  });
3016
3650
  }
3017
3651
 
3018
- function generateHookSettingsFile(port) {
3652
+ function generateHookSettingsFile(port, source) {
3019
3653
  const hooksDir = path$1.join(configuration.configuration.happyHomeDir, "tmp", "hooks");
3020
3654
  node_fs.mkdirSync(hooksDir, { recursive: true });
3021
- const filename = `session-hook-${process.pid}.json`;
3655
+ const filename = source ? `session-hook-${process.pid}-${source}.json` : `session-hook-${process.pid}.json`;
3022
3656
  const filepath = path$1.join(hooksDir, filename);
3023
3657
  const forwarderScript = path$1.resolve(projectPath.projectPath(), "scripts", "session_hook_forwarder.cjs");
3024
- const hookCommand = `node "${forwarderScript}" ${port}`;
3658
+ if (source !== void 0 && !/^[A-Za-z0-9_.-]{1,64}$/.test(source)) {
3659
+ throw new Error("invalid hook source tag");
3660
+ }
3661
+ const hookCommand = source ? `node "${forwarderScript}" ${port} ${source}` : `node "${forwarderScript}" ${port}`;
3025
3662
  const settings = {
3026
3663
  hooks: {
3027
3664
  SessionStart: [
@@ -3619,31 +4256,90 @@ function withAssistantDenylist(current, isAssistant) {
3619
4256
  return [...merged];
3620
4257
  }
3621
4258
 
4259
+ const VALID_EFFORTS = /* @__PURE__ */ new Set(["low", "medium", "high", "xhigh", "max"]);
4260
+ const has = (meta, key) => !!meta && Object.prototype.hasOwnProperty.call(meta, key);
4261
+ function resolveMessageMode(current, meta, ctx) {
4262
+ const next = { ...current };
4263
+ const result = {};
4264
+ let permissionMode$1 = current.permissionMode;
4265
+ if (!ctx.staleModeSnapshot && meta?.permissionMode) {
4266
+ permissionMode$1 = permissionMode.resolveRemoteClaudePermissionMode(current.permissionMode, meta.permissionMode, ctx.sandboxEnabled);
4267
+ next.permissionMode = permissionMode$1;
4268
+ result.publishPermissionMode = permissionMode$1;
4269
+ }
4270
+ if (has(meta, "model")) next.model = meta.model || void 0;
4271
+ if (has(meta, "customSystemPrompt")) next.customSystemPrompt = meta.customSystemPrompt || void 0;
4272
+ if (has(meta, "fallbackModel")) next.fallbackModel = meta.fallbackModel || void 0;
4273
+ if (has(meta, "appendSystemPrompt")) next.appendSystemPrompt = meta.appendSystemPrompt || void 0;
4274
+ if (has(meta, "allowedTools")) next.allowedTools = meta.allowedTools || void 0;
4275
+ if (has(meta, "disallowedTools")) {
4276
+ next.disallowedTools = withAssistantDenylist(meta.disallowedTools || void 0, ctx.isAssistantVariant);
4277
+ }
4278
+ if (has(meta, "effort")) {
4279
+ const incoming = meta.effort;
4280
+ if (incoming === null || incoming === void 0) {
4281
+ next.effort = void 0;
4282
+ } else if (typeof incoming === "string" && VALID_EFFORTS.has(incoming)) {
4283
+ next.effort = incoming;
4284
+ } else {
4285
+ result.ignoredEffort = String(incoming);
4286
+ }
4287
+ }
4288
+ return {
4289
+ ...result,
4290
+ next,
4291
+ mode: {
4292
+ permissionMode: permissionMode$1 || "default",
4293
+ model: next.model,
4294
+ fallbackModel: next.fallbackModel,
4295
+ customSystemPrompt: next.customSystemPrompt,
4296
+ appendSystemPrompt: next.appendSystemPrompt,
4297
+ allowedTools: next.allowedTools,
4298
+ disallowedTools: next.disallowedTools,
4299
+ effort: next.effort
4300
+ }
4301
+ };
4302
+ }
4303
+
3622
4304
  exports.reportSessionEditToDaemon = controlClient.reportSessionEditToDaemon;
3623
4305
  exports.claudeCheckSession = systemPrompt.claudeCheckSession;
3624
4306
  exports.parseSpecialCommand = specialCommands.parseSpecialCommand;
3625
4307
  exports.contentLogMetadata = contentLogMetadata.contentLogMetadata;
3626
4308
  exports.RawJSONLinesSchema = types.RawJSONLinesSchema;
3627
4309
  exports.getProjectPath = path.getProjectPath;
4310
+ exports.createSelfReportState = deterministicJson.createSelfReportState;
4311
+ exports.startHappyServer = deterministicJson.startHappyServer;
3628
4312
  exports.createSessionScanner = sessionScanner.createSessionScanner;
3629
4313
  exports.MessageQueue2 = registerKillSessionHandler.MessageQueue2;
3630
4314
  exports.registerKillSessionHandler = registerKillSessionHandler.registerKillSessionHandler;
3631
- exports.createSelfReportState = deterministicJson.createSelfReportState;
3632
- exports.startHappyServer = deterministicJson.startHappyServer;
3633
4315
  exports.getEnvironmentInfo = doctor.getEnvironmentInfo;
3634
4316
  exports.EditReportThrottle = editPaths.EditReportThrottle;
3635
4317
  exports.extractClaudeEditPaths = editPaths.extractClaudeEditPaths;
3636
4318
  exports.TitleGenerator = titleGenerator.TitleGenerator;
3637
4319
  exports.BoardAnalyzer = BoardAnalyzer;
3638
4320
  exports.FileRateLimiter = FileRateLimiter;
4321
+ exports.PrewarmHookGate = PrewarmHookGate;
3639
4322
  exports.SessionExitGate = SessionExitGate;
4323
+ exports.acquirePrewarmSlot = acquirePrewarmSlot;
3640
4324
  exports.claudeModeHash = claudeModeHash;
4325
+ exports.claudePrewarmEligibility = claudePrewarmEligibility;
4326
+ exports.claudePrewarmSessionEligibility = claudePrewarmSessionEligibility;
3641
4327
  exports.cleanupHookSettingsFile = cleanupHookSettingsFile;
4328
+ exports.createClaudePrewarmLease = createClaudePrewarmLease;
4329
+ exports.disposeAllClaudePrewarms = disposeAllClaudePrewarms;
4330
+ exports.evaluatePrewarmPrediction = evaluatePrewarmPrediction;
3642
4331
  exports.exitIntentFromArchiveFlag = exitIntentFromArchiveFlag;
4332
+ exports.formatPrewarmLine = formatPrewarmLine;
3643
4333
  exports.generateHookSettingsFile = generateHookSettingsFile;
3644
4334
  exports.loop = loop;
4335
+ exports.prewarmCacheFile = prewarmCacheFile;
4336
+ exports.prewarmPredictionMeta = prewarmPredictionMeta;
4337
+ exports.prewarmSlotDir = prewarmSlotDir;
4338
+ exports.readPrewarmCache = readPrewarmCache;
3645
4339
  exports.registerSideQuestionHandler = registerSideQuestionHandler;
4340
+ exports.resolveMessageMode = resolveMessageMode;
3646
4341
  exports.settleSessionOnExit = settleSessionOnExit;
3647
4342
  exports.startHookServer = startHookServer;
3648
4343
  exports.withAssistantDenylist = withAssistantDenylist;
4344
+ exports.writePrewarmCache = writePrewarmCache;
3649
4345
  exports.writeSideQuestionSettingsFile = writeSideQuestionSettingsFile;