very-happy-cli 0.2.165 → 0.2.167

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 (198) hide show
  1. package/README.md +1 -1
  2. package/dist/{AcpBackend-DCfNt9bD.cjs → AcpBackend-D1IKJGz_.cjs} +3 -3
  3. package/dist/{AcpBackend-C11FnVw5.mjs → AcpBackend-kFZlee5E.mjs} +3 -3
  4. package/dist/{AcpSessionManager-BQnDJvct.mjs → AcpSessionManager-B7FIrsys.mjs} +1 -1
  5. package/dist/{AcpSessionManager-9yN2iH4b.cjs → AcpSessionManager-Zf00QnlL.cjs} +1 -1
  6. package/dist/{BasePermissionHandler-BwQHxl6M.cjs → BasePermissionHandler-DHxYAK5L.cjs} +1 -1
  7. package/dist/{BasePermissionHandler-CwJ48yiB.mjs → BasePermissionHandler-DS0kRTNI.mjs} +1 -1
  8. package/dist/{BaseReasoningProcessor-ClF2g1qz.mjs → BaseReasoningProcessor-BRtCCt7q.mjs} +1 -1
  9. package/dist/{BaseReasoningProcessor-81lf_M8G.cjs → BaseReasoningProcessor-CsjVdt_H.cjs} +1 -1
  10. package/dist/{agentGuidance-CQuNlNx8.mjs → agentGuidance-BDYt2Qy2.mjs} +4 -2
  11. package/dist/{agentGuidance-B5NATuFa.cjs → agentGuidance-BtBx2xxE.cjs} +4 -1
  12. package/dist/{agentHome-DvR176E5.mjs → agentHome-Ct-VXFeG.mjs} +4 -4
  13. package/dist/{agentHome-D3Nn82kI.cjs → agentHome-DeAWzhSe.cjs} +4 -4
  14. package/dist/{api-AzdzTKFs.cjs → api-BZYLRDM9.cjs} +93 -13
  15. package/dist/{api-DTVPUE7g.mjs → api-CReZazeT.mjs} +93 -13
  16. package/dist/{apiMachine-B_cJldfa.cjs → apiMachine-BgMxGPsR.cjs} +2173 -66
  17. package/dist/{apiMachine-BQ-b4Lu3.mjs → apiMachine-CWndf1Vn.mjs} +2176 -69
  18. package/dist/{attachmentContent-muDCe4Gy.cjs → attachmentContent-HcJqFQW8.cjs} +2 -2
  19. package/dist/{attachmentContent-dzIs-wis.mjs → attachmentContent-j875mwU7.mjs} +2 -2
  20. package/dist/{attachmentLimits-eJZ4ZBjF.cjs → attachmentLimits-BEYEEBm8.cjs} +40 -2
  21. package/dist/{attachmentLimits-B8nzhw-i.mjs → attachmentLimits-CxG3T18E.mjs} +40 -2
  22. package/dist/{auth-Jtmvh1w4.mjs → auth-BIHuc7vY.mjs} +10 -10
  23. package/dist/{auth-BY5ujhGn.mjs → auth-CFS9Lfgv.mjs} +5 -5
  24. package/dist/{auth-DtP-B4gf.cjs → auth-Myr2Q42x.cjs} +10 -10
  25. package/dist/{auth-CfLd3phE.cjs → auth-VzWpbo5P.cjs} +5 -5
  26. package/dist/{auto-ClNnbSoF.cjs → auto-Bf6Dr7_o.cjs} +85 -21
  27. package/dist/{auto-DjWfR1UB.mjs → auto-Df9-zmuN.mjs} +84 -22
  28. package/dist/{bootstrap-D_ExGrY2.mjs → bootstrap-BSOxYpaP.mjs} +2 -2
  29. package/dist/{bootstrap-B1dMZA-u.cjs → bootstrap-Dj8WBiR2.cjs} +2 -2
  30. package/dist/{browser-mwzpOmcw.mjs → browser-BCFIHOvo.mjs} +1 -1
  31. package/dist/{browser-_gV7tcPs.cjs → browser-BoCV40yC.cjs} +1 -1
  32. package/dist/{claudeLocal-G5UmJ81F.cjs → claudeLocal-CGsq7Kul.cjs} +7 -7
  33. package/dist/{claudeLocal-BeHToEK5.mjs → claudeLocal-D5-eA9SC.mjs} +7 -7
  34. package/dist/{claudeLocalLauncher-Cq6bqAT4.mjs → claudeLocalLauncher-C9Cc438l.mjs} +15 -12
  35. package/dist/{claudeLocalLauncher-B4y2BsmO.cjs → claudeLocalLauncher-Cf9QeYDT.cjs} +15 -12
  36. package/dist/{claudeSessionFork-CDJq_b9r.cjs → claudeSessionFork-Byd8zD1U.cjs} +1 -1
  37. package/dist/{claudeSessionFork-CokUhS4r.mjs → claudeSessionFork-CMzAva8G.mjs} +1 -1
  38. package/dist/{client-Do7cGPEq.cjs → client-BKnKRLSt.cjs} +3 -3
  39. package/dist/{client-CJZKBZCE.mjs → client-C7FYMer0.mjs} +2 -2
  40. package/dist/{client-uN9d6Git.cjs → client-D0T5-6Ds.cjs} +2 -2
  41. package/dist/{client-BwaWdlCm.mjs → client-Dsfy_SAb.mjs} +3 -3
  42. package/dist/codex/happyMcpStdioBridge.cjs +23 -18
  43. package/dist/codex/happyMcpStdioBridge.mjs +22 -17
  44. package/dist/{codexAppServerClient-B0QaMQsC.mjs → codexAppServerClient-Dd_4TxHv.mjs} +48 -4
  45. package/dist/{codexAppServerClient-BuSdeUxT.cjs → codexAppServerClient-TiW9OBk4.cjs} +47 -3
  46. package/dist/{codexCommand-C3gdjMAw.mjs → codexCommand-BZSr4MKI.mjs} +170 -69
  47. package/dist/{codexCommand-YdYmykAR.cjs → codexCommand-Bxryqh90.cjs} +170 -69
  48. package/dist/{config-CGCIFRCN.mjs → config-C_Pj7yxV.mjs} +3 -3
  49. package/dist/{config-ChoHFnfO.cjs → config-DXPash-r.cjs} +3 -3
  50. package/dist/{configuration-BE61XNsg.cjs → configuration-C3piBtxY.cjs} +1 -1
  51. package/dist/{configuration-L1qcGTFM.mjs → configuration-WspKd2C2.mjs} +2 -2
  52. package/dist/{connect-D5IKfcfd.cjs → connect-BN-IBElA.cjs} +14 -14
  53. package/dist/{connect-CFD0Em6a.mjs → connect-DGPZs5px.mjs} +14 -14
  54. package/dist/{context-DaCCB4cm.mjs → context-Cr6a3NTg.mjs} +1 -1
  55. package/dist/{context-3WVw8qPz.cjs → context-Jrq4-eCZ.cjs} +1 -1
  56. package/dist/{controlClient-RWTlQA4_.cjs → controlClient-BI6Fw3fQ.cjs} +28 -5
  57. package/dist/{controlClient-Ci7HTMII.mjs → controlClient-DTheOlvC.mjs} +27 -6
  58. package/dist/{createSessionMetadata-CWR-AB2A.mjs → createSessionMetadata-BEZ4DIDA.mjs} +57 -5
  59. package/dist/{createSessionMetadata-CPGTztXP.cjs → createSessionMetadata-zQSz3hgk.cjs} +56 -3
  60. package/dist/defaultPermissionMode-Cif_RHGb.mjs +191 -0
  61. package/dist/defaultPermissionMode-DNKNzk7l.cjs +197 -0
  62. package/dist/{deterministicJson-BBwG-Ase.mjs → deterministicJson-BMMifViN.mjs} +36 -52
  63. package/dist/{deterministicJson-C4Jo2RWy.cjs → deterministicJson-C7O2ulKY.cjs} +41 -59
  64. package/dist/{doctor-ZOQLE5AH.cjs → doctor-BykBaMTr.cjs} +6 -6
  65. package/dist/{doctor-CAC6qY9Z.mjs → doctor-D1KKyPzB.mjs} +6 -6
  66. package/dist/{assistantTools-BsrG3PD-.cjs → downloadTarget-CWTb2-EM.cjs} +44 -6
  67. package/dist/{assistantTools-DPGga5lM.mjs → downloadTarget-Cp48jrIP.mjs} +45 -8
  68. package/dist/{ensureDaemonRunning-b1pvEFcS.mjs → ensureDaemonRunning-Ba5fYoxb.mjs} +5 -5
  69. package/dist/{ensureDaemonRunning-mIgX2vnc.cjs → ensureDaemonRunning-CCxX7MoP.cjs} +5 -5
  70. package/dist/{handleResumeCommand-CTGbZkCL.mjs → handleResumeCommand-BTUGlNjB.mjs} +5 -5
  71. package/dist/{handleResumeCommand-DGNhbv-3.cjs → handleResumeCommand-yPdDQHqz.cjs} +5 -5
  72. package/dist/{index-vVWpCoTr.mjs → index-B0HEEYGh.mjs} +22 -5
  73. package/dist/{index-BzIxE0Eu.cjs → index-BjhKqDa0.cjs} +3 -3
  74. package/dist/{index-BgzjPv07.mjs → index-C3_83bqS.mjs} +3 -3
  75. package/dist/{index-DqlyNgt4.cjs → index-C9hI8a10.cjs} +26 -4
  76. package/dist/{index-DjtBengz.mjs → index-CE2GgPbr.mjs} +40 -39
  77. package/dist/{index-Diu6HdWH.mjs → index-D8m8Ripb.mjs} +4 -4
  78. package/dist/{index-DrSPR59N.cjs → index-DifM62wX.cjs} +39 -38
  79. package/dist/{index-DIodyAqF.cjs → index-PNMQPKhz.cjs} +4 -4
  80. package/dist/index.cjs +2 -2
  81. package/dist/index.mjs +2 -2
  82. package/dist/{install-BO_W7VhL.mjs → install-BdvKiOQw.mjs} +2 -0
  83. package/dist/{install-Cp_aB-NQ.mjs → install-C0-QFn9s.mjs} +3 -3
  84. package/dist/{install-Cs5qAPrB.cjs → install-Cf6AFSWC.cjs} +2 -0
  85. package/dist/{install-DrUQk2DJ.cjs → install-CqZVeze8.cjs} +3 -3
  86. package/dist/lib.cjs +12 -12
  87. package/dist/lib.d.cts +116 -2
  88. package/dist/lib.d.mts +116 -2
  89. package/dist/lib.mjs +12 -12
  90. package/dist/{lidState-BLHLmhwd.mjs → lidState-B2ZxdREe.mjs} +1 -1
  91. package/dist/{lidState-z9ekRpZu.cjs → lidState-Bc2K9H9l.cjs} +1 -1
  92. package/dist/{localHappyAgentAuth-BWvmc_Hg.mjs → localHappyAgentAuth-B5XPEMwk.mjs} +1 -1
  93. package/dist/{localHappyAgentAuth-BCx0y1qW.cjs → localHappyAgentAuth-T5GOvRha.cjs} +1 -1
  94. package/dist/{logger-D0hkk7Vo.cjs → logger-B_MWPbZz.cjs} +2 -2
  95. package/dist/{logger-CknSVkIe.mjs → logger-CbBv3q_b.mjs} +2 -2
  96. package/dist/{machineMetadata-BDCYOXQg.cjs → machineMetadata-BafS4JY8.cjs} +4 -3
  97. package/dist/{machineMetadata-Cj1DoFot.mjs → machineMetadata-DHg238U4.mjs} +4 -3
  98. package/dist/{main-COAPGIso.cjs → main-DNrA0qBy.cjs} +45 -45
  99. package/dist/{main-CKUfkVG_.mjs → main-DXAK0n7x.mjs} +45 -45
  100. package/dist/{manager-BQ4flvQZ.mjs → manager-BEsI4qt3.mjs} +9 -3
  101. package/dist/{manager-Cly8xVIR.cjs → manager-HrEj442o.cjs} +8 -2
  102. package/dist/{mcp-BILnw4si.cjs → mcp-AvPOhDXy.cjs} +24 -19
  103. package/dist/{mcp-DeYUfpo8.mjs → mcp-BotAjCdD.mjs} +23 -18
  104. package/dist/mirrorProtocol-BdcN6QlN.cjs +1270 -0
  105. package/dist/mirrorProtocol-BwHm8odn.mjs +1247 -0
  106. package/dist/{package-UkmvSFsg.cjs → package-C9ZP9bpX.cjs} +7 -7
  107. package/dist/{package-VIUXrYZ1.mjs → package-DU1DxhH9.mjs} +7 -7
  108. package/dist/{peerTools-CttfOxti.cjs → peerTools-Dkbu7gag.cjs} +4 -4
  109. package/dist/{peerTools-SWITnkqz.mjs → peerTools-os2DVjA0.mjs} +4 -4
  110. package/dist/{persistence-C6ztVW1W.cjs → persistence-BYGl0QYw.cjs} +147 -25
  111. package/dist/{persistence-DujtUH94.mjs → persistence-ON0zpHfb.mjs} +123 -12
  112. package/dist/{piRunnerArgs-BVJHIjlk.mjs → piRunnerArgs-CYsnT9sV.mjs} +1 -1
  113. package/dist/{piRunnerArgs-tBQg6xDw.cjs → piRunnerArgs-DpbvstUX.cjs} +1 -1
  114. package/dist/{piRuntime-DZzjF9It.cjs → piRuntime-CDnILlCd.cjs} +1 -1
  115. package/dist/{piRuntime-DKFA8u8t.mjs → piRuntime-CmEid-wu.mjs} +1 -1
  116. package/dist/{piTerminal-BTSaFlpV.mjs → piTerminal-0eNlXSlL.mjs} +17 -17
  117. package/dist/{piTerminal-t5pQHCPT.cjs → piTerminal-B57TgMON.cjs} +17 -17
  118. package/dist/precheckCompat-CWOi5c9L.cjs +29 -0
  119. package/dist/precheckCompat-DeEbilbr.mjs +26 -0
  120. package/dist/rateLimitWindows-CusGIqlq.cjs +258 -0
  121. package/dist/rateLimitWindows-vZ9Bo7aT.mjs +248 -0
  122. package/dist/{registerCommonHandlers-BR0J4g64.mjs → registerCommonHandlers-B0PVff2U.mjs} +2 -2
  123. package/dist/{registerCommonHandlers--8ds2auE.cjs → registerCommonHandlers-DVYB3iVn.cjs} +2 -2
  124. package/dist/{registerKillSessionHandler-Czz0tdki.mjs → registerKillSessionHandler-BJMHJHXe.mjs} +15 -10
  125. package/dist/{registerKillSessionHandler-CI23l8aJ.cjs → registerKillSessionHandler-BwXGKtg_.cjs} +15 -10
  126. package/dist/{remoteSessionClient-DCAUHgPz.mjs → remoteSessionClient-BzPXSC21.mjs} +5 -5
  127. package/dist/{remoteSessionClient-BAkIwM2S.cjs → remoteSessionClient-PyUAIhwK.cjs} +5 -5
  128. package/dist/{tools-BVRoGcQH.mjs → reportProgressTool-BvB13EwC.mjs} +67 -10
  129. package/dist/{tools-mWqsE6ji.cjs → reportProgressTool-D4KB_4cP.cjs} +73 -9
  130. package/dist/{run-CkKujjn8.cjs → run-BC8jzq_h.cjs} +558 -122
  131. package/dist/{run-B75qm2I6.mjs → run-O2M8LsWf.mjs} +556 -120
  132. package/dist/{runClaude-B1T9DLLi.cjs → runClaude-C7jPa8VP.cjs} +93 -26
  133. package/dist/{runClaude-aBfBweec.mjs → runClaude-DGkr5E7s.mjs} +93 -26
  134. package/dist/{runClaudeDeps-BGjNGfuZ.cjs → runClaudeDeps-5kzncqME.cjs} +113 -35
  135. package/dist/{runClaudeDeps-BOrPP4J1.mjs → runClaudeDeps-CX_TxS78.mjs} +116 -37
  136. package/dist/{runGemini-BuAA_OQb.cjs → runGemini-BfYA4Uqc.cjs} +43 -36
  137. package/dist/{runGemini-a-V7JE-J.mjs → runGemini-CwmGBH3L.mjs} +43 -36
  138. package/dist/{runOpenClaw-DUSwXg1A.mjs → runOpenClaw-BYAPYFyL.mjs} +18 -18
  139. package/dist/{runOpenClaw-BBVffIh9.cjs → runOpenClaw-C72jut7v.cjs} +18 -18
  140. package/dist/{sandbox-Fd2G5yaq.cjs → sandbox-Bqkp8IT7.cjs} +4 -4
  141. package/dist/{sandbox-Brb_5wzc.mjs → sandbox-DlVnK1Vi.mjs} +4 -4
  142. package/dist/{selfCheck-NuJKMInJ.cjs → selfCheck-B4lLZplk.cjs} +34 -34
  143. package/dist/selfCheck-DYTGBdIO.mjs +84 -0
  144. package/dist/{send-DEQJiq_x.mjs → send-B5bWW9Tl.mjs} +8 -8
  145. package/dist/{send-4dgHKC3u.cjs → send-BCwS6n_s.cjs} +8 -8
  146. package/dist/{server-C6AlUFkw.mjs → server-CEJfRQfj.mjs} +4 -4
  147. package/dist/{server-DWGcDmHG.cjs → server-CFWZehnC.cjs} +6 -6
  148. package/dist/{sessionLock-Dm8QyGo4.mjs → sessionLock-AwOYsKT7.mjs} +12 -4
  149. package/dist/{sessionLock-B1GgaO1q.cjs → sessionLock-LBWNjpHf.cjs} +12 -3
  150. package/dist/{sessionModeFile-BvOEJ4Fl.cjs → sessionModeFile-CyPuZRIU.cjs} +1 -1
  151. package/dist/{sessionModeFile-CuNAWCKL.mjs → sessionModeFile-fvFn1JVG.mjs} +1 -1
  152. package/dist/{sessionOps-DG5MMEp_.mjs → sessionOps-DZRH4-hV.mjs} +4 -4
  153. package/dist/{sessionOps-JP64uJmc.cjs → sessionOps-DzbZI3Eq.cjs} +4 -4
  154. package/dist/{sessionScanner-DqSk5Ol_.mjs → sessionScanner-Q_Ei2flB.mjs} +75 -19
  155. package/dist/{sessionScanner-BBPEgJ5S.cjs → sessionScanner-i-cgwFVw.cjs} +75 -19
  156. package/dist/{sessions-4isbBAWi.mjs → sessions-DAmjMAZN.mjs} +9 -9
  157. package/dist/{sessions-DgJuw_i0.cjs → sessions-DYK5hD4T.cjs} +9 -9
  158. package/dist/{setupOfflineReconnection-_MoZtsro.mjs → setupOfflineReconnection-BfDBxNdo.mjs} +2 -2
  159. package/dist/{setupOfflineReconnection-CKJKVIUS.cjs → setupOfflineReconnection-C2LO3hSP.cjs} +2 -2
  160. package/dist/{spawn-BTOG4tTm.mjs → spawn-BmjG5j5Y.mjs} +15 -14
  161. package/dist/{spawn-CshERWbY.cjs → spawn-GK_sXE8h.cjs} +15 -14
  162. package/dist/{spawnAgents-Czi2VDzj.mjs → spawnAgents-HDaE3C0-.mjs} +1 -1
  163. package/dist/{spawnAgents-McixdtV1.cjs → spawnAgents-vglexX9N.cjs} +1 -1
  164. package/dist/{spawnHappyCLI-Dc4xYm8P.mjs → spawnHappyCLI-B2h0P4b5.mjs} +1 -1
  165. package/dist/{spawnHappyCLI-Dd5_8Vex.cjs → spawnHappyCLI-J4iEhfyZ.cjs} +1 -1
  166. package/dist/specialCommands-DisVxagO.mjs +93 -0
  167. package/dist/specialCommands-DmJMKspE.cjs +96 -0
  168. package/dist/{startFileWatcher-B0VlG-Fn.mjs → startFileWatcher-CeK1k5gt.mjs} +1 -1
  169. package/dist/{startFileWatcher-1LedLBY-.cjs → startFileWatcher-xKo8AoYl.cjs} +1 -1
  170. package/dist/{streamRelay-C0AffuX6.cjs → streamRelay-Ce9sgcOV.cjs} +1 -1
  171. package/dist/{streamRelay-BzMEEvJU.mjs → streamRelay-Iogsh51a.mjs} +1 -1
  172. package/dist/{sync-DwUUGGFz.cjs → sync-Bvc-vh6C.cjs} +1 -1
  173. package/dist/{sync-Dfm6K2te.mjs → sync-CCwYpJMS.mjs} +1 -1
  174. package/dist/{systemPrompt-D41Zw1a3.mjs → systemPrompt-BNIkP3tR.mjs} +3 -3
  175. package/dist/{systemPrompt-CB1Ls0AE.cjs → systemPrompt-DwOddbuG.cjs} +3 -3
  176. package/dist/{teams-D8Ly3i6u.mjs → teams-DRrLBcys.mjs} +7 -7
  177. package/dist/{teams-NWv2ji16.cjs → teams-GHMCRZOw.cjs} +7 -7
  178. package/dist/{time-BbzJ7PJQ.cjs → time-BXvtjhe9.cjs} +1 -1
  179. package/dist/{time-v1Y_qEJp.mjs → time-PG5Dfwdv.mjs} +1 -1
  180. package/dist/{titleGenerator-cH6IkPRi.cjs → titleGenerator-B07bZA0V.cjs} +2 -2
  181. package/dist/{titleGenerator-BhoblAQY.mjs → titleGenerator-CIzfpfZW.mjs} +1 -1
  182. package/dist/{todo-D1hgWV6d.cjs → todo-B0aeoNu3.cjs} +6 -6
  183. package/dist/{todo-CuNct-fw.mjs → todo-CfL7SBFc.mjs} +6 -6
  184. package/dist/{tools-jof0Bu54.mjs → tools-D91mq5Ib.mjs} +1 -1
  185. package/dist/{tools-c2fb0CF5.cjs → tools-DJIANHSh.cjs} +1 -1
  186. package/dist/transcriptCursor-B7T_gkQ0.mjs +102 -0
  187. package/dist/transcriptCursor-DcXGLeSc.cjs +106 -0
  188. package/dist/{uninstall-BB7WYYAk.mjs → uninstall-5xz3Xvhf.mjs} +3 -3
  189. package/dist/{uninstall-VPH5GfrA.cjs → uninstall-AtzOfdrj.cjs} +3 -3
  190. package/package.json +7 -7
  191. package/scripts/terminal_status_forwarder.cjs +89 -0
  192. package/dist/defaultPermissionMode-BnxJPVHT.mjs +0 -4
  193. package/dist/defaultPermissionMode-CxmTXUQR.cjs +0 -7
  194. package/dist/mirrorProtocol-BNLtoWjO.mjs +0 -170
  195. package/dist/mirrorProtocol-BUtmg1ws.cjs +0 -186
  196. package/dist/selfCheck-BgwJ3NGS.mjs +0 -84
  197. package/dist/specialCommands-BSqhYg5X.mjs +0 -52
  198. package/dist/specialCommands-DSsTeRej.cjs +0 -54
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var logger = require('./logger-D0hkk7Vo.cjs');
4
- var persistence = require('./persistence-C6ztVW1W.cjs');
5
- var configuration = require('./configuration-BE61XNsg.cjs');
3
+ var logger = require('./logger-B_MWPbZz.cjs');
4
+ var persistence = require('./persistence-BYGl0QYw.cjs');
5
+ var configuration = require('./configuration-C3piBtxY.cjs');
6
6
 
7
7
  function daemonControlHeaders(controlToken) {
8
8
  return {
@@ -125,6 +125,13 @@ async function notifyDaemonTurnEvent(sessionId, event) {
125
125
  async function notifyDaemonBackgroundTasks(sessionId, backgroundTasks) {
126
126
  return daemonPost("/session-event", { sessionId, event: "background_tasks", backgroundTasks });
127
127
  }
128
+ function reportRateLimitsToDaemon(report) {
129
+ void daemonPost("/rate-limits", report).then((result) => {
130
+ if (result?.error) logger.logger.debug(`[CONTROL CLIENT] rate-limits not recorded: ${result.error}`);
131
+ }).catch((error) => {
132
+ logger.logger.debug("[CONTROL CLIENT] rate-limits failed:", error);
133
+ });
134
+ }
128
135
  function reportSessionEditToDaemon(edit) {
129
136
  void daemonPost("/session-edit", edit).then((result) => {
130
137
  if (result?.error) logger.logger.debug(`[CONTROL CLIENT] session-edit not recorded: ${result.error}`);
@@ -153,8 +160,8 @@ async function pushClipboardViaDaemon(text, terminalId) {
153
160
  }
154
161
  return result;
155
162
  }
156
- async function pushFilePreviewViaDaemon(terminalId, path, mode = "file") {
157
- const result = await daemonPost("/file-preview", { terminalId, path, mode });
163
+ async function pushFilePreviewViaDaemon(terminalId, path, mode = "file", intent) {
164
+ const result = await daemonPost("/file-preview", { terminalId, path, mode, ...intent ? { intent } : {} });
158
165
  if (result?.error) return { delivered: false, error: result.error };
159
166
  return { delivered: result?.delivered === true, ...result?.delivered === true ? {} : { error: "preview was not delivered" } };
160
167
  }
@@ -258,7 +265,22 @@ async function waitForProcessDeath(pid, timeout) {
258
265
  }
259
266
  throw new Error("Process did not die within timeout");
260
267
  }
268
+ async function checkDaemonHibernation(body) {
269
+ const result = await daemonPost("/session-hibernate-check", body);
270
+ if (result && typeof result === "object" && typeof result.error === "string") {
271
+ return /404|Not Found|No daemon running|not running/.test(result.error) ? "unsupported" : "error";
272
+ }
273
+ if (!result || typeof result.hibernate !== "boolean") return "error";
274
+ return {
275
+ hibernate: result.hibernate,
276
+ ...typeof result.reason === "string" ? { reason: result.reason } : {},
277
+ ...typeof result.idleMs === "number" ? { idleMs: result.idleMs } : {},
278
+ ...typeof result.nextCheckMs === "number" ? { nextCheckMs: result.nextCheckMs } : {},
279
+ ...result.keepAwake === true ? { keepAwake: true } : {}
280
+ };
281
+ }
261
282
 
283
+ exports.checkDaemonHibernation = checkDaemonHibernation;
262
284
  exports.checkIfDaemonRunningAndCleanupStaleState = checkIfDaemonRunningAndCleanupStaleState;
263
285
  exports.cleanupDaemonState = cleanupDaemonState;
264
286
  exports.isDaemonRunningCurrentlyInstalledHappyVersion = isDaemonRunningCurrentlyInstalledHappyVersion;
@@ -271,6 +293,7 @@ exports.notifyDaemonSessionStarted = notifyDaemonSessionStarted;
271
293
  exports.notifyDaemonTurnEvent = notifyDaemonTurnEvent;
272
294
  exports.pushClipboardViaDaemon = pushClipboardViaDaemon;
273
295
  exports.pushFilePreviewViaDaemon = pushFilePreviewViaDaemon;
296
+ exports.reportRateLimitsToDaemon = reportRateLimitsToDaemon;
274
297
  exports.reportSessionEditToDaemon = reportSessionEditToDaemon;
275
298
  exports.resumeDaemonSession = resumeDaemonSession;
276
299
  exports.setTerminalTitleViaDaemon = setTerminalTitleViaDaemon;
@@ -1,6 +1,6 @@
1
- import { l as logger } from './logger-CknSVkIe.mjs';
2
- import { readDaemonState, clearDaemonState } from './persistence-DujtUH94.mjs';
3
- import { c as configuration } from './configuration-L1qcGTFM.mjs';
1
+ import { l as logger } from './logger-CbBv3q_b.mjs';
2
+ import { d as readDaemonState, f as clearDaemonState } from './persistence-ON0zpHfb.mjs';
3
+ import { c as configuration } from './configuration-WspKd2C2.mjs';
4
4
 
5
5
  function daemonControlHeaders(controlToken) {
6
6
  return {
@@ -123,6 +123,13 @@ async function notifyDaemonTurnEvent(sessionId, event) {
123
123
  async function notifyDaemonBackgroundTasks(sessionId, backgroundTasks) {
124
124
  return daemonPost("/session-event", { sessionId, event: "background_tasks", backgroundTasks });
125
125
  }
126
+ function reportRateLimitsToDaemon(report) {
127
+ void daemonPost("/rate-limits", report).then((result) => {
128
+ if (result?.error) logger.debug(`[CONTROL CLIENT] rate-limits not recorded: ${result.error}`);
129
+ }).catch((error) => {
130
+ logger.debug("[CONTROL CLIENT] rate-limits failed:", error);
131
+ });
132
+ }
126
133
  function reportSessionEditToDaemon(edit) {
127
134
  void daemonPost("/session-edit", edit).then((result) => {
128
135
  if (result?.error) logger.debug(`[CONTROL CLIENT] session-edit not recorded: ${result.error}`);
@@ -151,8 +158,8 @@ async function pushClipboardViaDaemon(text, terminalId) {
151
158
  }
152
159
  return result;
153
160
  }
154
- async function pushFilePreviewViaDaemon(terminalId, path, mode = "file") {
155
- const result = await daemonPost("/file-preview", { terminalId, path, mode });
161
+ async function pushFilePreviewViaDaemon(terminalId, path, mode = "file", intent) {
162
+ const result = await daemonPost("/file-preview", { terminalId, path, mode, ...intent ? { intent } : {} });
156
163
  if (result?.error) return { delivered: false, error: result.error };
157
164
  return { delivered: result?.delivered === true, ...result?.delivered === true ? {} : { error: "preview was not delivered" } };
158
165
  }
@@ -256,5 +263,19 @@ async function waitForProcessDeath(pid, timeout) {
256
263
  }
257
264
  throw new Error("Process did not die within timeout");
258
265
  }
266
+ async function checkDaemonHibernation(body) {
267
+ const result = await daemonPost("/session-hibernate-check", body);
268
+ if (result && typeof result === "object" && typeof result.error === "string") {
269
+ return /404|Not Found|No daemon running|not running/.test(result.error) ? "unsupported" : "error";
270
+ }
271
+ if (!result || typeof result.hibernate !== "boolean") return "error";
272
+ return {
273
+ hibernate: result.hibernate,
274
+ ...typeof result.reason === "string" ? { reason: result.reason } : {},
275
+ ...typeof result.idleMs === "number" ? { idleMs: result.idleMs } : {},
276
+ ...typeof result.nextCheckMs === "number" ? { nextCheckMs: result.nextCheckMs } : {},
277
+ ...result.keepAwake === true ? { keepAwake: true } : {}
278
+ };
279
+ }
259
280
 
260
- export { stopDaemon as a, pushFilePreviewViaDaemon as b, checkIfDaemonRunningAndCleanupStaleState as c, setTerminalTitleViaDaemon as d, spawnDaemonSession as e, listDaemonPeers as f, reportSessionEditToDaemon as g, notifyDaemonTurnEvent as h, isDaemonRunningCurrentlyInstalledHappyVersion as i, notifyDaemonBackgroundTasks as j, notifyDaemonSessionEvent as k, listDaemonSessions as l, notifyDaemonClaudeAuthFailed as m, notifyDaemonSessionStarted as n, cleanupDaemonState as o, pushClipboardViaDaemon as p, resumeDaemonSession as r, stopDaemonSession as s };
281
+ export { checkIfDaemonRunningAndCleanupStaleState as a, stopDaemon as b, checkDaemonHibernation as c, pushFilePreviewViaDaemon as d, setTerminalTitleViaDaemon as e, spawnDaemonSession as f, listDaemonPeers as g, resumeDaemonSession as h, isDaemonRunningCurrentlyInstalledHappyVersion as i, reportSessionEditToDaemon as j, notifyDaemonTurnEvent as k, listDaemonSessions as l, notifyDaemonBackgroundTasks as m, notifyDaemonSessionStarted as n, notifyDaemonSessionEvent as o, pushClipboardViaDaemon as p, notifyDaemonClaudeAuthFailed as q, reportRateLimitsToDaemon as r, stopDaemonSession as s, cleanupDaemonState as t };
@@ -1,8 +1,58 @@
1
1
  import os from 'node:os';
2
- import { resolve } from 'node:path';
3
- import { c as configuration } from './configuration-L1qcGTFM.mjs';
2
+ import { resolve, isAbsolute, dirname } from 'node:path';
3
+ import { c as configuration } from './configuration-WspKd2C2.mjs';
4
4
  import { p as projectPath } from './projectPath-BTBIMB57.mjs';
5
- import { p as packageJson } from './package-VIUXrYZ1.mjs';
5
+ import { p as packageJson } from './package-DU1DxhH9.mjs';
6
+ import { existsSync, readFileSync, statSync } from 'node:fs';
7
+
8
+ const realFs = {
9
+ existsSync,
10
+ isDirectory: (path) => {
11
+ try {
12
+ return statSync(path).isDirectory();
13
+ } catch {
14
+ return false;
15
+ }
16
+ },
17
+ readFileSync: (path) => readFileSync(path, "utf8")
18
+ };
19
+ function resolveSessionWorktree(cwd, fs = realFs) {
20
+ let dir = resolve(cwd);
21
+ for (let depth = 0; depth < 64; depth++) {
22
+ const dotGit = resolve(dir, ".git");
23
+ try {
24
+ if (fs.existsSync(dotGit)) {
25
+ if (fs.isDirectory(dotGit)) return null;
26
+ const gitdir = fs.readFileSync(dotGit).match(/^gitdir:\s*(.+?)\s*$/m)?.[1];
27
+ if (!gitdir) return null;
28
+ const absolute = isAbsolute(gitdir) ? gitdir : resolve(dir, gitdir);
29
+ if (!/[\\/]\.git[\\/]worktrees[\\/][^\\/]+[\\/]?$/.test(absolute)) return null;
30
+ let branch = null;
31
+ try {
32
+ const head = fs.readFileSync(resolve(absolute, "HEAD")).trim();
33
+ const ref = head.match(/^ref:\s*refs\/heads\/(.+)$/)?.[1];
34
+ branch = ref ?? null;
35
+ } catch {
36
+ }
37
+ return { branch, root: dir };
38
+ }
39
+ } catch {
40
+ return null;
41
+ }
42
+ const parent = dirname(dir);
43
+ if (parent === dir) break;
44
+ dir = parent;
45
+ }
46
+ return null;
47
+ }
48
+ function sessionWorktreeMetadata(cwd) {
49
+ try {
50
+ const worktree = resolveSessionWorktree(cwd);
51
+ return worktree ? { worktree } : {};
52
+ } catch {
53
+ return {};
54
+ }
55
+ }
6
56
 
7
57
  const SPAWN_ORIGIN_TAG_MAX = 24;
8
58
  function spawnOriginTags(env = process.env, flavor = void 0) {
@@ -46,9 +96,11 @@ function createSessionMetadata(opts) {
46
96
  // B-091/B-303: dispatched sessions carry their spawn origin as a tag
47
97
  // from birth (see spawnOriginTags) — applies to every flavor the daemon
48
98
  // can spawn, since HAPPY_SPAWNED_BY is exported flavor-independently.
49
- ...originTags ? { tags: originTags } : {}
99
+ ...originTags ? { tags: originTags } : {},
100
+ // B-586: linked git worktree → branch shown in the session list.
101
+ ...sessionWorktreeMetadata(process.cwd())
50
102
  };
51
103
  return { state, metadata };
52
104
  }
53
105
 
54
- export { createSessionMetadata as c, isValidSpawnOrigin as i, spawnOriginTags as s };
106
+ export { sessionWorktreeMetadata as a, createSessionMetadata as c, isValidSpawnOrigin as i, spawnOriginTags as s };
@@ -2,9 +2,59 @@
2
2
 
3
3
  var os = require('node:os');
4
4
  var path = require('node:path');
5
- var configuration = require('./configuration-BE61XNsg.cjs');
5
+ var configuration = require('./configuration-C3piBtxY.cjs');
6
6
  var projectPath = require('./projectPath-ChLhdOyt.cjs');
7
- var _package = require('./package-UkmvSFsg.cjs');
7
+ var _package = require('./package-C9ZP9bpX.cjs');
8
+ var node_fs = require('node:fs');
9
+
10
+ const realFs = {
11
+ existsSync: node_fs.existsSync,
12
+ isDirectory: (path) => {
13
+ try {
14
+ return node_fs.statSync(path).isDirectory();
15
+ } catch {
16
+ return false;
17
+ }
18
+ },
19
+ readFileSync: (path) => node_fs.readFileSync(path, "utf8")
20
+ };
21
+ function resolveSessionWorktree(cwd, fs = realFs) {
22
+ let dir = path.resolve(cwd);
23
+ for (let depth = 0; depth < 64; depth++) {
24
+ const dotGit = path.resolve(dir, ".git");
25
+ try {
26
+ if (fs.existsSync(dotGit)) {
27
+ if (fs.isDirectory(dotGit)) return null;
28
+ const gitdir = fs.readFileSync(dotGit).match(/^gitdir:\s*(.+?)\s*$/m)?.[1];
29
+ if (!gitdir) return null;
30
+ const absolute = path.isAbsolute(gitdir) ? gitdir : path.resolve(dir, gitdir);
31
+ if (!/[\\/]\.git[\\/]worktrees[\\/][^\\/]+[\\/]?$/.test(absolute)) return null;
32
+ let branch = null;
33
+ try {
34
+ const head = fs.readFileSync(path.resolve(absolute, "HEAD")).trim();
35
+ const ref = head.match(/^ref:\s*refs\/heads\/(.+)$/)?.[1];
36
+ branch = ref ?? null;
37
+ } catch {
38
+ }
39
+ return { branch, root: dir };
40
+ }
41
+ } catch {
42
+ return null;
43
+ }
44
+ const parent = path.dirname(dir);
45
+ if (parent === dir) break;
46
+ dir = parent;
47
+ }
48
+ return null;
49
+ }
50
+ function sessionWorktreeMetadata(cwd) {
51
+ try {
52
+ const worktree = resolveSessionWorktree(cwd);
53
+ return worktree ? { worktree } : {};
54
+ } catch {
55
+ return {};
56
+ }
57
+ }
8
58
 
9
59
  const SPAWN_ORIGIN_TAG_MAX = 24;
10
60
  function spawnOriginTags(env = process.env, flavor = void 0) {
@@ -48,11 +98,14 @@ function createSessionMetadata(opts) {
48
98
  // B-091/B-303: dispatched sessions carry their spawn origin as a tag
49
99
  // from birth (see spawnOriginTags) — applies to every flavor the daemon
50
100
  // can spawn, since HAPPY_SPAWNED_BY is exported flavor-independently.
51
- ...originTags ? { tags: originTags } : {}
101
+ ...originTags ? { tags: originTags } : {},
102
+ // B-586: linked git worktree → branch shown in the session list.
103
+ ...sessionWorktreeMetadata(process.cwd())
52
104
  };
53
105
  return { state, metadata };
54
106
  }
55
107
 
56
108
  exports.createSessionMetadata = createSessionMetadata;
57
109
  exports.isValidSpawnOrigin = isValidSpawnOrigin;
110
+ exports.sessionWorktreeMetadata = sessionWorktreeMetadata;
58
111
  exports.spawnOriginTags = spawnOriginTags;
@@ -0,0 +1,191 @@
1
+ import { l as logger } from './logger-CbBv3q_b.mjs';
2
+ import { e as evaluateWrapperIdle, j as HIBERNATION_UNSUPPORTED_BACKOFF_MS } from './persistence-ON0zpHfb.mjs';
3
+
4
+ const PRESENCE_SETTLE_MS = 6e3;
5
+ async function commitHibernation(deps) {
6
+ const log = deps.log ?? ((message) => logger.debug(message));
7
+ if (!deps.claimExit()) {
8
+ log("[hibernate] exit already claimed for another reason; not hibernating");
9
+ return false;
10
+ }
11
+ const { client } = deps;
12
+ const now = deps.now ?? Date.now;
13
+ const sleep = deps.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
14
+ let frozen = false;
15
+ let stamped = false;
16
+ const waitOrExit = async (work, fallback) => {
17
+ let settled = false;
18
+ const watched = work.finally(() => {
19
+ settled = true;
20
+ });
21
+ const exitWatch = (async () => {
22
+ while (!settled && !deps.exitRequested()) await sleep(EXIT_POLL_MS);
23
+ return settled ? watched : fallback;
24
+ })();
25
+ return Promise.race([watched, exitWatch]);
26
+ };
27
+ const abort = async (why2) => {
28
+ log(`[hibernate] aborted at commit: ${why2}`);
29
+ if (stamped) {
30
+ const clear = (metadata) => {
31
+ const next = { ...metadata };
32
+ delete next.hibernation;
33
+ return next;
34
+ };
35
+ const cleared = await client.updateMetadataAndWait(clear, deps.exitRequested() ? EXIT_CLEAR_TIMEOUT_MS : void 0).catch(() => false);
36
+ if (!cleared) log("[hibernate] stamp clear not confirmed (it keeps retrying in the background)");
37
+ }
38
+ if (frozen) {
39
+ client.unmuteHeartbeats();
40
+ client.unfreezeInbound();
41
+ }
42
+ deps.releaseExit();
43
+ return false;
44
+ };
45
+ const moved = () => {
46
+ if (deps.exitRequested()) return "exit requested";
47
+ if (client.inboundRoutedSinceCommit()) return "inbound message";
48
+ const verdict = deps.recheck();
49
+ return verdict.ok ? null : verdict.reason;
50
+ };
51
+ client.beginHibernationCommit();
52
+ try {
53
+ await client.flush();
54
+ } catch (error) {
55
+ return abort(`flush failed: ${error instanceof Error ? error.message : String(error)}`);
56
+ }
57
+ let why = moved();
58
+ if (why) return abort(why);
59
+ client.freezeInbound();
60
+ client.muteHeartbeats();
61
+ frozen = true;
62
+ const stamp = { at: now(), seq: client.messageCursor, idleMs: deps.idleMs, v: 1 };
63
+ stamped = true;
64
+ const landed = await waitOrExit(client.updateMetadataAndWait((metadata) => ({ ...metadata, hibernation: stamp })).catch(() => false), false);
65
+ if (deps.exitRequested()) return abort("exit requested");
66
+ if (!landed) return abort("stamp not confirmed");
67
+ const settle = Math.max(0, client.lastHeartbeatAt + (deps.presenceSettleMs ?? PRESENCE_SETTLE_MS) - now());
68
+ if (settle > 0) await waitOrExit(sleep(settle), void 0);
69
+ why = moved();
70
+ if (why) return abort(why);
71
+ deps.markCommitted();
72
+ log(`[hibernate] committing: seq=${stamp.seq} idleMs=${stamp.idleMs}`);
73
+ await deps.finish(stamp);
74
+ return true;
75
+ }
76
+ const EXIT_POLL_MS = 100;
77
+ const EXIT_CLEAR_TIMEOUT_MS = 1e3;
78
+ class HibernationProbe {
79
+ constructor(deps) {
80
+ this.deps = deps;
81
+ }
82
+ timer = null;
83
+ stopped = false;
84
+ running = false;
85
+ start() {
86
+ this.schedule(this.deps.checkMs);
87
+ }
88
+ stop() {
89
+ this.stopped = true;
90
+ if (this.timer !== null) (this.deps.clearTimer ?? ((h) => clearTimeout(h)))(this.timer);
91
+ this.timer = null;
92
+ }
93
+ schedule(ms) {
94
+ if (this.stopped) return;
95
+ const set = this.deps.setTimer ?? ((fn, delay) => {
96
+ const handle = setTimeout(fn, delay);
97
+ handle.unref?.();
98
+ return handle;
99
+ });
100
+ this.timer = set(() => {
101
+ void this.tick();
102
+ }, Math.max(1e3, ms));
103
+ }
104
+ /** One sample; returns the delay it scheduled (or null when it hibernated / stopped). */
105
+ async tick() {
106
+ if (this.stopped || this.running) return null;
107
+ this.running = true;
108
+ const log = this.deps.log ?? ((message) => logger.debug(message));
109
+ try {
110
+ const now = (this.deps.now ?? Date.now)();
111
+ const snapshot = this.deps.snapshot();
112
+ const local = evaluateWrapperIdle(snapshot, 1, now);
113
+ if (!local.ok && local.reason !== "keep-awake") {
114
+ this.schedule(this.deps.checkMs);
115
+ return this.deps.checkMs;
116
+ }
117
+ const answer = await this.deps.ask(snapshot);
118
+ if (answer === "unsupported") {
119
+ this.schedule(HIBERNATION_UNSUPPORTED_BACKOFF_MS);
120
+ return HIBERNATION_UNSUPPORTED_BACKOFF_MS;
121
+ }
122
+ if (answer === "error") {
123
+ this.schedule(this.deps.checkMs);
124
+ return this.deps.checkMs;
125
+ }
126
+ if (answer.keepAwake === true) this.deps.onKeepAwakeLatched?.();
127
+ if (local.ok && answer.hibernate && typeof answer.idleMs === "number" && answer.idleMs > 0) {
128
+ const done = await this.deps.commit(answer.idleMs);
129
+ if (done) {
130
+ this.stopped = true;
131
+ return null;
132
+ }
133
+ this.schedule(this.deps.checkMs);
134
+ return this.deps.checkMs;
135
+ }
136
+ const next = typeof answer.nextCheckMs === "number" && answer.nextCheckMs > 0 ? answer.nextCheckMs : this.deps.checkMs;
137
+ if (answer.reason) log(`[hibernate] daemon says stay awake (${answer.reason}); next check in ${Math.round(next / 1e3)}s`);
138
+ this.schedule(next);
139
+ return next;
140
+ } catch (error) {
141
+ log(`[hibernate] probe failed: ${error instanceof Error ? error.message : String(error)}`);
142
+ this.schedule(this.deps.checkMs);
143
+ return this.deps.checkMs;
144
+ } finally {
145
+ this.running = false;
146
+ }
147
+ }
148
+ }
149
+ class HibernationExitLatch {
150
+ constructor(outranks) {
151
+ this.outranks = outranks;
152
+ }
153
+ active = false;
154
+ committed = false;
155
+ deferredIntent = null;
156
+ begin() {
157
+ if (this.active) return false;
158
+ this.active = true;
159
+ this.committed = false;
160
+ this.deferredIntent = null;
161
+ return true;
162
+ }
163
+ get hibernating() {
164
+ return this.active;
165
+ }
166
+ /** true = the caller must NOT run this exit now (deferred, or the process is already leaving). */
167
+ intercept(intent) {
168
+ if (!this.active) return false;
169
+ if (!this.committed && (this.deferredIntent === null || this.outranks(intent, this.deferredIntent))) this.deferredIntent = intent;
170
+ return true;
171
+ }
172
+ get exitRequested() {
173
+ return this.deferredIntent !== null;
174
+ }
175
+ commit() {
176
+ if (this.active) this.committed = true;
177
+ }
178
+ /** Abort: returns the deferred exit to run now (or null). No-op once committed. */
179
+ release() {
180
+ if (!this.active || this.committed) return null;
181
+ this.active = false;
182
+ const deferred = this.deferredIntent;
183
+ this.deferredIntent = null;
184
+ return deferred;
185
+ }
186
+ }
187
+
188
+ const DEFAULT_CLAUDE_PERMISSION_MODE = "default";
189
+ const DEFAULT_CODEX_PERMISSION_MODE = "default";
190
+
191
+ export { DEFAULT_CLAUDE_PERMISSION_MODE as D, HibernationProbe as H, HibernationExitLatch as a, DEFAULT_CODEX_PERMISSION_MODE as b, commitHibernation as c };
@@ -0,0 +1,197 @@
1
+ 'use strict';
2
+
3
+ var logger = require('./logger-B_MWPbZz.cjs');
4
+ var persistence = require('./persistence-BYGl0QYw.cjs');
5
+
6
+ const PRESENCE_SETTLE_MS = 6e3;
7
+ async function commitHibernation(deps) {
8
+ const log = deps.log ?? ((message) => logger.logger.debug(message));
9
+ if (!deps.claimExit()) {
10
+ log("[hibernate] exit already claimed for another reason; not hibernating");
11
+ return false;
12
+ }
13
+ const { client } = deps;
14
+ const now = deps.now ?? Date.now;
15
+ const sleep = deps.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
16
+ let frozen = false;
17
+ let stamped = false;
18
+ const waitOrExit = async (work, fallback) => {
19
+ let settled = false;
20
+ const watched = work.finally(() => {
21
+ settled = true;
22
+ });
23
+ const exitWatch = (async () => {
24
+ while (!settled && !deps.exitRequested()) await sleep(EXIT_POLL_MS);
25
+ return settled ? watched : fallback;
26
+ })();
27
+ return Promise.race([watched, exitWatch]);
28
+ };
29
+ const abort = async (why2) => {
30
+ log(`[hibernate] aborted at commit: ${why2}`);
31
+ if (stamped) {
32
+ const clear = (metadata) => {
33
+ const next = { ...metadata };
34
+ delete next.hibernation;
35
+ return next;
36
+ };
37
+ const cleared = await client.updateMetadataAndWait(clear, deps.exitRequested() ? EXIT_CLEAR_TIMEOUT_MS : void 0).catch(() => false);
38
+ if (!cleared) log("[hibernate] stamp clear not confirmed (it keeps retrying in the background)");
39
+ }
40
+ if (frozen) {
41
+ client.unmuteHeartbeats();
42
+ client.unfreezeInbound();
43
+ }
44
+ deps.releaseExit();
45
+ return false;
46
+ };
47
+ const moved = () => {
48
+ if (deps.exitRequested()) return "exit requested";
49
+ if (client.inboundRoutedSinceCommit()) return "inbound message";
50
+ const verdict = deps.recheck();
51
+ return verdict.ok ? null : verdict.reason;
52
+ };
53
+ client.beginHibernationCommit();
54
+ try {
55
+ await client.flush();
56
+ } catch (error) {
57
+ return abort(`flush failed: ${error instanceof Error ? error.message : String(error)}`);
58
+ }
59
+ let why = moved();
60
+ if (why) return abort(why);
61
+ client.freezeInbound();
62
+ client.muteHeartbeats();
63
+ frozen = true;
64
+ const stamp = { at: now(), seq: client.messageCursor, idleMs: deps.idleMs, v: 1 };
65
+ stamped = true;
66
+ const landed = await waitOrExit(client.updateMetadataAndWait((metadata) => ({ ...metadata, hibernation: stamp })).catch(() => false), false);
67
+ if (deps.exitRequested()) return abort("exit requested");
68
+ if (!landed) return abort("stamp not confirmed");
69
+ const settle = Math.max(0, client.lastHeartbeatAt + (deps.presenceSettleMs ?? PRESENCE_SETTLE_MS) - now());
70
+ if (settle > 0) await waitOrExit(sleep(settle), void 0);
71
+ why = moved();
72
+ if (why) return abort(why);
73
+ deps.markCommitted();
74
+ log(`[hibernate] committing: seq=${stamp.seq} idleMs=${stamp.idleMs}`);
75
+ await deps.finish(stamp);
76
+ return true;
77
+ }
78
+ const EXIT_POLL_MS = 100;
79
+ const EXIT_CLEAR_TIMEOUT_MS = 1e3;
80
+ class HibernationProbe {
81
+ constructor(deps) {
82
+ this.deps = deps;
83
+ }
84
+ timer = null;
85
+ stopped = false;
86
+ running = false;
87
+ start() {
88
+ this.schedule(this.deps.checkMs);
89
+ }
90
+ stop() {
91
+ this.stopped = true;
92
+ if (this.timer !== null) (this.deps.clearTimer ?? ((h) => clearTimeout(h)))(this.timer);
93
+ this.timer = null;
94
+ }
95
+ schedule(ms) {
96
+ if (this.stopped) return;
97
+ const set = this.deps.setTimer ?? ((fn, delay) => {
98
+ const handle = setTimeout(fn, delay);
99
+ handle.unref?.();
100
+ return handle;
101
+ });
102
+ this.timer = set(() => {
103
+ void this.tick();
104
+ }, Math.max(1e3, ms));
105
+ }
106
+ /** One sample; returns the delay it scheduled (or null when it hibernated / stopped). */
107
+ async tick() {
108
+ if (this.stopped || this.running) return null;
109
+ this.running = true;
110
+ const log = this.deps.log ?? ((message) => logger.logger.debug(message));
111
+ try {
112
+ const now = (this.deps.now ?? Date.now)();
113
+ const snapshot = this.deps.snapshot();
114
+ const local = persistence.evaluateWrapperIdle(snapshot, 1, now);
115
+ if (!local.ok && local.reason !== "keep-awake") {
116
+ this.schedule(this.deps.checkMs);
117
+ return this.deps.checkMs;
118
+ }
119
+ const answer = await this.deps.ask(snapshot);
120
+ if (answer === "unsupported") {
121
+ this.schedule(persistence.HIBERNATION_UNSUPPORTED_BACKOFF_MS);
122
+ return persistence.HIBERNATION_UNSUPPORTED_BACKOFF_MS;
123
+ }
124
+ if (answer === "error") {
125
+ this.schedule(this.deps.checkMs);
126
+ return this.deps.checkMs;
127
+ }
128
+ if (answer.keepAwake === true) this.deps.onKeepAwakeLatched?.();
129
+ if (local.ok && answer.hibernate && typeof answer.idleMs === "number" && answer.idleMs > 0) {
130
+ const done = await this.deps.commit(answer.idleMs);
131
+ if (done) {
132
+ this.stopped = true;
133
+ return null;
134
+ }
135
+ this.schedule(this.deps.checkMs);
136
+ return this.deps.checkMs;
137
+ }
138
+ const next = typeof answer.nextCheckMs === "number" && answer.nextCheckMs > 0 ? answer.nextCheckMs : this.deps.checkMs;
139
+ if (answer.reason) log(`[hibernate] daemon says stay awake (${answer.reason}); next check in ${Math.round(next / 1e3)}s`);
140
+ this.schedule(next);
141
+ return next;
142
+ } catch (error) {
143
+ log(`[hibernate] probe failed: ${error instanceof Error ? error.message : String(error)}`);
144
+ this.schedule(this.deps.checkMs);
145
+ return this.deps.checkMs;
146
+ } finally {
147
+ this.running = false;
148
+ }
149
+ }
150
+ }
151
+ class HibernationExitLatch {
152
+ constructor(outranks) {
153
+ this.outranks = outranks;
154
+ }
155
+ active = false;
156
+ committed = false;
157
+ deferredIntent = null;
158
+ begin() {
159
+ if (this.active) return false;
160
+ this.active = true;
161
+ this.committed = false;
162
+ this.deferredIntent = null;
163
+ return true;
164
+ }
165
+ get hibernating() {
166
+ return this.active;
167
+ }
168
+ /** true = the caller must NOT run this exit now (deferred, or the process is already leaving). */
169
+ intercept(intent) {
170
+ if (!this.active) return false;
171
+ if (!this.committed && (this.deferredIntent === null || this.outranks(intent, this.deferredIntent))) this.deferredIntent = intent;
172
+ return true;
173
+ }
174
+ get exitRequested() {
175
+ return this.deferredIntent !== null;
176
+ }
177
+ commit() {
178
+ if (this.active) this.committed = true;
179
+ }
180
+ /** Abort: returns the deferred exit to run now (or null). No-op once committed. */
181
+ release() {
182
+ if (!this.active || this.committed) return null;
183
+ this.active = false;
184
+ const deferred = this.deferredIntent;
185
+ this.deferredIntent = null;
186
+ return deferred;
187
+ }
188
+ }
189
+
190
+ const DEFAULT_CLAUDE_PERMISSION_MODE = "default";
191
+ const DEFAULT_CODEX_PERMISSION_MODE = "default";
192
+
193
+ exports.DEFAULT_CLAUDE_PERMISSION_MODE = DEFAULT_CLAUDE_PERMISSION_MODE;
194
+ exports.DEFAULT_CODEX_PERMISSION_MODE = DEFAULT_CODEX_PERMISSION_MODE;
195
+ exports.HibernationExitLatch = HibernationExitLatch;
196
+ exports.HibernationProbe = HibernationProbe;
197
+ exports.commitHibernation = commitHibernation;