very-happy-cli 0.2.177 → 0.2.179

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 (203) hide show
  1. package/dist/{AcpBackend-B0K0WrtW.mjs → AcpBackend-CHp3y7cb.mjs} +135 -16
  2. package/dist/{AcpBackend-B-ny68XM.cjs → AcpBackend-DFipFF7-.cjs} +135 -16
  3. package/dist/{AcpSessionManager-CjdJLofq.cjs → AcpSessionManager-0zpvRJXc.cjs} +38 -4
  4. package/dist/{AcpSessionManager-DykjzBM4.mjs → AcpSessionManager-d2-rKWWa.mjs} +38 -4
  5. package/dist/{BasePermissionHandler-DR6nxuEn.cjs → BasePermissionHandler-CH3zuEkA.cjs} +5 -2
  6. package/dist/{BasePermissionHandler-hdY7kTqX.mjs → BasePermissionHandler-DdZBYIR4.mjs} +5 -2
  7. package/dist/acpSessionResume-DTGmAPLt.mjs +67 -0
  8. package/dist/acpSessionResume-oiCBnAVA.cjs +74 -0
  9. package/dist/{agentHome-BdTXEUPe.cjs → agentHome-BWcz8mz0.cjs} +5 -5
  10. package/dist/{agentHome-GRN2VfHv.mjs → agentHome-CghLvL_1.mjs} +5 -5
  11. package/dist/{api-BWX10o97.cjs → api-Cmjfr8Z7.cjs} +29 -261
  12. package/dist/{api-CKBViqI3.mjs → api-CzwFpJQc.mjs} +22 -254
  13. package/dist/{apiMachine-DttO4UFj.mjs → apiMachine-DJkTEiqy.mjs} +53 -16
  14. package/dist/{apiMachine-BYYFGgFs.cjs → apiMachine-G6OogT08.cjs} +53 -16
  15. package/dist/{attachmentContent-cPVF463_.mjs → attachmentContent-B2os4HbA.mjs} +2 -2
  16. package/dist/{attachmentContent-kJKXpkMX.cjs → attachmentContent-Bo0UAsSu.cjs} +4 -4
  17. package/dist/{auth-BmESeKuM.mjs → auth-BS6PaOOG.mjs} +6 -6
  18. package/dist/{auth-CTECt2Oz.cjs → auth-D6bBUwZa.cjs} +6 -6
  19. package/dist/{auth-CKdXb9zp.mjs → auth-DMX0xPNK.mjs} +9 -9
  20. package/dist/{auth-DNxVmVbn.cjs → auth-HEhRaNgL.cjs} +9 -9
  21. package/dist/{authRelay-DSAvg1uv.mjs → authRelay-DhQhkBvX.mjs} +1 -1
  22. package/dist/{authRelay-BdYkC1Po.cjs → authRelay-Dy1qU9td.cjs} +1 -0
  23. package/dist/{auto-D1ypjjfx.cjs → auto-C6I55iOh.cjs} +19 -18
  24. package/dist/{auto-Ch3203qd.mjs → auto-Cl1SEDcD.mjs} +19 -18
  25. package/dist/{bootstrap-6OI698q9.cjs → bootstrap-exVucYav.cjs} +2 -2
  26. package/dist/{bootstrap-C0s2bPFQ.mjs → bootstrap-iuyufnp3.mjs} +2 -2
  27. package/dist/{browser-DG6Uof5O.cjs → browser-BohJK12g.cjs} +1 -1
  28. package/dist/{browser-BlLWZUMx.mjs → browser-CSYum7xH.mjs} +1 -1
  29. package/dist/{claudeLocal-CcWcKnoo.mjs → claudeLocal-Dq_R3Ax_.mjs} +6 -5
  30. package/dist/{claudeLocal-CemsIArT.cjs → claudeLocal-re4yjSTx.cjs} +6 -5
  31. package/dist/{claudeLocalLauncher-A4VuevIi.cjs → claudeLocalLauncher-B4hJHpCA.cjs} +11 -10
  32. package/dist/{claudeLocalLauncher-7p6y88nj.mjs → claudeLocalLauncher-CN67lN7-.mjs} +11 -10
  33. package/dist/{claudeSessionFork-BtROOjqf.mjs → claudeSessionFork-BihfD0Ik.mjs} +1 -1
  34. package/dist/{claudeSessionFork-CbDfm8Fz.cjs → claudeSessionFork-DiSMYerV.cjs} +1 -1
  35. package/dist/{client-DyvBTYee.cjs → client-BKcK1Bi-.cjs} +3 -3
  36. package/dist/client-BhoEBnuN.mjs +71 -0
  37. package/dist/{client-COmgDDy0.cjs → client-CuVdN6PP.cjs} +2 -2
  38. package/dist/{client-BPMWutfs.mjs → client-DuTDwWSQ.mjs} +3 -3
  39. package/dist/client-ZjOsn6nZ.cjs +76 -0
  40. package/dist/{client-DG5ndWLw.mjs → client-wo9nbxuf.mjs} +2 -2
  41. package/dist/codex/happyMcpStdioBridge.cjs +25 -16
  42. package/dist/codex/happyMcpStdioBridge.mjs +25 -16
  43. package/dist/{codexAppServerClient-D-Z8qSfI.mjs → codexAppServerClient-BK3zra_1.mjs} +3 -3
  44. package/dist/{codexAppServerClient-R24WZZfg.cjs → codexAppServerClient-Dt5zxrun.cjs} +3 -3
  45. package/dist/{codexCommand-CVTkZJ1o.mjs → codexCommand-B6pY7CMh.mjs} +66 -61
  46. package/dist/{codexCommand-6hW19gsq.cjs → codexCommand-CAZ1SLjg.cjs} +89 -84
  47. package/dist/{codexTermination-CCIfwzcx.mjs → codexTermination-Cd1Eon_4.mjs} +1 -1
  48. package/dist/{codexTermination-BBU7e92y.cjs → codexTermination-DmGbHxcD.cjs} +1 -1
  49. package/dist/{config-CvsNChKX.mjs → config-2oMG_fEI.mjs} +3 -3
  50. package/dist/{config-DhdrvOLV.cjs → config-B0uK6K7n.cjs} +3 -3
  51. package/dist/{configuration-DZPy0T9Z.cjs → configuration-CMHZnp6G.cjs} +1 -1
  52. package/dist/{configuration-D55F0t16.mjs → configuration-WMi4idBB.mjs} +1 -1
  53. package/dist/{connect-CwCXMRmD.mjs → connect-BLVHhHzA.mjs} +15 -15
  54. package/dist/{connect-Wz-XZYXW.cjs → connect-uaglGrde.cjs} +15 -15
  55. package/dist/{context-BKbrZ55r.cjs → context-DXzU5bFM.cjs} +1 -1
  56. package/dist/{context-CCRpVXFo.mjs → context-DploEcoN.mjs} +1 -1
  57. package/dist/{controlClient-C4xB5J6O.mjs → controlClient-BWUJrj3t.mjs} +3 -3
  58. package/dist/{controlClient-SX8gSza2.cjs → controlClient-C-5qCt8W.cjs} +3 -3
  59. package/dist/{createSessionMetadata-Bi-m0Y_O.mjs → createSessionMetadata-3uXrJgOW.mjs} +2 -2
  60. package/dist/{createSessionMetadata-BCFmYlBo.cjs → createSessionMetadata-BkIzHALd.cjs} +2 -2
  61. package/dist/{defaultPermissionMode-wBcbBezm.mjs → defaultPermissionMode-BzxLh20a.mjs} +2 -2
  62. package/dist/{defaultPermissionMode-DMBEnXll.cjs → defaultPermissionMode-pS3vmiSg.cjs} +2 -2
  63. package/dist/{deterministicJson-ChGfQEF6.cjs → deterministicJson-B8z2GPi9.cjs} +220 -14
  64. package/dist/{deterministicJson-BkQETt8_.mjs → deterministicJson-D_whDMFd.mjs} +217 -12
  65. package/dist/{doctor-BsN3JZJn.cjs → doctor-Br1Kcy2J.cjs} +8 -8
  66. package/dist/{doctor-B9c2C9dF.mjs → doctor-CmtSsR2-.mjs} +8 -8
  67. package/dist/{downloadTarget-Dj3WoVJa.cjs → downloadTarget-BQJK_6oH.cjs} +6 -6
  68. package/dist/{downloadTarget-ByXzbDK4.mjs → downloadTarget-BoNwTIH_.mjs} +6 -6
  69. package/dist/{ensureDaemonRunning-7Wb8M7Lv.cjs → ensureDaemonRunning-BRUmsq6J.cjs} +5 -5
  70. package/dist/{ensureDaemonRunning--HYzs5Ce.mjs → ensureDaemonRunning-Czo9IHJQ.mjs} +5 -5
  71. package/dist/{handleResumeCommand-DHddBkNJ.mjs → handleResumeCommand-C8thKjqf.mjs} +22 -6
  72. package/dist/{handleResumeCommand-OmuUGYjQ.cjs → handleResumeCommand-tKD_Hpxc.cjs} +22 -6
  73. package/dist/{index-CrR4JISa.cjs → index-B0UjHlAe.cjs} +5 -5
  74. package/dist/{index-BzJNDsJq.mjs → index-BTxHphpV.mjs} +254 -49
  75. package/dist/index-BiyC7cZ3.mjs +18 -0
  76. package/dist/{index-De8L5lFK.cjs → index-C6O2vVjm.cjs} +156 -34
  77. package/dist/index-CUuc6iCn.cjs +24 -0
  78. package/dist/{index-Dhl6_bw7.mjs → index-CdQI0C9p.mjs} +5 -5
  79. package/dist/{index-D9NoYc5I.cjs → index-D09T1m8Y.cjs} +3 -3
  80. package/dist/{index-CEm0MYiS.mjs → index-D3bidoG8.mjs} +3 -3
  81. package/dist/{index-BRJzH4sc.cjs → index-DMqDMT1Q.cjs} +257 -52
  82. package/dist/{index-DMy3OCBe.mjs → index-DPOa4NhL.mjs} +154 -35
  83. package/dist/index.cjs +2 -2
  84. package/dist/index.mjs +2 -2
  85. package/dist/{install-BdvKiOQw.mjs → install-BX3lv3NO.mjs} +1 -1
  86. package/dist/{install-Cf6AFSWC.cjs → install-BXvf2E3o.cjs} +1 -1
  87. package/dist/{install-1qn-D9FS.cjs → install-CYRZxS87.cjs} +3 -3
  88. package/dist/{install-BDIUtPXi.mjs → install-hnve_9vq.mjs} +3 -3
  89. package/dist/lib.cjs +14 -14
  90. package/dist/lib.d.cts +65 -1
  91. package/dist/lib.d.mts +65 -1
  92. package/dist/lib.mjs +14 -14
  93. package/dist/{lidState-BqVsw7H1.mjs → lidState-Bb8fgXg3.mjs} +2 -2
  94. package/dist/{lidState-DxbK0qfu.cjs → lidState-Dv2wwFTj.cjs} +2 -2
  95. package/dist/{localHappyAgentAuth-D5tANdRD.cjs → localHappyAgentAuth-DjYvkXvV.cjs} +2 -2
  96. package/dist/{localHappyAgentAuth-Ce8kO2yc.mjs → localHappyAgentAuth-NEU7fax7.mjs} +2 -2
  97. package/dist/{logger-13cBr_ew.mjs → logger-BtVhHnD8.mjs} +2 -2
  98. package/dist/{logger-LvwVeATU.cjs → logger-C1GWx3gi.cjs} +2 -2
  99. package/dist/{machineMetadata-29h7vgf4.cjs → machineMetadata-CLHS9sv_.cjs} +3 -3
  100. package/dist/{machineMetadata-dMida2qq.mjs → machineMetadata-D-g--oU_.mjs} +3 -3
  101. package/dist/{main-x4nAhdH5.mjs → main-B2LWV8DI.mjs} +59 -46
  102. package/dist/{main-DpM5jaFH.cjs → main-CWhSsbtU.cjs} +59 -46
  103. package/dist/{mcp-DQv3caXs.cjs → mcp-CARUsXHV.cjs} +15 -15
  104. package/dist/{mcp-DMiFGYMT.mjs → mcp-ext92q3Y.mjs} +15 -15
  105. package/dist/{mirrorProtocol-Bz8tEabR.mjs → mirrorProtocol-BwYibqry.mjs} +3 -3
  106. package/dist/{mirrorProtocol-BfrERW7Z.cjs → mirrorProtocol-DEy2g1CB.cjs} +3 -3
  107. package/dist/{package-CjlsAaRe.mjs → package-BPPebGQF.mjs} +7 -7
  108. package/dist/{package-Ch9WGDV_.cjs → package-SgqTYsjn.cjs} +7 -7
  109. package/dist/panels-BZ0_Tt7B.mjs +137 -0
  110. package/dist/panels-D1c7q2dD.cjs +142 -0
  111. package/dist/{peerTools-CxmrKnfV.mjs → peerTools-CWKzcQ7u.mjs} +60 -10
  112. package/dist/{peerTools-DtGKWli5.cjs → peerTools-DRQETXaz.cjs} +60 -9
  113. package/dist/{persistence-DXbKOHxl.cjs → persistence-BegE7NPa.cjs} +14 -3
  114. package/dist/{persistence-C_tYtOqK.mjs → persistence-Cr-wutZ4.mjs} +14 -4
  115. package/dist/{piRunnerArgs-BVRZe2AR.cjs → piRunnerArgs-Cs-378Vz.cjs} +8 -2
  116. package/dist/{piRunnerArgs-BpHc-JZl.mjs → piRunnerArgs-DwvM_yWA.mjs} +7 -1
  117. package/dist/{piRuntime-D7eio8Ix.cjs → piRuntime-BG-1td_n.cjs} +2 -2
  118. package/dist/{piRuntime-DOdGF395.mjs → piRuntime-Bue5mnlc.mjs} +2 -2
  119. package/dist/{piTerminal-dpxz4Q8D.mjs → piTerminal-B5x9X5yV.mjs} +18 -18
  120. package/dist/{piTerminal-y_PRo2NY.cjs → piTerminal-G4z-xVyy.cjs} +18 -18
  121. package/dist/processTreeSnapshot-CuLJDNC-.mjs +101 -0
  122. package/dist/processTreeSnapshot-mDbnuojn.cjs +105 -0
  123. package/dist/prompt-BOouDaTM.mjs +99 -0
  124. package/dist/prompt-lgF9IE82.cjs +105 -0
  125. package/dist/{attachmentLimits-Di1Z93lN.mjs → pushNotifications-BdFjDjQe.mjs} +303 -3
  126. package/dist/{attachmentLimits-DtFqqiwR.cjs → pushNotifications-DaLQUyi0.cjs} +304 -2
  127. package/dist/{index-DFPT4HOO.cjs → query-Ctfg-5gy.cjs} +25 -5
  128. package/dist/{index-CEjJnq05.mjs → query-DYP_W1wp.mjs} +26 -3
  129. package/dist/{rateLimitWindows-DYHDGuzQ.mjs → rateLimitWindows-CuEqk_0g.mjs} +1 -1
  130. package/dist/{rateLimitWindows-DFnMU2Vt.cjs → rateLimitWindows-Dj_8voBK.cjs} +1 -1
  131. package/dist/{registerCommonHandlers-D8OMpBbQ.mjs → registerCommonHandlers-BAlP7SGc.mjs} +2 -2
  132. package/dist/{registerCommonHandlers-60VuTkdg.cjs → registerCommonHandlers-Cj084Sg7.cjs} +2 -2
  133. package/dist/{registerKillSessionHandler-Drhf7-Vz.mjs → registerKillSessionHandler-PD0jWtQo.mjs} +6 -6
  134. package/dist/{registerKillSessionHandler-pqChBKwO.cjs → registerKillSessionHandler-qMju0ZfF.cjs} +6 -6
  135. package/dist/{remoteSessionClient-B7NvjHD3.cjs → remoteSessionClient-B7i7MkYV.cjs} +5 -5
  136. package/dist/{remoteSessionClient-D01Hso2-.mjs → remoteSessionClient-Bn2qu5C5.mjs} +5 -5
  137. package/dist/{reportProgressTool-Du_zAK4h.cjs → reportProgressTool-CM1JFAHg.cjs} +84 -2
  138. package/dist/{reportProgressTool-B203EZCR.mjs → reportProgressTool-gHItlSzz.mjs} +82 -3
  139. package/dist/{resources-JDPugcDq.cjs → resources-CvIlkzpP.cjs} +30 -0
  140. package/dist/{resources-BdFBQi8r.mjs → resources-y9jfyO-_.mjs} +30 -0
  141. package/dist/{run-DX4Zs3Ug.mjs → run-BM4TxiyN.mjs} +249 -45
  142. package/dist/{run-DZ5jU53c.cjs → run-CNXwIe0A.cjs} +263 -59
  143. package/dist/{runClaude-ClRhHpwR.cjs → runClaude-CWhj2V4Q.cjs} +37 -41
  144. package/dist/{runClaude-CgPHXP0L.mjs → runClaude-C_3I8hvR.mjs} +37 -41
  145. package/dist/{runClaudeDeps-D2v_WDSL.cjs → runClaudeDeps-B81cOKnH.cjs} +295 -157
  146. package/dist/{runClaudeDeps-Dz2iydq4.mjs → runClaudeDeps-QGrOeDe2.mjs} +295 -160
  147. package/dist/{runGemini-DBXxpoY8.mjs → runGemini-BEdWEZLR.mjs} +61 -55
  148. package/dist/{runGemini-BtZqGFkp.cjs → runGemini-CgRLYbt5.cjs} +61 -55
  149. package/dist/{runOpenClaw-D8q8G57u.cjs → runOpenClaw-C1NVmzOL.cjs} +19 -19
  150. package/dist/{runOpenClaw-BOHpzCEU.mjs → runOpenClaw-DdQZAYj1.mjs} +19 -19
  151. package/dist/{sandbox-C452Vrsc.mjs → sandbox-DjQUdCMG.mjs} +5 -5
  152. package/dist/{sandbox-Cu9mMzjx.cjs → sandbox-nocIjliq.cjs} +5 -5
  153. package/dist/selfCheck-CjCF4C3v.mjs +85 -0
  154. package/dist/{selfCheck-gKa3uVr1.cjs → selfCheck-DCt4Uzbq.cjs} +36 -35
  155. package/dist/{send-B8HARi7x.mjs → send-Ct7X4pPU.mjs} +9 -9
  156. package/dist/{send-2Vb5eppI.cjs → send-Dydf_hwZ.cjs} +9 -9
  157. package/dist/{server-Db9Wuam3.cjs → server-CosABFbd.cjs} +7 -7
  158. package/dist/{server-BBWCIZyS.mjs → server-DTQGZMxh.mjs} +5 -5
  159. package/dist/{sessionLock-6qL_N6Rn.cjs → sessionLock-DokGab2R.cjs} +16 -3
  160. package/dist/{sessionLock-ZfvFVdUi.mjs → sessionLock-WYIyaVO4.mjs} +16 -4
  161. package/dist/{sessionOps-CdgbEJgf.mjs → sessionOps-BIGgRube.mjs} +11 -6
  162. package/dist/{sessionOps-Dmt7WUUs.cjs → sessionOps-S-qPBLFf.cjs} +11 -6
  163. package/dist/{sessionScanner-CQL_WSaC.cjs → sessionScanner-CIMM2hvZ.cjs} +3 -3
  164. package/dist/{sessionScanner-CNVaSNOn.mjs → sessionScanner-o5hnMi5e.mjs} +3 -3
  165. package/dist/{sessions-DTomHfFg.mjs → sessions-BJHEZpi2.mjs} +40 -18
  166. package/dist/{sessions-BJblG_Hx.cjs → sessions-JchI1w3z.cjs} +40 -17
  167. package/dist/{setupOfflineReconnection-DVA0VpQL.cjs → setupOfflineReconnection-CNiAt5ZP.cjs} +2 -2
  168. package/dist/{setupOfflineReconnection-C5trsV-j.mjs → setupOfflineReconnection-DMiBO2y9.mjs} +2 -2
  169. package/dist/{spawn-DRyNAqD8.cjs → spawn-6PD7nnoC.cjs} +49 -18
  170. package/dist/{spawn-CQJFgoOq.mjs → spawn-DgvUNYEo.mjs} +49 -18
  171. package/dist/{spawnAgents-CCjJifAW.cjs → spawnAgents-DsXgegHM.cjs} +37 -1
  172. package/dist/spawnAgents-P006Hqio.mjs +79 -0
  173. package/dist/{spawnHappyCLI-B_0RWxD4.mjs → spawnHappyCLI-CCOrEtf9.mjs} +1 -1
  174. package/dist/{spawnHappyCLI-ChniczJ5.cjs → spawnHappyCLI-Dywezwk6.cjs} +1 -1
  175. package/dist/{specialCommands-DkdFJi4N.mjs → specialCommands-DPcd9edP.mjs} +3 -3
  176. package/dist/{specialCommands-DbntVs0d.cjs → specialCommands-QxPpkGKf.cjs} +3 -3
  177. package/dist/{startFileWatcher-UQyTSRAP.mjs → startFileWatcher-DghDOCO4.mjs} +1 -1
  178. package/dist/{startFileWatcher-C292fhra.cjs → startFileWatcher-RECH5qY8.cjs} +1 -1
  179. package/dist/{streamRelay-_qCd873P.mjs → streamRelay-DMV_TXfS.mjs} +1 -1
  180. package/dist/{streamRelay-Cx01enfe.cjs → streamRelay-DlUWKUpo.cjs} +1 -1
  181. package/dist/{sync-C3p7-KLn.mjs → sync-CSe0Rf45.mjs} +1 -1
  182. package/dist/{sync-C7sxoUYG.cjs → sync-D23jbqVa.cjs} +1 -1
  183. package/dist/{systemPrompt-DtibzbRU.cjs → systemPrompt-BOy4kU4P.cjs} +4 -3
  184. package/dist/{systemPrompt-CdHOlyVW.mjs → systemPrompt-CFNKnh65.mjs} +4 -3
  185. package/dist/{teams-ujXr3AFn.mjs → teams-DyY669f0.mjs} +9 -9
  186. package/dist/{teams-D7O7TpVU.cjs → teams-Ov2BDT-A.cjs} +9 -9
  187. package/dist/{time-yEL6wHUF.mjs → time-65DcU6Jx.mjs} +1 -1
  188. package/dist/{time-Dg5tVB8S.cjs → time-CrwIMHta.cjs} +1 -1
  189. package/dist/{titleGenerator-BMEaDTwU.cjs → titleGenerator-CS_rh2_J.cjs} +9 -8
  190. package/dist/{titleGenerator-Dr-BtjzO.mjs → titleGenerator-CiAMxf7s.mjs} +9 -8
  191. package/dist/{todo-CvJe4M2C.mjs → todo-BDONw0sK.mjs} +7 -7
  192. package/dist/{todo-CUcFamGs.cjs → todo-KY-okGii.cjs} +7 -7
  193. package/dist/{tools-BrM3bZW5.mjs → tools-D8-PnZEG.mjs} +1 -1
  194. package/dist/{tools-DDKTB5aQ.cjs → tools-_w52DZG6.cjs} +1 -1
  195. package/dist/{uninstall-7oLuhYIu.cjs → uninstall-8vnLN-IE.cjs} +3 -3
  196. package/dist/{uninstall-CEcMMQGz.mjs → uninstall-_fjGRP9b.mjs} +3 -3
  197. package/dist/webPanels-B2_C2-3g.mjs +49 -0
  198. package/dist/webPanels-FCgFKvVe.cjs +53 -0
  199. package/package.json +7 -7
  200. package/dist/selfCheck-BAvqBwBR.mjs +0 -84
  201. package/dist/sessionModeFile-CWVq8AT9.mjs +0 -32
  202. package/dist/sessionModeFile-CsLtn_PL.cjs +0 -36
  203. package/dist/spawnAgents-BjtmjBvP.mjs +0 -45
@@ -1,5 +1,5 @@
1
1
  import { createId } from '@paralleldrive/cuid2';
2
- import { s as streamKeyOf, c as createEnvelope } from './index-DMy3OCBe.mjs';
2
+ import { s as streamKeyOf, d as createEnvelope } from './index-DPOa4NhL.mjs';
3
3
 
4
4
  function turnOptions(turnId, time) {
5
5
  return turnId ? { turn: turnId, time } : { time };
@@ -22,6 +22,26 @@ function toolCallEndResult(result) {
22
22
  ...record.truncated === true ? { truncated: true } : {}
23
23
  };
24
24
  }
25
+ function piSubagentLabel(args) {
26
+ if (args.piTool !== "subagent") return null;
27
+ const raw = args.rawInput && typeof args.rawInput === "object" ? args.rawInput : {};
28
+ const clip = (text) => {
29
+ const flat = text.replace(/\s+/g, " ").trim();
30
+ return flat.length > 120 ? `${flat.slice(0, 119)}\u2026` : flat;
31
+ };
32
+ const agent = typeof raw.agent === "string" ? raw.agent : void 0;
33
+ if (typeof raw.task === "string" && raw.task.trim()) return { description: clip(raw.task), ...agent ? { subagentType: agent } : {} };
34
+ if (Array.isArray(raw.tasks)) return { description: `${raw.tasks.length} parallel task${raw.tasks.length === 1 ? "" : "s"}`, ...agent ? { subagentType: agent } : {} };
35
+ if (Array.isArray(raw.chain)) return { description: `chain of ${raw.chain.length} step${raw.chain.length === 1 ? "" : "s"}` };
36
+ return { description: agent ? `${agent} sub-agent` : "sub-agent", ...agent ? { subagentType: agent } : {} };
37
+ }
38
+ function subagentStopStatus(result) {
39
+ if (!result || typeof result !== "object" || Array.isArray(result)) return "completed";
40
+ const record = result;
41
+ if (record.status === "cancelled" || record.status === "canceled") return "stopped";
42
+ if (record.error !== void 0 || record.status === "failed" || typeof record.exitCode === "number" && record.exitCode !== 0) return "failed";
43
+ return "completed";
44
+ }
25
45
  function parseThinkingPayload(payload) {
26
46
  if (typeof payload === "string") {
27
47
  return { text: payload, streaming: false };
@@ -35,6 +55,8 @@ function parseThinkingPayload(payload) {
35
55
  }
36
56
  class AcpSessionManager {
37
57
  currentTurnId = null;
58
+ /** B-632 ③: ACP call id → sub-agent id of a running pi `subagent` call. */
59
+ subagentByCall = /* @__PURE__ */ new Map();
38
60
  acpCallToSessionCall = /* @__PURE__ */ new Map();
39
61
  stream;
40
62
  /** Monotonic clock: max(lastTime + 1, Date.now()) */
@@ -132,10 +154,13 @@ class AcpSessionManager {
132
154
  return flushed;
133
155
  }
134
156
  const turnId = this.currentTurnId;
157
+ const stops = [...this.subagentByCall.values()].map((subagent) => createEnvelope("agent", { t: "stop", status: status === "completed" ? "completed" : "stopped" }, { turn: turnId, time: this.nextTime(), subagent }));
158
+ this.subagentByCall.clear();
135
159
  this.currentTurnId = null;
136
160
  this.acpCallToSessionCall.clear();
137
161
  return [
138
162
  ...flushed,
163
+ ...stops,
139
164
  createEnvelope("agent", { t: "turn-end", status }, { turn: turnId, time: this.nextTime() })
140
165
  ];
141
166
  }
@@ -170,6 +195,10 @@ class AcpSessionManager {
170
195
  if (msg.type === "tool-call") {
171
196
  const flushed = this.flush();
172
197
  const call = this.ensureSessionCallId(msg.callId);
198
+ const label = piSubagentLabel(msg.args ?? {});
199
+ const subagent = label ? this.subagentByCall.get(msg.callId) ?? createId() : void 0;
200
+ const started = subagent !== void 0 && !this.subagentByCall.has(msg.callId);
201
+ if (subagent) this.subagentByCall.set(msg.callId, subagent);
173
202
  return [
174
203
  ...flushed,
175
204
  createEnvelope("agent", {
@@ -178,17 +207,22 @@ class AcpSessionManager {
178
207
  name: msg.toolName,
179
208
  title: buildToolTitle(msg.toolName),
180
209
  description: buildToolDescription(msg.toolName),
181
- args: msg.args
182
- }, turnOptions(this.currentTurnId, this.nextTime()))
210
+ // The web links the call row to the sub-agent card by this id (as for Claude's Agent).
211
+ args: subagent ? { ...msg.args, sessionSubagent: subagent } : msg.args
212
+ }, turnOptions(this.currentTurnId, this.nextTime())),
213
+ ...started && label ? [createEnvelope("agent", { t: "start", ...label }, { ...turnOptions(this.currentTurnId, this.nextTime()), subagent })] : []
183
214
  ];
184
215
  }
185
216
  if (msg.type === "tool-result") {
186
217
  const flushed = this.flush();
187
218
  const call = this.ensureSessionCallId(msg.callId);
188
219
  const result = toolCallEndResult(msg.result);
220
+ const subagent = this.subagentByCall.get(msg.callId);
221
+ if (subagent) this.subagentByCall.delete(msg.callId);
189
222
  return [
190
223
  ...flushed,
191
- createEnvelope("agent", { t: "tool-call-end", call, ...result ? { result } : {} }, turnOptions(this.currentTurnId, this.nextTime()))
224
+ createEnvelope("agent", { t: "tool-call-end", call, ...result ? { result } : {} }, turnOptions(this.currentTurnId, this.nextTime())),
225
+ ...subagent ? [createEnvelope("agent", { t: "stop", status: subagentStopStatus(msg.result) }, { ...turnOptions(this.currentTurnId, this.nextTime()), subagent })] : []
192
226
  ];
193
227
  }
194
228
  return [];
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var logger = require('./logger-LvwVeATU.cjs');
3
+ var logger = require('./logger-C1GWx3gi.cjs');
4
4
 
5
5
  class BasePermissionHandler {
6
6
  pendingRequests = /* @__PURE__ */ new Map();
@@ -32,7 +32,10 @@ class BasePermissionHandler {
32
32
  return;
33
33
  }
34
34
  this.pendingRequests.delete(response.id);
35
- const result = response.approved ? { decision: response.decision === "approved_for_session" ? "approved_for_session" : "approved" } : { decision: response.decision === "denied" ? "denied" : "abort" };
35
+ const result = response.approved ? {
36
+ decision: response.decision === "approved_for_session" ? "approved_for_session" : "approved",
37
+ ...response.updatedInput && typeof response.updatedInput === "object" ? { updatedInput: response.updatedInput } : {}
38
+ } : { decision: response.decision === "denied" ? "denied" : "abort" };
36
39
  pending.resolve(result);
37
40
  this.session.updateAgentState((currentState) => {
38
41
  const request = currentState.requests?.[response.id];
@@ -1,4 +1,4 @@
1
- import { l as logger } from './logger-13cBr_ew.mjs';
1
+ import { l as logger } from './logger-BtVhHnD8.mjs';
2
2
 
3
3
  class BasePermissionHandler {
4
4
  pendingRequests = /* @__PURE__ */ new Map();
@@ -30,7 +30,10 @@ class BasePermissionHandler {
30
30
  return;
31
31
  }
32
32
  this.pendingRequests.delete(response.id);
33
- const result = response.approved ? { decision: response.decision === "approved_for_session" ? "approved_for_session" : "approved" } : { decision: response.decision === "denied" ? "denied" : "abort" };
33
+ const result = response.approved ? {
34
+ decision: response.decision === "approved_for_session" ? "approved_for_session" : "approved",
35
+ ...response.updatedInput && typeof response.updatedInput === "object" ? { updatedInput: response.updatedInput } : {}
36
+ } : { decision: response.decision === "denied" ? "denied" : "abort" };
34
37
  pending.resolve(result);
35
38
  this.session.updateAgentState((currentState) => {
36
39
  const request = currentState.requests?.[response.id];
@@ -0,0 +1,67 @@
1
+ import { mkdirSync, renameSync, existsSync, unlinkSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { w as writePrivateFileSync, c as configuration } from './configuration-WMi4idBB.mjs';
4
+
5
+ const SESSION_MODE_DIR = "session-modes";
6
+ const ACP_PERMISSION_MODES = ["default", "acceptEdits", "plan", "bypassPermissions"];
7
+ function normalizeAcpPermissionMode(value) {
8
+ if (typeof value !== "string") return null;
9
+ if (value === "yolo") return "bypassPermissions";
10
+ return ACP_PERMISSION_MODES.includes(value) ? value : null;
11
+ }
12
+ function sessionModeFilePath(happySessionId, dir = join(configuration.happyHomeDir, SESSION_MODE_DIR)) {
13
+ return join(dir, `${happySessionId}.json`);
14
+ }
15
+ function sessionModeFilePayload(permissionMode, now = Date.now()) {
16
+ return { permissionMode, updatedAt: now };
17
+ }
18
+ function writeSessionModeFile(happySessionId, permissionMode, opts = {}) {
19
+ const path = sessionModeFilePath(happySessionId, opts.dir);
20
+ mkdirSync(join(path, ".."), { recursive: true, mode: 448 });
21
+ const payload = sessionModeFilePayload(permissionMode, opts.now);
22
+ const tmp = `${path}.${process.pid}.tmp`;
23
+ writePrivateFileSync(tmp, JSON.stringify(payload));
24
+ renameSync(tmp, path);
25
+ return payload;
26
+ }
27
+ function removeSessionModeFile(happySessionId, dir) {
28
+ const path = sessionModeFilePath(happySessionId, dir);
29
+ if (existsSync(path)) unlinkSync(path);
30
+ }
31
+
32
+ function readAcpReconnectEnv(env) {
33
+ const sessionId = env.HAPPY_RECONNECT_SESSION_ID;
34
+ const encryptionKey = env.HAPPY_RECONNECT_ENCRYPTION_KEY;
35
+ const variant = env.HAPPY_RECONNECT_ENCRYPTION_VARIANT;
36
+ if (!sessionId || !encryptionKey || variant !== "legacy" && variant !== "dataKey") return null;
37
+ const int = (value) => {
38
+ const n = parseInt(value || "0", 10);
39
+ return Number.isFinite(n) && n >= 0 ? n : 0;
40
+ };
41
+ return {
42
+ sessionId,
43
+ encryptionKey,
44
+ encryptionVariant: variant,
45
+ seq: int(env.HAPPY_RECONNECT_SEQ),
46
+ metadataVersion: int(env.HAPPY_RECONNECT_METADATA_VERSION),
47
+ agentStateVersion: int(env.HAPPY_RECONNECT_AGENT_STATE_VERSION)
48
+ };
49
+ }
50
+ function piRestartNotice(agentName, cause, started) {
51
+ const head = cause === "agent-exit" ? `${agentName} was restarted after its process exited` : `${agentName} was started again`;
52
+ if (started.resumed === "loaded") return `${head} and reopened the earlier conversation.`;
53
+ if (started.resumed === "fresh") {
54
+ const why = started.loadFailure ? ` (${oneLine(started.loadFailure)})` : "";
55
+ return `${head} but could not reopen the earlier conversation${why}; it does not remember it (the transcript here is kept).`;
56
+ }
57
+ return `${head}; it does not remember the earlier conversation (the transcript here is kept).`;
58
+ }
59
+ function oneLine(text) {
60
+ const flat = text.replace(/\s+/g, " ").trim();
61
+ return flat.length > 160 ? `${flat.slice(0, 157)}\u2026` : flat;
62
+ }
63
+ function sanitizeAgentSessionId(value) {
64
+ return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(value) ? value : null;
65
+ }
66
+
67
+ export { removeSessionModeFile as a, normalizeAcpPermissionMode as n, piRestartNotice as p, readAcpReconnectEnv as r, sanitizeAgentSessionId as s, writeSessionModeFile as w };
@@ -0,0 +1,74 @@
1
+ 'use strict';
2
+
3
+ var node_fs = require('node:fs');
4
+ var path = require('node:path');
5
+ var configuration = require('./configuration-CMHZnp6G.cjs');
6
+
7
+ const SESSION_MODE_DIR = "session-modes";
8
+ const ACP_PERMISSION_MODES = ["default", "acceptEdits", "plan", "bypassPermissions"];
9
+ function normalizeAcpPermissionMode(value) {
10
+ if (typeof value !== "string") return null;
11
+ if (value === "yolo") return "bypassPermissions";
12
+ return ACP_PERMISSION_MODES.includes(value) ? value : null;
13
+ }
14
+ function sessionModeFilePath(happySessionId, dir = path.join(configuration.configuration.happyHomeDir, SESSION_MODE_DIR)) {
15
+ return path.join(dir, `${happySessionId}.json`);
16
+ }
17
+ function sessionModeFilePayload(permissionMode, now = Date.now()) {
18
+ return { permissionMode, updatedAt: now };
19
+ }
20
+ function writeSessionModeFile(happySessionId, permissionMode, opts = {}) {
21
+ const path$1 = sessionModeFilePath(happySessionId, opts.dir);
22
+ node_fs.mkdirSync(path.join(path$1, ".."), { recursive: true, mode: 448 });
23
+ const payload = sessionModeFilePayload(permissionMode, opts.now);
24
+ const tmp = `${path$1}.${process.pid}.tmp`;
25
+ configuration.writePrivateFileSync(tmp, JSON.stringify(payload));
26
+ node_fs.renameSync(tmp, path$1);
27
+ return payload;
28
+ }
29
+ function removeSessionModeFile(happySessionId, dir) {
30
+ const path = sessionModeFilePath(happySessionId, dir);
31
+ if (node_fs.existsSync(path)) node_fs.unlinkSync(path);
32
+ }
33
+
34
+ function readAcpReconnectEnv(env) {
35
+ const sessionId = env.HAPPY_RECONNECT_SESSION_ID;
36
+ const encryptionKey = env.HAPPY_RECONNECT_ENCRYPTION_KEY;
37
+ const variant = env.HAPPY_RECONNECT_ENCRYPTION_VARIANT;
38
+ if (!sessionId || !encryptionKey || variant !== "legacy" && variant !== "dataKey") return null;
39
+ const int = (value) => {
40
+ const n = parseInt(value || "0", 10);
41
+ return Number.isFinite(n) && n >= 0 ? n : 0;
42
+ };
43
+ return {
44
+ sessionId,
45
+ encryptionKey,
46
+ encryptionVariant: variant,
47
+ seq: int(env.HAPPY_RECONNECT_SEQ),
48
+ metadataVersion: int(env.HAPPY_RECONNECT_METADATA_VERSION),
49
+ agentStateVersion: int(env.HAPPY_RECONNECT_AGENT_STATE_VERSION)
50
+ };
51
+ }
52
+ function piRestartNotice(agentName, cause, started) {
53
+ const head = cause === "agent-exit" ? `${agentName} was restarted after its process exited` : `${agentName} was started again`;
54
+ if (started.resumed === "loaded") return `${head} and reopened the earlier conversation.`;
55
+ if (started.resumed === "fresh") {
56
+ const why = started.loadFailure ? ` (${oneLine(started.loadFailure)})` : "";
57
+ return `${head} but could not reopen the earlier conversation${why}; it does not remember it (the transcript here is kept).`;
58
+ }
59
+ return `${head}; it does not remember the earlier conversation (the transcript here is kept).`;
60
+ }
61
+ function oneLine(text) {
62
+ const flat = text.replace(/\s+/g, " ").trim();
63
+ return flat.length > 160 ? `${flat.slice(0, 157)}\u2026` : flat;
64
+ }
65
+ function sanitizeAgentSessionId(value) {
66
+ return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(value) ? value : null;
67
+ }
68
+
69
+ exports.normalizeAcpPermissionMode = normalizeAcpPermissionMode;
70
+ exports.piRestartNotice = piRestartNotice;
71
+ exports.readAcpReconnectEnv = readAcpReconnectEnv;
72
+ exports.removeSessionModeFile = removeSessionModeFile;
73
+ exports.sanitizeAgentSessionId = sanitizeAgentSessionId;
74
+ exports.writeSessionModeFile = writeSessionModeFile;
@@ -2,16 +2,16 @@
2
2
 
3
3
  var chalk = require('chalk');
4
4
  var os = require('node:os');
5
- var persistence = require('./persistence-DXbKOHxl.cjs');
5
+ var persistence = require('./persistence-BegE7NPa.cjs');
6
6
  require('node:fs');
7
- require('./logger-LvwVeATU.cjs');
7
+ require('./logger-C1GWx3gi.cjs');
8
8
  var loginShellEnv = require('./loginShellEnv-BkuYtExZ.cjs');
9
9
  require('node:fs/promises');
10
- require('./configuration-DZPy0T9Z.cjs');
10
+ require('./configuration-CMHZnp6G.cjs');
11
11
  require('node:path');
12
- require('./package-Ch9WGDV_.cjs');
12
+ require('./package-SgqTYsjn.cjs');
13
13
  require('zod');
14
- require('./authRelay-BdYkC1Po.cjs');
14
+ require('./authRelay-Dy1qU9td.cjs');
15
15
  require('node:crypto');
16
16
  require('tweetnacl');
17
17
  require('node:util');
@@ -1,15 +1,15 @@
1
1
  import chalk from 'chalk';
2
2
  import { homedir } from 'node:os';
3
- import { r as readSettings, u as updateSettings } from './persistence-C_tYtOqK.mjs';
3
+ import { r as readSettings, u as updateSettings } from './persistence-Cr-wutZ4.mjs';
4
4
  import 'node:fs';
5
- import './logger-13cBr_ew.mjs';
5
+ import './logger-BtVhHnD8.mjs';
6
6
  import { d as describeAgentHome, p as probeLoginShellEnv, r as resolveAgentHomes, e as expandHomePath, A as AGENT_HOME_ENV_NAMES } from './loginShellEnv-Dw8M7tkI.mjs';
7
7
  import 'node:fs/promises';
8
- import './configuration-D55F0t16.mjs';
8
+ import './configuration-WMi4idBB.mjs';
9
9
  import 'node:path';
10
- import './package-CjlsAaRe.mjs';
10
+ import './package-BPPebGQF.mjs';
11
11
  import 'zod';
12
- import './authRelay-DSAvg1uv.mjs';
12
+ import './authRelay-DhQhkBvX.mjs';
13
13
  import 'node:crypto';
14
14
  import 'tweetnacl';
15
15
  import 'node:util';
@@ -1,23 +1,22 @@
1
1
  'use strict';
2
2
 
3
3
  var axios = require('axios');
4
- var logger = require('./logger-LvwVeATU.cjs');
5
- var lidState = require('./lidState-DxbK0qfu.cjs');
4
+ var logger = require('./logger-C1GWx3gi.cjs');
5
+ var lidState = require('./lidState-Dv2wwFTj.cjs');
6
6
  var node_events = require('node:events');
7
7
  var socket_ioClient = require('socket.io-client');
8
- var attachmentLimits = require('./attachmentLimits-DtFqqiwR.cjs');
9
- var authRelay = require('./authRelay-BdYkC1Po.cjs');
8
+ var pushNotifications = require('./pushNotifications-DaLQUyi0.cjs');
9
+ var authRelay = require('./authRelay-Dy1qU9td.cjs');
10
10
  var limits = require('./limits-C-a7gr04.cjs');
11
- var time = require('./time-Dg5tVB8S.cjs');
12
- var configuration = require('./configuration-DZPy0T9Z.cjs');
11
+ var time = require('./time-CrwIMHta.cjs');
12
+ var configuration = require('./configuration-CMHZnp6G.cjs');
13
13
  var node_crypto = require('node:crypto');
14
- var index = require('./index-De8L5lFK.cjs');
15
- var registerCommonHandlers = require('./registerCommonHandlers-60VuTkdg.cjs');
14
+ var index = require('./index-C6O2vVjm.cjs');
15
+ var registerCommonHandlers = require('./registerCommonHandlers-Cj084Sg7.cjs');
16
16
  var cuid2 = require('@paralleldrive/cuid2');
17
- var sync = require('./sync-C7sxoUYG.cjs');
17
+ var sync = require('./sync-D23jbqVa.cjs');
18
18
  var backgroundTaskActivity = require('./backgroundTaskActivity-CBvUdj39.cjs');
19
- var controlClient = require('./controlClient-SX8gSza2.cjs');
20
- var contentLogMetadata = require('./contentLogMetadata-ZSFk_NjQ.cjs');
19
+ var controlClient = require('./controlClient-C-5qCt8W.cjs');
21
20
  var chalk = require('chalk');
22
21
 
23
22
  async function hmac_sha512(key, data) {
@@ -1176,8 +1175,8 @@ class ApiSessionClient extends node_events.EventEmitter {
1176
1175
  */
1177
1176
  pendingDownloads = [];
1178
1177
  rpcHandlerManager;
1179
- agentStateLock = new attachmentLimits.AsyncLock();
1180
- metadataLock = new attachmentLimits.AsyncLock();
1178
+ agentStateLock = new pushNotifications.AsyncLock();
1179
+ metadataLock = new pushNotifications.AsyncLock();
1181
1180
  encryptionKey;
1182
1181
  encryptionVariant;
1183
1182
  reconnectInterval = null;
@@ -1502,8 +1501,8 @@ class ApiSessionClient extends node_events.EventEmitter {
1502
1501
  responseType: "arraybuffer",
1503
1502
  timeout: 6e4,
1504
1503
  maxRedirects: 5,
1505
- maxContentLength: attachmentLimits.MAX_CHAT_ATTACHMENT_ENCRYPTED_BYTES,
1506
- maxBodyLength: attachmentLimits.MAX_CHAT_ATTACHMENT_ENCRYPTED_BYTES
1504
+ maxContentLength: pushNotifications.MAX_CHAT_ATTACHMENT_ENCRYPTED_BYTES,
1505
+ maxBodyLength: pushNotifications.MAX_CHAT_ATTACHMENT_ENCRYPTED_BYTES
1507
1506
  });
1508
1507
  return new Uint8Array(response.data);
1509
1508
  }
@@ -1600,7 +1599,7 @@ class ApiSessionClient extends node_events.EventEmitter {
1600
1599
  this.noteActivity();
1601
1600
  if (sourceLocalId) this.promptQueueDrain?.onInbound(sourceLocalId);
1602
1601
  const messageWithSource = sourceLocalId && typeof message === "object" && message !== null ? { ...message, localKey: message.localKey ?? sourceLocalId } : message;
1603
- const userResult = attachmentLimits.UserMessageSchema.safeParse(messageWithSource);
1602
+ const userResult = pushNotifications.UserMessageSchema.safeParse(messageWithSource);
1604
1603
  if (userResult.success) {
1605
1604
  if (this.pendingMessageCallback) {
1606
1605
  this.pendingMessageCallback(userResult.data);
@@ -1609,7 +1608,7 @@ class ApiSessionClient extends node_events.EventEmitter {
1609
1608
  }
1610
1609
  return;
1611
1610
  }
1612
- const fileResult = attachmentLimits.FileEventMessageSchema.safeParse(message);
1611
+ const fileResult = pushNotifications.FileEventMessageSchema.safeParse(message);
1613
1612
  if (fileResult.success) {
1614
1613
  logger.logger.debug(`[API] Received file event: ${fileResult.data.content.data.ev.name} (ref: ${fileResult.data.content.data.ev.ref})`);
1615
1614
  if (this.pendingFileEventCallback) {
@@ -1958,6 +1957,17 @@ class ApiSessionClient extends node_events.EventEmitter {
1958
1957
  * own line, so a launcher sends the matching session event only when this
1959
1958
  * says the turn-end did not carry it).
1960
1959
  */
1960
+ /**
1961
+ * B-495: close the turn a fork backfill left open. History, not a live
1962
+ * turn end — so no `turn-ended` tap (board analyzer, completion hooks).
1963
+ */
1964
+ closeReplayedClaudeTurn() {
1965
+ const mapped = closeClaudeTurnWithStatus(this.claudeSessionProtocolState, "completed");
1966
+ this.claudeSessionProtocolState.currentTurnId = mapped.currentTurnId;
1967
+ for (const envelope of mapped.envelopes) {
1968
+ this.sendSessionProtocolMessage(envelope);
1969
+ }
1970
+ }
1961
1971
  closeClaudeSessionTurn(status = "completed", meta) {
1962
1972
  this.emit("turn-ended", status);
1963
1973
  const mapped = closeClaudeTurnWithStatus(this.claudeSessionProtocolState, status, meta);
@@ -2437,248 +2447,6 @@ class ApiSessionClient extends node_events.EventEmitter {
2437
2447
  }
2438
2448
  }
2439
2449
 
2440
- function getSessionTitle(metadata) {
2441
- const summaryText = metadata?.summary?.text?.trim();
2442
- if (summaryText) {
2443
- return summaryText;
2444
- }
2445
- const path = metadata?.path?.trim();
2446
- if (!path) {
2447
- return "Session";
2448
- }
2449
- const segments = path.split(/[\\/]/).filter(Boolean);
2450
- return segments[segments.length - 1] || "Session";
2451
- }
2452
- function getSessionNotificationUrl(data) {
2453
- const sessionId = data?.sessionId;
2454
- if (typeof sessionId !== "string") {
2455
- return null;
2456
- }
2457
- const trimmedSessionId = sessionId.trim();
2458
- if (!trimmedSessionId) {
2459
- return null;
2460
- }
2461
- return `/session/${encodeURIComponent(trimmedSessionId)}`;
2462
- }
2463
- function getSessionNotificationTitle(kind) {
2464
- switch (kind) {
2465
- case "done":
2466
- return "It's ready!";
2467
- case "permission":
2468
- return "Permission request";
2469
- case "question":
2470
- return "Clarification needed";
2471
- }
2472
- }
2473
- function getSessionNotificationBody(metadata) {
2474
- return getSessionTitle(metadata);
2475
- }
2476
- function getSessionNotificationCopy(kind, metadata) {
2477
- return {
2478
- title: getSessionNotificationTitle(kind),
2479
- body: getSessionNotificationBody(metadata)
2480
- };
2481
- }
2482
- class PushNotificationClient {
2483
- token;
2484
- baseUrl;
2485
- expoLoad = null;
2486
- constructor(token, baseUrl = "https://api.cluster-fluster.com") {
2487
- this.token = token;
2488
- this.baseUrl = baseUrl;
2489
- }
2490
- loadExpo() {
2491
- if (!this.expoLoad) {
2492
- const load = import('expo-server-sdk').then(({ Expo }) => ({ Expo, expo: new Expo() }));
2493
- load.catch(() => {
2494
- if (this.expoLoad === load) this.expoLoad = null;
2495
- });
2496
- this.expoLoad = load;
2497
- }
2498
- return this.expoLoad;
2499
- }
2500
- /**
2501
- * Fetch all push tokens for the authenticated user.
2502
- * Retries up to 3 times with exponential backoff on transient errors.
2503
- */
2504
- async fetchPushTokens() {
2505
- const maxAttempts = 3;
2506
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
2507
- try {
2508
- const response = await axios.get(
2509
- `${this.baseUrl}/v1/push-tokens`,
2510
- {
2511
- headers: {
2512
- "Authorization": `Bearer ${this.token}`,
2513
- "Content-Type": "application/json",
2514
- "X-Happy-Client": `cli-daemon/${configuration.configuration.currentCliVersion}`
2515
- }
2516
- }
2517
- );
2518
- logger.logger.debug(`Fetched ${response.data.tokens.length} push tokens`);
2519
- response.data.tokens.forEach((token, index) => {
2520
- logger.logger.debug(`[PUSH] Token ${index + 1}: id=${token.id}, created=${new Date(token.createdAt).toISOString()}, updated=${new Date(token.updatedAt).toISOString()}`);
2521
- });
2522
- return response.data.tokens;
2523
- } catch (error) {
2524
- logger.logger.debug(`[PUSH] [ERROR] Failed to fetch push tokens (attempt ${attempt}/${maxAttempts}):`, error);
2525
- if (attempt < maxAttempts) {
2526
- const delay = 1e3 * Math.pow(2, attempt - 1);
2527
- await new Promise((resolve) => setTimeout(resolve, delay));
2528
- }
2529
- }
2530
- }
2531
- logger.logger.debug("[PUSH] [ERROR] All push token fetch attempts failed");
2532
- return [];
2533
- }
2534
- /**
2535
- * Send push notification via Expo Push API with retry
2536
- * @param messages - Array of push messages to send
2537
- */
2538
- async sendPushNotifications(messages) {
2539
- logger.logger.debug(`Sending ${messages.length} push notifications`);
2540
- const { Expo, expo } = await this.loadExpo();
2541
- const validMessages = messages.filter((message) => {
2542
- if (Array.isArray(message.to)) {
2543
- return message.to.every((token) => Expo.isExpoPushToken(token));
2544
- }
2545
- return Expo.isExpoPushToken(message.to);
2546
- });
2547
- if (validMessages.length === 0) {
2548
- logger.logger.debug("No valid Expo push tokens found");
2549
- return;
2550
- }
2551
- const chunks = expo.chunkPushNotifications(validMessages);
2552
- for (const chunk of chunks) {
2553
- const startTime = Date.now();
2554
- const timeout = 3e5;
2555
- let attempt = 0;
2556
- while (true) {
2557
- try {
2558
- const ticketChunk = await expo.sendPushNotificationsAsync(chunk);
2559
- const errors = ticketChunk.filter((ticket) => ticket.status === "error");
2560
- if (errors.length > 0) {
2561
- const errorDetails = errors.map((e) => ({ message: e.message, details: e.details }));
2562
- logger.logger.debug("[PUSH] Some notifications failed:", errorDetails);
2563
- }
2564
- if (errors.length === ticketChunk.length) {
2565
- throw new Error("All push notifications in chunk failed");
2566
- }
2567
- break;
2568
- } catch (error) {
2569
- const elapsed = Date.now() - startTime;
2570
- if (elapsed >= timeout) {
2571
- logger.logger.debug("[PUSH] Timeout reached after 5 minutes, giving up on chunk");
2572
- break;
2573
- }
2574
- attempt++;
2575
- const delay = Math.min(1e3 * Math.pow(2, attempt), 3e4);
2576
- const remainingTime = timeout - elapsed;
2577
- const waitTime = Math.min(delay, remainingTime);
2578
- if (waitTime > 0) {
2579
- logger.logger.debug(`[PUSH] Retrying in ${waitTime}ms (attempt ${attempt})`);
2580
- await new Promise((resolve) => setTimeout(resolve, waitTime));
2581
- }
2582
- }
2583
- }
2584
- }
2585
- logger.logger.debug(`Push notifications sent successfully`);
2586
- }
2587
- /**
2588
- * Send a push notification to all registered devices for the user
2589
- * @param title - Notification title
2590
- * @param body - Notification body
2591
- * @param data - Additional data to send with the notification
2592
- */
2593
- sendToAllDevices(title, body, data) {
2594
- logger.logger.debug("[PUSH] sendToAllDevices called:", {
2595
- title: contentLogMetadata.contentLogMetadata(title),
2596
- body: contentLogMetadata.contentLogMetadata(body),
2597
- dataKeyCount: data ? Object.keys(data).length : 0
2598
- });
2599
- (async () => {
2600
- try {
2601
- logger.logger.debug("[PUSH] Fetching push tokens...");
2602
- const tokens = await this.fetchPushTokens();
2603
- logger.logger.debug(`[PUSH] Fetched ${tokens.length} push tokens`);
2604
- tokens.forEach((token, index) => {
2605
- logger.logger.debug(`[PUSH] Using token ${index + 1}: id=${token.id}`);
2606
- });
2607
- if (tokens.length === 0) {
2608
- logger.logger.debug("No push tokens found for user");
2609
- return;
2610
- }
2611
- const messages = tokens.map((token, index) => {
2612
- logger.logger.debug(`[PUSH] Creating message ${index + 1} for token`);
2613
- return {
2614
- to: token.token,
2615
- title,
2616
- body: body && body.length > 0 ? body : void 0,
2617
- data,
2618
- // TODO: For brutalist session artwork, attach rich media via a public HTTPS image URL.
2619
- // Bundled app asset paths / require(...) / local file paths will not work in push payloads.
2620
- // iOS also needs a Notification Service Extension to render richContent.image reliably.
2621
- sound: "default",
2622
- priority: "high"
2623
- };
2624
- });
2625
- logger.logger.debug(`[PUSH] Sending ${messages.length} push notifications...`);
2626
- await this.sendPushNotifications(messages);
2627
- logger.logger.debug("[PUSH] Push notifications sent successfully");
2628
- } catch (error) {
2629
- logger.logger.debug("[PUSH] Error sending to all devices:", error);
2630
- }
2631
- })();
2632
- }
2633
- /**
2634
- * Routes session-event pushes through the server so it can apply
2635
- * presence-based suppression (active desktop/web, mobile foreground).
2636
- * Falls back to direct Expo send only when sessionId is missing — that
2637
- * shouldn't happen for session notifications but guards against regressions.
2638
- */
2639
- sendSessionNotification(params) {
2640
- const { title, body } = getSessionNotificationCopy(params.kind, params.metadata);
2641
- const sessionTitle = getSessionNotificationBody(params.metadata);
2642
- const url = getSessionNotificationUrl(params.data);
2643
- const payloadData = {
2644
- ...params.data,
2645
- kind: params.kind,
2646
- sessionTitle,
2647
- ...url ? { url } : {}
2648
- };
2649
- const sessionId = typeof params.data?.sessionId === "string" ? params.data.sessionId : null;
2650
- if (!sessionId) {
2651
- logger.logger.debug("[PUSH] sendSessionNotification: missing sessionId, falling back to direct send");
2652
- this.sendToAllDevices(title, body, payloadData);
2653
- return;
2654
- }
2655
- void (async () => {
2656
- try {
2657
- await axios.post(
2658
- `${this.baseUrl}/v1/sessions/${encodeURIComponent(sessionId)}/push-event`,
2659
- {
2660
- kind: params.kind,
2661
- title,
2662
- body,
2663
- data: payloadData
2664
- },
2665
- {
2666
- headers: {
2667
- "Authorization": `Bearer ${this.token}`,
2668
- "Content-Type": "application/json",
2669
- "X-Happy-Client": `cli-daemon/${configuration.configuration.currentCliVersion}`
2670
- },
2671
- timeout: 15e3
2672
- }
2673
- );
2674
- logger.logger.debug(`[PUSH] sendSessionNotification dispatched via server (kind=${params.kind})`);
2675
- } catch (error) {
2676
- logger.logger.debug("[PUSH] sendSessionNotification failed:", error);
2677
- }
2678
- })();
2679
- }
2680
- }
2681
-
2682
2450
  function startOfflineReconnection(config) {
2683
2451
  let reconnected = false;
2684
2452
  let session = null;
@@ -2957,7 +2725,7 @@ class ApiClient {
2957
2725
  pushClient;
2958
2726
  constructor(credential) {
2959
2727
  this.credential = credential;
2960
- this.pushClient = new PushNotificationClient(credential.token, configuration.configuration.serverUrl);
2728
+ this.pushClient = new pushNotifications.PushNotificationClient(credential.token, configuration.configuration.serverUrl);
2961
2729
  }
2962
2730
  /**
2963
2731
  * Create a new session or load existing one with the given tag
@@ -3173,7 +2941,7 @@ class ApiClient {
3173
2941
  return new ApiSessionClient(this.credential.token, session, opts);
3174
2942
  }
3175
2943
  async machineSyncClient(machine) {
3176
- const { ApiMachineClient } = await Promise.resolve().then(function () { return require('./apiMachine-BYYFGgFs.cjs'); });
2944
+ const { ApiMachineClient } = await Promise.resolve().then(function () { return require('./apiMachine-G6OogT08.cjs'); });
3177
2945
  return new ApiMachineClient(this.credential.token, machine);
3178
2946
  }
3179
2947
  push() {