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.
- package/dist/{AcpBackend-B0K0WrtW.mjs → AcpBackend-CHp3y7cb.mjs} +135 -16
- package/dist/{AcpBackend-B-ny68XM.cjs → AcpBackend-DFipFF7-.cjs} +135 -16
- package/dist/{AcpSessionManager-CjdJLofq.cjs → AcpSessionManager-0zpvRJXc.cjs} +38 -4
- package/dist/{AcpSessionManager-DykjzBM4.mjs → AcpSessionManager-d2-rKWWa.mjs} +38 -4
- package/dist/{BasePermissionHandler-DR6nxuEn.cjs → BasePermissionHandler-CH3zuEkA.cjs} +5 -2
- package/dist/{BasePermissionHandler-hdY7kTqX.mjs → BasePermissionHandler-DdZBYIR4.mjs} +5 -2
- package/dist/acpSessionResume-DTGmAPLt.mjs +67 -0
- package/dist/acpSessionResume-oiCBnAVA.cjs +74 -0
- package/dist/{agentHome-BdTXEUPe.cjs → agentHome-BWcz8mz0.cjs} +5 -5
- package/dist/{agentHome-GRN2VfHv.mjs → agentHome-CghLvL_1.mjs} +5 -5
- package/dist/{api-BWX10o97.cjs → api-Cmjfr8Z7.cjs} +29 -261
- package/dist/{api-CKBViqI3.mjs → api-CzwFpJQc.mjs} +22 -254
- package/dist/{apiMachine-DttO4UFj.mjs → apiMachine-DJkTEiqy.mjs} +53 -16
- package/dist/{apiMachine-BYYFGgFs.cjs → apiMachine-G6OogT08.cjs} +53 -16
- package/dist/{attachmentContent-cPVF463_.mjs → attachmentContent-B2os4HbA.mjs} +2 -2
- package/dist/{attachmentContent-kJKXpkMX.cjs → attachmentContent-Bo0UAsSu.cjs} +4 -4
- package/dist/{auth-BmESeKuM.mjs → auth-BS6PaOOG.mjs} +6 -6
- package/dist/{auth-CTECt2Oz.cjs → auth-D6bBUwZa.cjs} +6 -6
- package/dist/{auth-CKdXb9zp.mjs → auth-DMX0xPNK.mjs} +9 -9
- package/dist/{auth-DNxVmVbn.cjs → auth-HEhRaNgL.cjs} +9 -9
- package/dist/{authRelay-DSAvg1uv.mjs → authRelay-DhQhkBvX.mjs} +1 -1
- package/dist/{authRelay-BdYkC1Po.cjs → authRelay-Dy1qU9td.cjs} +1 -0
- package/dist/{auto-D1ypjjfx.cjs → auto-C6I55iOh.cjs} +19 -18
- package/dist/{auto-Ch3203qd.mjs → auto-Cl1SEDcD.mjs} +19 -18
- package/dist/{bootstrap-6OI698q9.cjs → bootstrap-exVucYav.cjs} +2 -2
- package/dist/{bootstrap-C0s2bPFQ.mjs → bootstrap-iuyufnp3.mjs} +2 -2
- package/dist/{browser-DG6Uof5O.cjs → browser-BohJK12g.cjs} +1 -1
- package/dist/{browser-BlLWZUMx.mjs → browser-CSYum7xH.mjs} +1 -1
- package/dist/{claudeLocal-CcWcKnoo.mjs → claudeLocal-Dq_R3Ax_.mjs} +6 -5
- package/dist/{claudeLocal-CemsIArT.cjs → claudeLocal-re4yjSTx.cjs} +6 -5
- package/dist/{claudeLocalLauncher-A4VuevIi.cjs → claudeLocalLauncher-B4hJHpCA.cjs} +11 -10
- package/dist/{claudeLocalLauncher-7p6y88nj.mjs → claudeLocalLauncher-CN67lN7-.mjs} +11 -10
- package/dist/{claudeSessionFork-BtROOjqf.mjs → claudeSessionFork-BihfD0Ik.mjs} +1 -1
- package/dist/{claudeSessionFork-CbDfm8Fz.cjs → claudeSessionFork-DiSMYerV.cjs} +1 -1
- package/dist/{client-DyvBTYee.cjs → client-BKcK1Bi-.cjs} +3 -3
- package/dist/client-BhoEBnuN.mjs +71 -0
- package/dist/{client-COmgDDy0.cjs → client-CuVdN6PP.cjs} +2 -2
- package/dist/{client-BPMWutfs.mjs → client-DuTDwWSQ.mjs} +3 -3
- package/dist/client-ZjOsn6nZ.cjs +76 -0
- package/dist/{client-DG5ndWLw.mjs → client-wo9nbxuf.mjs} +2 -2
- package/dist/codex/happyMcpStdioBridge.cjs +25 -16
- package/dist/codex/happyMcpStdioBridge.mjs +25 -16
- package/dist/{codexAppServerClient-D-Z8qSfI.mjs → codexAppServerClient-BK3zra_1.mjs} +3 -3
- package/dist/{codexAppServerClient-R24WZZfg.cjs → codexAppServerClient-Dt5zxrun.cjs} +3 -3
- package/dist/{codexCommand-CVTkZJ1o.mjs → codexCommand-B6pY7CMh.mjs} +66 -61
- package/dist/{codexCommand-6hW19gsq.cjs → codexCommand-CAZ1SLjg.cjs} +89 -84
- package/dist/{codexTermination-CCIfwzcx.mjs → codexTermination-Cd1Eon_4.mjs} +1 -1
- package/dist/{codexTermination-BBU7e92y.cjs → codexTermination-DmGbHxcD.cjs} +1 -1
- package/dist/{config-CvsNChKX.mjs → config-2oMG_fEI.mjs} +3 -3
- package/dist/{config-DhdrvOLV.cjs → config-B0uK6K7n.cjs} +3 -3
- package/dist/{configuration-DZPy0T9Z.cjs → configuration-CMHZnp6G.cjs} +1 -1
- package/dist/{configuration-D55F0t16.mjs → configuration-WMi4idBB.mjs} +1 -1
- package/dist/{connect-CwCXMRmD.mjs → connect-BLVHhHzA.mjs} +15 -15
- package/dist/{connect-Wz-XZYXW.cjs → connect-uaglGrde.cjs} +15 -15
- package/dist/{context-BKbrZ55r.cjs → context-DXzU5bFM.cjs} +1 -1
- package/dist/{context-CCRpVXFo.mjs → context-DploEcoN.mjs} +1 -1
- package/dist/{controlClient-C4xB5J6O.mjs → controlClient-BWUJrj3t.mjs} +3 -3
- package/dist/{controlClient-SX8gSza2.cjs → controlClient-C-5qCt8W.cjs} +3 -3
- package/dist/{createSessionMetadata-Bi-m0Y_O.mjs → createSessionMetadata-3uXrJgOW.mjs} +2 -2
- package/dist/{createSessionMetadata-BCFmYlBo.cjs → createSessionMetadata-BkIzHALd.cjs} +2 -2
- package/dist/{defaultPermissionMode-wBcbBezm.mjs → defaultPermissionMode-BzxLh20a.mjs} +2 -2
- package/dist/{defaultPermissionMode-DMBEnXll.cjs → defaultPermissionMode-pS3vmiSg.cjs} +2 -2
- package/dist/{deterministicJson-ChGfQEF6.cjs → deterministicJson-B8z2GPi9.cjs} +220 -14
- package/dist/{deterministicJson-BkQETt8_.mjs → deterministicJson-D_whDMFd.mjs} +217 -12
- package/dist/{doctor-BsN3JZJn.cjs → doctor-Br1Kcy2J.cjs} +8 -8
- package/dist/{doctor-B9c2C9dF.mjs → doctor-CmtSsR2-.mjs} +8 -8
- package/dist/{downloadTarget-Dj3WoVJa.cjs → downloadTarget-BQJK_6oH.cjs} +6 -6
- package/dist/{downloadTarget-ByXzbDK4.mjs → downloadTarget-BoNwTIH_.mjs} +6 -6
- package/dist/{ensureDaemonRunning-7Wb8M7Lv.cjs → ensureDaemonRunning-BRUmsq6J.cjs} +5 -5
- package/dist/{ensureDaemonRunning--HYzs5Ce.mjs → ensureDaemonRunning-Czo9IHJQ.mjs} +5 -5
- package/dist/{handleResumeCommand-DHddBkNJ.mjs → handleResumeCommand-C8thKjqf.mjs} +22 -6
- package/dist/{handleResumeCommand-OmuUGYjQ.cjs → handleResumeCommand-tKD_Hpxc.cjs} +22 -6
- package/dist/{index-CrR4JISa.cjs → index-B0UjHlAe.cjs} +5 -5
- package/dist/{index-BzJNDsJq.mjs → index-BTxHphpV.mjs} +254 -49
- package/dist/index-BiyC7cZ3.mjs +18 -0
- package/dist/{index-De8L5lFK.cjs → index-C6O2vVjm.cjs} +156 -34
- package/dist/index-CUuc6iCn.cjs +24 -0
- package/dist/{index-Dhl6_bw7.mjs → index-CdQI0C9p.mjs} +5 -5
- package/dist/{index-D9NoYc5I.cjs → index-D09T1m8Y.cjs} +3 -3
- package/dist/{index-CEm0MYiS.mjs → index-D3bidoG8.mjs} +3 -3
- package/dist/{index-BRJzH4sc.cjs → index-DMqDMT1Q.cjs} +257 -52
- package/dist/{index-DMy3OCBe.mjs → index-DPOa4NhL.mjs} +154 -35
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/dist/{install-BdvKiOQw.mjs → install-BX3lv3NO.mjs} +1 -1
- package/dist/{install-Cf6AFSWC.cjs → install-BXvf2E3o.cjs} +1 -1
- package/dist/{install-1qn-D9FS.cjs → install-CYRZxS87.cjs} +3 -3
- package/dist/{install-BDIUtPXi.mjs → install-hnve_9vq.mjs} +3 -3
- package/dist/lib.cjs +14 -14
- package/dist/lib.d.cts +65 -1
- package/dist/lib.d.mts +65 -1
- package/dist/lib.mjs +14 -14
- package/dist/{lidState-BqVsw7H1.mjs → lidState-Bb8fgXg3.mjs} +2 -2
- package/dist/{lidState-DxbK0qfu.cjs → lidState-Dv2wwFTj.cjs} +2 -2
- package/dist/{localHappyAgentAuth-D5tANdRD.cjs → localHappyAgentAuth-DjYvkXvV.cjs} +2 -2
- package/dist/{localHappyAgentAuth-Ce8kO2yc.mjs → localHappyAgentAuth-NEU7fax7.mjs} +2 -2
- package/dist/{logger-13cBr_ew.mjs → logger-BtVhHnD8.mjs} +2 -2
- package/dist/{logger-LvwVeATU.cjs → logger-C1GWx3gi.cjs} +2 -2
- package/dist/{machineMetadata-29h7vgf4.cjs → machineMetadata-CLHS9sv_.cjs} +3 -3
- package/dist/{machineMetadata-dMida2qq.mjs → machineMetadata-D-g--oU_.mjs} +3 -3
- package/dist/{main-x4nAhdH5.mjs → main-B2LWV8DI.mjs} +59 -46
- package/dist/{main-DpM5jaFH.cjs → main-CWhSsbtU.cjs} +59 -46
- package/dist/{mcp-DQv3caXs.cjs → mcp-CARUsXHV.cjs} +15 -15
- package/dist/{mcp-DMiFGYMT.mjs → mcp-ext92q3Y.mjs} +15 -15
- package/dist/{mirrorProtocol-Bz8tEabR.mjs → mirrorProtocol-BwYibqry.mjs} +3 -3
- package/dist/{mirrorProtocol-BfrERW7Z.cjs → mirrorProtocol-DEy2g1CB.cjs} +3 -3
- package/dist/{package-CjlsAaRe.mjs → package-BPPebGQF.mjs} +7 -7
- package/dist/{package-Ch9WGDV_.cjs → package-SgqTYsjn.cjs} +7 -7
- package/dist/panels-BZ0_Tt7B.mjs +137 -0
- package/dist/panels-D1c7q2dD.cjs +142 -0
- package/dist/{peerTools-CxmrKnfV.mjs → peerTools-CWKzcQ7u.mjs} +60 -10
- package/dist/{peerTools-DtGKWli5.cjs → peerTools-DRQETXaz.cjs} +60 -9
- package/dist/{persistence-DXbKOHxl.cjs → persistence-BegE7NPa.cjs} +14 -3
- package/dist/{persistence-C_tYtOqK.mjs → persistence-Cr-wutZ4.mjs} +14 -4
- package/dist/{piRunnerArgs-BVRZe2AR.cjs → piRunnerArgs-Cs-378Vz.cjs} +8 -2
- package/dist/{piRunnerArgs-BpHc-JZl.mjs → piRunnerArgs-DwvM_yWA.mjs} +7 -1
- package/dist/{piRuntime-D7eio8Ix.cjs → piRuntime-BG-1td_n.cjs} +2 -2
- package/dist/{piRuntime-DOdGF395.mjs → piRuntime-Bue5mnlc.mjs} +2 -2
- package/dist/{piTerminal-dpxz4Q8D.mjs → piTerminal-B5x9X5yV.mjs} +18 -18
- package/dist/{piTerminal-y_PRo2NY.cjs → piTerminal-G4z-xVyy.cjs} +18 -18
- package/dist/processTreeSnapshot-CuLJDNC-.mjs +101 -0
- package/dist/processTreeSnapshot-mDbnuojn.cjs +105 -0
- package/dist/prompt-BOouDaTM.mjs +99 -0
- package/dist/prompt-lgF9IE82.cjs +105 -0
- package/dist/{attachmentLimits-Di1Z93lN.mjs → pushNotifications-BdFjDjQe.mjs} +303 -3
- package/dist/{attachmentLimits-DtFqqiwR.cjs → pushNotifications-DaLQUyi0.cjs} +304 -2
- package/dist/{index-DFPT4HOO.cjs → query-Ctfg-5gy.cjs} +25 -5
- package/dist/{index-CEjJnq05.mjs → query-DYP_W1wp.mjs} +26 -3
- package/dist/{rateLimitWindows-DYHDGuzQ.mjs → rateLimitWindows-CuEqk_0g.mjs} +1 -1
- package/dist/{rateLimitWindows-DFnMU2Vt.cjs → rateLimitWindows-Dj_8voBK.cjs} +1 -1
- package/dist/{registerCommonHandlers-D8OMpBbQ.mjs → registerCommonHandlers-BAlP7SGc.mjs} +2 -2
- package/dist/{registerCommonHandlers-60VuTkdg.cjs → registerCommonHandlers-Cj084Sg7.cjs} +2 -2
- package/dist/{registerKillSessionHandler-Drhf7-Vz.mjs → registerKillSessionHandler-PD0jWtQo.mjs} +6 -6
- package/dist/{registerKillSessionHandler-pqChBKwO.cjs → registerKillSessionHandler-qMju0ZfF.cjs} +6 -6
- package/dist/{remoteSessionClient-B7NvjHD3.cjs → remoteSessionClient-B7i7MkYV.cjs} +5 -5
- package/dist/{remoteSessionClient-D01Hso2-.mjs → remoteSessionClient-Bn2qu5C5.mjs} +5 -5
- package/dist/{reportProgressTool-Du_zAK4h.cjs → reportProgressTool-CM1JFAHg.cjs} +84 -2
- package/dist/{reportProgressTool-B203EZCR.mjs → reportProgressTool-gHItlSzz.mjs} +82 -3
- package/dist/{resources-JDPugcDq.cjs → resources-CvIlkzpP.cjs} +30 -0
- package/dist/{resources-BdFBQi8r.mjs → resources-y9jfyO-_.mjs} +30 -0
- package/dist/{run-DX4Zs3Ug.mjs → run-BM4TxiyN.mjs} +249 -45
- package/dist/{run-DZ5jU53c.cjs → run-CNXwIe0A.cjs} +263 -59
- package/dist/{runClaude-ClRhHpwR.cjs → runClaude-CWhj2V4Q.cjs} +37 -41
- package/dist/{runClaude-CgPHXP0L.mjs → runClaude-C_3I8hvR.mjs} +37 -41
- package/dist/{runClaudeDeps-D2v_WDSL.cjs → runClaudeDeps-B81cOKnH.cjs} +295 -157
- package/dist/{runClaudeDeps-Dz2iydq4.mjs → runClaudeDeps-QGrOeDe2.mjs} +295 -160
- package/dist/{runGemini-DBXxpoY8.mjs → runGemini-BEdWEZLR.mjs} +61 -55
- package/dist/{runGemini-BtZqGFkp.cjs → runGemini-CgRLYbt5.cjs} +61 -55
- package/dist/{runOpenClaw-D8q8G57u.cjs → runOpenClaw-C1NVmzOL.cjs} +19 -19
- package/dist/{runOpenClaw-BOHpzCEU.mjs → runOpenClaw-DdQZAYj1.mjs} +19 -19
- package/dist/{sandbox-C452Vrsc.mjs → sandbox-DjQUdCMG.mjs} +5 -5
- package/dist/{sandbox-Cu9mMzjx.cjs → sandbox-nocIjliq.cjs} +5 -5
- package/dist/selfCheck-CjCF4C3v.mjs +85 -0
- package/dist/{selfCheck-gKa3uVr1.cjs → selfCheck-DCt4Uzbq.cjs} +36 -35
- package/dist/{send-B8HARi7x.mjs → send-Ct7X4pPU.mjs} +9 -9
- package/dist/{send-2Vb5eppI.cjs → send-Dydf_hwZ.cjs} +9 -9
- package/dist/{server-Db9Wuam3.cjs → server-CosABFbd.cjs} +7 -7
- package/dist/{server-BBWCIZyS.mjs → server-DTQGZMxh.mjs} +5 -5
- package/dist/{sessionLock-6qL_N6Rn.cjs → sessionLock-DokGab2R.cjs} +16 -3
- package/dist/{sessionLock-ZfvFVdUi.mjs → sessionLock-WYIyaVO4.mjs} +16 -4
- package/dist/{sessionOps-CdgbEJgf.mjs → sessionOps-BIGgRube.mjs} +11 -6
- package/dist/{sessionOps-Dmt7WUUs.cjs → sessionOps-S-qPBLFf.cjs} +11 -6
- package/dist/{sessionScanner-CQL_WSaC.cjs → sessionScanner-CIMM2hvZ.cjs} +3 -3
- package/dist/{sessionScanner-CNVaSNOn.mjs → sessionScanner-o5hnMi5e.mjs} +3 -3
- package/dist/{sessions-DTomHfFg.mjs → sessions-BJHEZpi2.mjs} +40 -18
- package/dist/{sessions-BJblG_Hx.cjs → sessions-JchI1w3z.cjs} +40 -17
- package/dist/{setupOfflineReconnection-DVA0VpQL.cjs → setupOfflineReconnection-CNiAt5ZP.cjs} +2 -2
- package/dist/{setupOfflineReconnection-C5trsV-j.mjs → setupOfflineReconnection-DMiBO2y9.mjs} +2 -2
- package/dist/{spawn-DRyNAqD8.cjs → spawn-6PD7nnoC.cjs} +49 -18
- package/dist/{spawn-CQJFgoOq.mjs → spawn-DgvUNYEo.mjs} +49 -18
- package/dist/{spawnAgents-CCjJifAW.cjs → spawnAgents-DsXgegHM.cjs} +37 -1
- package/dist/spawnAgents-P006Hqio.mjs +79 -0
- package/dist/{spawnHappyCLI-B_0RWxD4.mjs → spawnHappyCLI-CCOrEtf9.mjs} +1 -1
- package/dist/{spawnHappyCLI-ChniczJ5.cjs → spawnHappyCLI-Dywezwk6.cjs} +1 -1
- package/dist/{specialCommands-DkdFJi4N.mjs → specialCommands-DPcd9edP.mjs} +3 -3
- package/dist/{specialCommands-DbntVs0d.cjs → specialCommands-QxPpkGKf.cjs} +3 -3
- package/dist/{startFileWatcher-UQyTSRAP.mjs → startFileWatcher-DghDOCO4.mjs} +1 -1
- package/dist/{startFileWatcher-C292fhra.cjs → startFileWatcher-RECH5qY8.cjs} +1 -1
- package/dist/{streamRelay-_qCd873P.mjs → streamRelay-DMV_TXfS.mjs} +1 -1
- package/dist/{streamRelay-Cx01enfe.cjs → streamRelay-DlUWKUpo.cjs} +1 -1
- package/dist/{sync-C3p7-KLn.mjs → sync-CSe0Rf45.mjs} +1 -1
- package/dist/{sync-C7sxoUYG.cjs → sync-D23jbqVa.cjs} +1 -1
- package/dist/{systemPrompt-DtibzbRU.cjs → systemPrompt-BOy4kU4P.cjs} +4 -3
- package/dist/{systemPrompt-CdHOlyVW.mjs → systemPrompt-CFNKnh65.mjs} +4 -3
- package/dist/{teams-ujXr3AFn.mjs → teams-DyY669f0.mjs} +9 -9
- package/dist/{teams-D7O7TpVU.cjs → teams-Ov2BDT-A.cjs} +9 -9
- package/dist/{time-yEL6wHUF.mjs → time-65DcU6Jx.mjs} +1 -1
- package/dist/{time-Dg5tVB8S.cjs → time-CrwIMHta.cjs} +1 -1
- package/dist/{titleGenerator-BMEaDTwU.cjs → titleGenerator-CS_rh2_J.cjs} +9 -8
- package/dist/{titleGenerator-Dr-BtjzO.mjs → titleGenerator-CiAMxf7s.mjs} +9 -8
- package/dist/{todo-CvJe4M2C.mjs → todo-BDONw0sK.mjs} +7 -7
- package/dist/{todo-CUcFamGs.cjs → todo-KY-okGii.cjs} +7 -7
- package/dist/{tools-BrM3bZW5.mjs → tools-D8-PnZEG.mjs} +1 -1
- package/dist/{tools-DDKTB5aQ.cjs → tools-_w52DZG6.cjs} +1 -1
- package/dist/{uninstall-7oLuhYIu.cjs → uninstall-8vnLN-IE.cjs} +3 -3
- package/dist/{uninstall-CEcMMQGz.mjs → uninstall-_fjGRP9b.mjs} +3 -3
- package/dist/webPanels-B2_C2-3g.mjs +49 -0
- package/dist/webPanels-FCgFKvVe.cjs +53 -0
- package/package.json +7 -7
- package/dist/selfCheck-BAvqBwBR.mjs +0 -84
- package/dist/sessionModeFile-CWVq8AT9.mjs +0 -32
- package/dist/sessionModeFile-CsLtn_PL.cjs +0 -36
- package/dist/spawnAgents-BjtmjBvP.mjs +0 -45
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createId } from '@paralleldrive/cuid2';
|
|
2
|
-
import { s as streamKeyOf,
|
|
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
|
-
|
|
182
|
-
|
|
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-
|
|
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 ? {
|
|
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-
|
|
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 ? {
|
|
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-
|
|
5
|
+
var persistence = require('./persistence-BegE7NPa.cjs');
|
|
6
6
|
require('node:fs');
|
|
7
|
-
require('./logger-
|
|
7
|
+
require('./logger-C1GWx3gi.cjs');
|
|
8
8
|
var loginShellEnv = require('./loginShellEnv-BkuYtExZ.cjs');
|
|
9
9
|
require('node:fs/promises');
|
|
10
|
-
require('./configuration-
|
|
10
|
+
require('./configuration-CMHZnp6G.cjs');
|
|
11
11
|
require('node:path');
|
|
12
|
-
require('./package-
|
|
12
|
+
require('./package-SgqTYsjn.cjs');
|
|
13
13
|
require('zod');
|
|
14
|
-
require('./authRelay-
|
|
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-
|
|
3
|
+
import { r as readSettings, u as updateSettings } from './persistence-Cr-wutZ4.mjs';
|
|
4
4
|
import 'node:fs';
|
|
5
|
-
import './logger-
|
|
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-
|
|
8
|
+
import './configuration-WMi4idBB.mjs';
|
|
9
9
|
import 'node:path';
|
|
10
|
-
import './package-
|
|
10
|
+
import './package-BPPebGQF.mjs';
|
|
11
11
|
import 'zod';
|
|
12
|
-
import './authRelay-
|
|
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-
|
|
5
|
-
var lidState = require('./lidState-
|
|
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
|
|
9
|
-
var authRelay = require('./authRelay-
|
|
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-
|
|
12
|
-
var configuration = require('./configuration-
|
|
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-
|
|
15
|
-
var registerCommonHandlers = require('./registerCommonHandlers-
|
|
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-
|
|
17
|
+
var sync = require('./sync-D23jbqVa.cjs');
|
|
18
18
|
var backgroundTaskActivity = require('./backgroundTaskActivity-CBvUdj39.cjs');
|
|
19
|
-
var controlClient = require('./controlClient-
|
|
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
|
|
1180
|
-
metadataLock = new
|
|
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:
|
|
1506
|
-
maxBodyLength:
|
|
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 =
|
|
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 =
|
|
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-
|
|
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() {
|