very-happy-cli 0.2.159 → 0.2.160
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-DUYFlyfN.cjs → AcpBackend-Bm2rdke8.cjs} +78 -76
- package/dist/{AcpBackend-VsfkZiVF.mjs → AcpBackend-mzv8Dhba.mjs} +4 -2
- package/dist/{AcpSessionManager-Bdv8LWXh.cjs → AcpSessionManager-BAY1Pggx.cjs} +9 -9
- package/dist/{AcpSessionManager-rYtVb0kN.mjs → AcpSessionManager-CoMWFVw3.mjs} +1 -1
- package/dist/BasePermissionHandler-CFHAxumV.cjs +157 -0
- package/dist/BasePermissionHandler-m3WVholL.mjs +155 -0
- package/dist/BaseReasoningProcessor-BFa9_rZA.cjs +200 -0
- package/dist/BaseReasoningProcessor-CYrKBXGm.mjs +198 -0
- package/dist/RemoteModeDisplay-D-HewyXg.mjs +150 -0
- package/dist/RemoteModeDisplay-NC1gPHtj.cjs +153 -0
- package/dist/agentAttachments-Dbw8iMCZ.cjs +20 -0
- package/dist/agentAttachments-M_B5qEF2.mjs +18 -0
- package/dist/agentGuidance-B5NATuFa.cjs +28 -0
- package/dist/agentGuidance-CQuNlNx8.mjs +20 -0
- package/dist/{agentHome-CHh4lmjM.cjs → agentHome-CboCeKWq.cjs} +14 -28
- package/dist/{agentHome-CvsJyeQB.mjs → agentHome-Dj1C43aJ.mjs} +8 -22
- package/dist/api-CLMUr-SX.mjs +3339 -0
- package/dist/api-CgundNNX.cjs +3346 -0
- package/dist/{types-Dh-s4Lqs.mjs → apiMachine-B9dLW_p5.mjs} +9116 -16205
- package/dist/{types-BbvK1Tr_.cjs → apiMachine-Bn8482VM.cjs} +9104 -16247
- package/dist/assistantTools-BTqPnlFl.cjs +380 -0
- package/dist/assistantTools-D6tuc6o4.mjs +376 -0
- package/dist/attachmentContent-DpiTJZb4.cjs +88 -0
- package/dist/attachmentContent-_kxRznNf.mjs +82 -0
- package/dist/attachmentLimits-CzVrqgLR.cjs +354 -0
- package/dist/attachmentLimits-yba1uHFO.mjs +348 -0
- package/dist/auth-BDOVh5h5.cjs +220 -0
- package/dist/auth-Cwutmdsa.mjs +225 -0
- package/dist/auth-PYHZQNPp.mjs +218 -0
- package/dist/auth-ba4WMYrN.cjs +227 -0
- package/dist/authRelay-BdYkC1Po.cjs +156 -0
- package/dist/authRelay-DSAvg1uv.mjs +143 -0
- package/dist/{auto-DKmEls8Z.cjs → auto-BOX_fgmR.cjs} +70 -79
- package/dist/{auto-nb8GhRRy.mjs → auto-BXu14yP_.mjs} +27 -36
- package/dist/backgroundTaskActivity-8PdPxrvy.mjs +149 -0
- package/dist/backgroundTaskActivity-CBvUdj39.cjs +157 -0
- package/dist/bootstrap-B5G1TijC.cjs +116 -0
- package/dist/bootstrap-hxXPCFMx.mjs +112 -0
- package/dist/browser-Y6Bl8L_O.cjs +22 -0
- package/dist/browser-jh2P0UVZ.mjs +20 -0
- package/dist/claudeCliPath-BqkaH2oR.mjs +8 -0
- package/dist/claudeCliPath-U4HHmV4r.cjs +10 -0
- package/dist/claudeLocal-BaY4fZKi.mjs +339 -0
- package/dist/claudeLocal-CRGG4Pea.cjs +343 -0
- package/dist/claudeLocalLauncher-D4T7MTqd.mjs +152 -0
- package/dist/claudeLocalLauncher-DyEbVzUN.cjs +154 -0
- package/dist/cliUpdate-DsKXPFYp.cjs +120 -0
- package/dist/cliUpdate-Y34VGe9Y.mjs +112 -0
- package/dist/client-3Ac-O4pw.cjs +104 -0
- package/dist/client-BPNbmtvO.cjs +119 -0
- package/dist/client-CeGKqqcJ.mjs +100 -0
- package/dist/client-ClR0K8zX.mjs +112 -0
- package/dist/codex/happyMcpStdioBridge.cjs +33 -14
- package/dist/codex/happyMcpStdioBridge.mjs +26 -7
- package/dist/codexAppServerClient-I3teiV-N.mjs +1088 -0
- package/dist/codexAppServerClient-q2FjnRcK.cjs +1090 -0
- package/dist/codexCommand-4zcccIoq.cjs +2088 -0
- package/dist/codexCommand-Cc9gcbdX.mjs +2086 -0
- package/dist/codexThreadFork-BH9IZPqD.cjs +350 -0
- package/dist/codexThreadFork-slzAseLx.mjs +338 -0
- package/dist/{config-ClLtM6F3.mjs → config-CTx_jb-C.mjs} +7 -40
- package/dist/{config-DLx-vW3I.cjs → config-Ci9Kpgwa.cjs} +26 -59
- package/dist/configuration-BSYpcPwE.cjs +181 -0
- package/dist/configuration-RfeNjFmd.mjs +170 -0
- package/dist/connect-BpOdzNbE.mjs +682 -0
- package/dist/connect-C2CiOUFs.cjs +684 -0
- package/dist/constants-BC4St0xd.mjs +11 -0
- package/dist/constants-VJ0N6WuG.cjs +17 -0
- package/dist/contentLogMetadata-BlWI0egu.mjs +51 -0
- package/dist/contentLogMetadata-ZSFk_NjQ.cjs +54 -0
- package/dist/context-DsDr6E2t.cjs +69 -0
- package/dist/context-H0Bcb9S_.mjs +65 -0
- package/dist/controlClient-BGbDcgWS.mjs +260 -0
- package/dist/controlClient-Bcwv3D21.cjs +279 -0
- package/dist/createSessionMetadata-BJxEnM-o.cjs +58 -0
- package/dist/createSessionMetadata-CVVkGjxV.mjs +54 -0
- package/dist/defaultPermissionMode-BnxJPVHT.mjs +4 -0
- package/dist/defaultPermissionMode-CxmTXUQR.cjs +7 -0
- package/dist/detectCLI-CSGMlV51.mjs +58 -0
- package/dist/detectCLI-DR9ZaN6B.cjs +61 -0
- package/dist/deterministicJson-C5CYTVpm.cjs +507 -0
- package/dist/deterministicJson-CzkFJWw1.mjs +502 -0
- package/dist/doctor-BPkYWSuq.mjs +75 -0
- package/dist/doctor-D2YJ-Yn2.cjs +395 -0
- package/dist/doctor-DOvByjbk.mjs +391 -0
- package/dist/doctor-u46qYYKX.cjs +79 -0
- package/dist/doctorReadiness-BCZGcN0a.cjs +151 -0
- package/dist/doctorReadiness-C208SMN9.mjs +142 -0
- package/dist/editPaths-BVfS_FFL.mjs +68 -0
- package/dist/editPaths-Bqp4OFPw.cjs +73 -0
- package/dist/ensureDaemonRunning-BCwNrMyv.cjs +64 -0
- package/dist/ensureDaemonRunning-Dqa2pOjY.mjs +61 -0
- package/dist/handleResumeCommand-BvXYf5El.mjs +240 -0
- package/dist/handleResumeCommand-C2cKchpX.cjs +245 -0
- package/dist/ids-B6ZC0HGt.cjs +13 -0
- package/dist/ids-DU6sLx4C.mjs +10 -0
- package/dist/index-B6UGRQ7h.mjs +102 -0
- package/dist/{index-BEOMECtE.cjs → index-B6pAdvJx.cjs} +121 -91
- package/dist/index-Bu5Zi_a9.cjs +182 -0
- package/dist/index-D3kI0hDR.cjs +107 -0
- package/dist/index-DA7yINuk.cjs +994 -0
- package/dist/index-DDeHXrIX.cjs +71 -0
- package/dist/index-DKLU_fD0.mjs +158 -0
- package/dist/{index-2mCaeKyf.mjs → index-DMZqWwsP.mjs} +68 -38
- package/dist/index-DVkMGPyS.mjs +68 -0
- package/dist/index-qdS1friN.mjs +949 -0
- package/dist/index.cjs +5 -46
- package/dist/index.mjs +5 -46
- package/dist/{install-BPhJppvd.mjs → install-BO_W7VhL.mjs} +37 -37
- package/dist/install-BgoC2e_2.cjs +88 -0
- package/dist/install-CFY3tYtJ.mjs +86 -0
- package/dist/{install-BOHrUaFM.cjs → install-Cs5qAPrB.cjs} +38 -38
- package/dist/{installPiTools-DuZ6jZvX.cjs → installPiTools-BKnXjrVu.cjs} +2 -3
- package/dist/{installPiTools-Cj7yU9Fc.mjs → installPiTools-B_CdM5_2.mjs} +1 -2
- package/dist/{installTerminalHooks-Cou3WUf3.cjs → installTerminalHooks-BQZbvxsZ.cjs} +5 -40
- package/dist/{installTerminalHooks-WeznjkuC.mjs → installTerminalHooks-By7gBMEF.mjs} +3 -38
- package/dist/lib.cjs +28 -19
- package/dist/lib.d.cts +12 -2
- package/dist/lib.d.mts +12 -2
- package/dist/lib.mjs +23 -14
- package/dist/lidState-BeDfxxEX.cjs +305 -0
- package/dist/lidState-CeEt442o.mjs +297 -0
- package/dist/limits-C-a7gr04.cjs +43 -0
- package/dist/limits-DIo7rEBR.mjs +36 -0
- package/dist/localHappyAgentAuth-C-HQyiv6.mjs +82 -0
- package/dist/localHappyAgentAuth-D6rFhaoc.cjs +86 -0
- package/dist/logger-6HYUEXNk.mjs +271 -0
- package/dist/logger-CS0mw3fa.cjs +275 -0
- package/dist/loginShellEnv-BkuYtExZ.cjs +182 -0
- package/dist/loginShellEnv-Dw8M7tkI.mjs +167 -0
- package/dist/machineMetadata-DyDbODYd.cjs +41 -0
- package/dist/machineMetadata-oOzBfDfs.mjs +38 -0
- package/dist/main-BkxJP6JQ.cjs +941 -0
- package/dist/main-BwNIAI1A.mjs +939 -0
- package/dist/manager-BQ4flvQZ.mjs +101 -0
- package/dist/manager-Cly8xVIR.cjs +105 -0
- package/dist/{mcp-Dy3f_K0h.mjs → mcp-B1A4I3TK.mjs} +27 -33
- package/dist/{mcp-CPYbtsYG.cjs → mcp-Hszd7qpS.cjs} +42 -48
- package/dist/messageBuffer-BWlGgR3A.mjs +71 -0
- package/dist/messageBuffer-fJMH6uY8.cjs +73 -0
- package/dist/mirrorProtocol-BNLtoWjO.mjs +170 -0
- package/dist/mirrorProtocol-BUtmg1ws.cjs +186 -0
- package/dist/oneShotPrompts-CL0dip9C.cjs +16 -0
- package/dist/oneShotPrompts-DT4p6RNd.mjs +12 -0
- package/dist/package-BhaKlnxz.mjs +171 -0
- package/dist/package-BwMrPwqH.cjs +173 -0
- package/dist/path-B7zW-WwE.cjs +18 -0
- package/dist/path-D2wdaNSk.mjs +15 -0
- package/dist/peerTools-BTqw97Gb.mjs +272 -0
- package/dist/peerTools-BvKtHXj8.cjs +283 -0
- package/dist/permissionMode-Cr5JCbB7.mjs +80 -0
- package/dist/permissionMode-CrV-XuMs.cjs +87 -0
- package/dist/persistence-HGW_ZVs9.mjs +372 -0
- package/dist/persistence-yKTH3-5X.cjs +414 -0
- package/dist/piExtension.mjs +2 -1
- package/dist/piRunnerArgs-BNloJCCg.cjs +66 -0
- package/dist/piRunnerArgs-BuX1UFWy.mjs +59 -0
- package/dist/{piRuntime-kLZNpAAl.mjs → piRuntime-CSGkwCKQ.mjs} +2 -2
- package/dist/{piRuntime-NtF0YqjH.cjs → piRuntime-C_H7MJCM.cjs} +4 -4
- package/dist/{piTerminal-B0fEOV_2.mjs → piTerminal-C8a1OrNQ.mjs} +32 -35
- package/dist/{piTerminal-9J0GAKzb.cjs → piTerminal-DNCZ6yTM.cjs} +32 -35
- package/dist/previewPath-B0rBdhy1.cjs +83 -0
- package/dist/previewPath-CXN4Vag0.mjs +81 -0
- package/dist/projectPath-BTBIMB57.mjs +10 -0
- package/dist/projectPath-ChLhdOyt.cjs +13 -0
- package/dist/registerCommonHandlers-Ccvsz7Ou.mjs +536 -0
- package/dist/registerCommonHandlers-DskirN-_.cjs +538 -0
- package/dist/registerKillSessionHandler-DZeLXWcB.cjs +361 -0
- package/dist/registerKillSessionHandler-GYvHdipX.mjs +358 -0
- package/dist/remoteSessionClient-B0LraSB9.cjs +634 -0
- package/dist/remoteSessionClient-CYnXRynE.mjs +612 -0
- package/dist/resources-BdFBQi8r.mjs +117 -0
- package/dist/resources-JDPugcDq.cjs +120 -0
- package/dist/run-CJzxoHVh.cjs +5762 -0
- package/dist/run-D3ifupU3.mjs +5739 -0
- package/dist/runClaude-Ba01qT-u.mjs +848 -0
- package/dist/runClaude-Da3RirzE.cjs +850 -0
- package/dist/runClaudeDeps-DOt79DjU.mjs +3624 -0
- package/dist/runClaudeDeps-DOzEBMls.cjs +3649 -0
- package/dist/{runGemini-DV6Ouadt.mjs → runGemini-BGeTz57m.mjs} +58 -31
- package/dist/{runGemini-F-mqx3_K.cjs → runGemini-DSr9LIxL.cjs} +202 -175
- package/dist/{runOpenClaw-Qqo9j63M.cjs → runOpenClaw-B1mTxN35.cjs} +64 -65
- package/dist/{runOpenClaw-D7MlPS5n.mjs → runOpenClaw-CogSedIc.mjs} +31 -32
- package/dist/sandbox-CG7IyDTU.cjs +187 -0
- package/dist/sandbox-DTe6d54R.mjs +180 -0
- package/dist/selfCheck-C9mVrQwf.mjs +84 -0
- package/dist/selfCheck-Dc-mNSLb.cjs +87 -0
- package/dist/{send-4qJTCAYW.cjs → send-B7J_eaG3.cjs} +16 -9
- package/dist/{send-CLhYXNgy.mjs → send-CBXJKc6O.mjs} +12 -5
- package/dist/server-CZTP_iOn.cjs +407 -0
- package/dist/server-DcVBv04l.mjs +404 -0
- package/dist/sessionLock-Bys1PNSo.cjs +205 -0
- package/dist/sessionLock-D-EG2CfG.mjs +197 -0
- package/dist/sessionModeFile-DMl3dw3r.mjs +32 -0
- package/dist/sessionModeFile-RSm0NQkH.cjs +36 -0
- package/dist/sessionOps-Dn8z85h_.cjs +783 -0
- package/dist/sessionOps-SuHW8Dfe.mjs +760 -0
- package/dist/sessionScanner-BOrGjMXL.cjs +209 -0
- package/dist/sessionScanner-CX3onqXh.mjs +206 -0
- package/dist/{sessions-CzIH2rGp.mjs → sessions-BEG_HTSi.mjs} +17 -8
- package/dist/{sessions-Bh1pyddi.cjs → sessions-D74aJbhL.cjs} +37 -28
- package/dist/setupOfflineReconnection-ByElY60m.cjs +74 -0
- package/dist/setupOfflineReconnection-DpvWTt69.mjs +72 -0
- package/dist/smallFastModel-BLNgMrwR.mjs +18 -0
- package/dist/smallFastModel-D_uxGMo3.cjs +21 -0
- package/dist/{spawn-CPIWlPOM.mjs → spawn-B7yro0b2.mjs} +26 -38
- package/dist/{spawn-CmFOSVdW.cjs → spawn-DgR0RKRs.cjs} +52 -64
- package/dist/spawnAgents-BGQiEF-w.cjs +52 -0
- package/dist/spawnAgents-DZzZ9jMI.mjs +45 -0
- package/dist/spawnHappyCLI-B2H5s4B_.mjs +64 -0
- package/dist/spawnHappyCLI-DBhwZT7O.cjs +66 -0
- package/dist/specialCommands-BSqhYg5X.mjs +52 -0
- package/dist/specialCommands-DSsTeRej.cjs +54 -0
- package/dist/startFileWatcher-B4VsLgjD.cjs +71 -0
- package/dist/startFileWatcher-DErVWZE4.mjs +69 -0
- package/dist/startupPlan-BLMbfQIH.cjs +12 -0
- package/dist/startupPlan-DFMyNgAs.mjs +10 -0
- package/dist/streamRelay-BiKw59Cc.cjs +233 -0
- package/dist/streamRelay-FPVbHpbM.mjs +231 -0
- package/dist/sync-C8gyQFMc.mjs +69 -0
- package/dist/sync-DccIKZ5_.cjs +71 -0
- package/dist/systemPrompt-BwTPWfMu.cjs +97 -0
- package/dist/systemPrompt-DX521JJz.mjs +94 -0
- package/dist/{teams-CEahj4cm.mjs → teams-C32F1hqd.mjs} +9 -40
- package/dist/{teams-CB1R9-Z9.cjs → teams-Dl8g8kTI.cjs} +14 -45
- package/dist/template-BaHAmH2K.cjs +129 -0
- package/dist/template-CiOPa2rd.mjs +121 -0
- package/dist/{terminalTitleSuggest-DKgX3osW.mjs → terminalTitleSuggest-CeKsX_V6.mjs} +1 -9
- package/dist/{terminalTitleSuggest-Dji8I0Jy.cjs → terminalTitleSuggest-DhvRFX3H.cjs} +0 -10
- package/dist/terminals-B_bfC9c2.cjs +250 -0
- package/dist/terminals-Dlg0x3nY.mjs +235 -0
- package/dist/time-D0XyHOid.mjs +38 -0
- package/dist/time-DCuTyook.cjs +42 -0
- package/dist/titleGenerator-CQ8CoGhg.mjs +166 -0
- package/dist/titleGenerator-ChzMJsyg.cjs +172 -0
- package/dist/tmuxSocket-B8Yx20sT.mjs +19 -0
- package/dist/tmuxSocket-D-Xt6Vn-.cjs +24 -0
- package/dist/{todo-DqyRI4wP.cjs → todo-BvUOTa8G.cjs} +15 -12
- package/dist/{todo-Cknp5D4U.mjs → todo-CZ6cFrrn.mjs} +11 -8
- package/dist/tools-BZtHF_qQ.mjs +177 -0
- package/dist/tools-Be3AoAwu.cjs +63 -0
- package/dist/tools-DQj0AeLk.cjs +180 -0
- package/dist/tools-DkluDcG4.mjs +60 -0
- package/dist/trimIdent-4gvk9Wk6.cjs +22 -0
- package/dist/trimIdent-BAjmv_TG.mjs +20 -0
- package/dist/types-CRS-srZK.cjs +66 -0
- package/dist/types-CkqAACXx.mjs +64 -0
- package/dist/uninstall-BkLzaJ6I.mjs +47 -0
- package/dist/uninstall-x-TUtf5H.cjs +49 -0
- package/package.json +7 -7
- package/dist/agentGuidance-BRDN1NoZ.cjs +0 -2217
- package/dist/agentGuidance-KgvYuF3R.mjs +0 -2145
- package/dist/index-BF6WfgV5.mjs +0 -19624
- package/dist/index-C-JazrMB.mjs +0 -52
- package/dist/index-blDSadUR.cjs +0 -58
- package/dist/index-rH3DrQ5B.cjs +0 -19688
- package/dist/limits-BH5CV5vR.cjs +0 -2683
- package/dist/limits-CjRj8IX5.mjs +0 -2558
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var z = require('zod');
|
|
4
|
+
var index = require('./index-DA7yINuk.cjs');
|
|
5
|
+
|
|
6
|
+
z.z.object({
|
|
7
|
+
teamsVersion: z.z.number().int().positive().optional(),
|
|
8
|
+
teamLaunchVersion: z.z.number().int().positive().optional(),
|
|
9
|
+
host: z.z.string(),
|
|
10
|
+
platform: z.z.string(),
|
|
11
|
+
happyCliVersion: z.z.string(),
|
|
12
|
+
homeDir: z.z.string(),
|
|
13
|
+
happyHomeDir: z.z.string(),
|
|
14
|
+
happyLibDir: z.z.string(),
|
|
15
|
+
cliAvailability: z.z.object({
|
|
16
|
+
claude: z.z.boolean(),
|
|
17
|
+
codex: z.z.boolean(),
|
|
18
|
+
gemini: z.z.boolean(),
|
|
19
|
+
openclaw: z.z.boolean(),
|
|
20
|
+
pi: z.z.boolean().optional(),
|
|
21
|
+
// absent on daemons that predate the pi runner
|
|
22
|
+
detectedAt: z.z.number()
|
|
23
|
+
}).optional(),
|
|
24
|
+
resumeSupport: z.z.object({
|
|
25
|
+
rpcAvailable: z.z.boolean(),
|
|
26
|
+
requiresSameMachine: z.z.boolean(),
|
|
27
|
+
requiresHappyAgentAuth: z.z.boolean(),
|
|
28
|
+
happyAgentAuthenticated: z.z.boolean(),
|
|
29
|
+
detectedAt: z.z.number()
|
|
30
|
+
}).optional()
|
|
31
|
+
});
|
|
32
|
+
const ClaudeAuthStateSchema = z.z.object({
|
|
33
|
+
probeVersion: z.z.number(),
|
|
34
|
+
daemonPid: z.z.number(),
|
|
35
|
+
status: z.z.union([z.z.enum(["ok", "not-logged-in", "unknown", "error", "claude-missing"]), z.z.string()]),
|
|
36
|
+
authMethod: z.z.string().optional(),
|
|
37
|
+
subscriptionType: z.z.string().optional(),
|
|
38
|
+
diagnosis: z.z.string().optional(),
|
|
39
|
+
detail: z.z.string().optional(),
|
|
40
|
+
repairable: z.z.string().optional(),
|
|
41
|
+
context: z.z.object({
|
|
42
|
+
platform: z.z.string(),
|
|
43
|
+
lineage: z.z.string(),
|
|
44
|
+
credentialStore: z.z.string()
|
|
45
|
+
}),
|
|
46
|
+
checkedAt: z.z.number()
|
|
47
|
+
});
|
|
48
|
+
const CliUpdateStateSchema = z.z.object({
|
|
49
|
+
currentVersion: z.z.string(),
|
|
50
|
+
recommendedVersion: z.z.string().nullable(),
|
|
51
|
+
minimumVersion: z.z.string().nullable(),
|
|
52
|
+
status: z.z.enum(["current", "available", "required"]),
|
|
53
|
+
/** B-351/B-503: the version this machine may install by itself, as decided
|
|
54
|
+
* by the relay (exact pin or the promoted `latest`); null means no
|
|
55
|
+
* unattended install. */
|
|
56
|
+
autoUpdateVersion: z.z.string().nullable().optional(),
|
|
57
|
+
retrySupported: z.z.boolean().optional(),
|
|
58
|
+
manualUpdateSupported: z.z.boolean().optional(),
|
|
59
|
+
checkedAt: z.z.number(),
|
|
60
|
+
/**
|
|
61
|
+
* B-321: a new bundle is on disk but refused to run, so the daemon is still
|
|
62
|
+
* serving the old code. Present only while that is true. Optional and additive:
|
|
63
|
+
* old web builds ignore it, old daemons never send it (iron rule 4).
|
|
64
|
+
*/
|
|
65
|
+
handoverHold: z.z.object({ reason: z.z.string(), at: z.z.number() }).nullable().optional(),
|
|
66
|
+
/** B-327: the last thing the machine's auto-update did, or why it did nothing. */
|
|
67
|
+
autoUpdate: z.z.object({
|
|
68
|
+
source: z.z.string().optional(),
|
|
69
|
+
state: z.z.union([z.z.enum(["installing", "installed", "failed", "skipped"]), z.z.string()]),
|
|
70
|
+
version: z.z.string().nullable(),
|
|
71
|
+
detail: z.z.string().optional(),
|
|
72
|
+
at: z.z.number()
|
|
73
|
+
}).nullable().optional()
|
|
74
|
+
});
|
|
75
|
+
const WebTerminalListItemSchema = z.z.object({
|
|
76
|
+
id: z.z.string(),
|
|
77
|
+
title: z.z.string().optional(),
|
|
78
|
+
/** New daemons always send an array (including []); absence identifies an
|
|
79
|
+
* old daemon that cannot persist terminal tags. */
|
|
80
|
+
tags: z.z.array(z.z.string()).optional(),
|
|
81
|
+
cwd: z.z.string().optional(),
|
|
82
|
+
createdAt: z.z.number().optional(),
|
|
83
|
+
activityAt: z.z.number().optional(),
|
|
84
|
+
agentState: z.z.enum(["working", "needs_input", "idle", "shell"]).optional(),
|
|
85
|
+
agentKind: z.z.string().optional(),
|
|
86
|
+
agentObservedAt: z.z.number().optional(),
|
|
87
|
+
/** B-105: mirror session of the claude running inside the terminal. */
|
|
88
|
+
mirrorSessionId: z.z.string().optional(),
|
|
89
|
+
/** B-150: auto-restored after a restart (ms epoch) — the directory and the
|
|
90
|
+
* conversation carried over, the processes did not. Cleared once opened. */
|
|
91
|
+
restoredAt: z.z.number().optional(),
|
|
92
|
+
/** B-265: @vh_title_manual is set (user renamed it). */
|
|
93
|
+
manual: z.z.boolean().optional(),
|
|
94
|
+
/** B-273: opened attached to the user's tmux session of this name. */
|
|
95
|
+
attachTmux: z.z.string().optional(),
|
|
96
|
+
/** B-486: direct-pty shell (no tmux) — not restorable after a daemon restart. */
|
|
97
|
+
direct: z.z.boolean().optional()
|
|
98
|
+
});
|
|
99
|
+
const ClosedTerminalRecordSchema = z.z.object({
|
|
100
|
+
id: z.z.string(),
|
|
101
|
+
title: z.z.string().optional(),
|
|
102
|
+
cwd: z.z.string().optional(),
|
|
103
|
+
/** B-105: shadow mirror session — structured history of the claude that ran
|
|
104
|
+
* inside the terminal, still reachable after the terminal is gone. */
|
|
105
|
+
mirrorSessionId: z.z.string().optional(),
|
|
106
|
+
/** B-149: claude conversation id, for one-click resume of a dead terminal. */
|
|
107
|
+
claudeSessionId: z.z.string().optional(),
|
|
108
|
+
/** B-149: 'daemon-gap' = died while no daemon was watching (restart/reboot);
|
|
109
|
+
* absent means an ordinary observed close. */
|
|
110
|
+
reason: z.z.enum(["closed", "daemon-gap"]).optional(),
|
|
111
|
+
/** B-265: tags + manual-rename flag at close time (restored verbatim). */
|
|
112
|
+
tags: z.z.array(z.z.string()).optional(),
|
|
113
|
+
manual: z.z.boolean().optional(),
|
|
114
|
+
/** B-273: attached user tmux session name — restore re-attaches. */
|
|
115
|
+
attachTmux: z.z.string().optional(),
|
|
116
|
+
closedAt: z.z.number()
|
|
117
|
+
});
|
|
118
|
+
z.z.object({
|
|
119
|
+
agentVersions: index.AgentVersionsSchema.optional(),
|
|
120
|
+
agentVersionEpoch: z.z.number().optional(),
|
|
121
|
+
status: z.z.union([
|
|
122
|
+
z.z.enum(["running", "shutting-down"]),
|
|
123
|
+
z.z.string()
|
|
124
|
+
// Forward compatibility
|
|
125
|
+
]),
|
|
126
|
+
pid: z.z.number().optional(),
|
|
127
|
+
httpPort: z.z.number().optional(),
|
|
128
|
+
startedAt: z.z.number().optional(),
|
|
129
|
+
shutdownRequestedAt: z.z.number().optional(),
|
|
130
|
+
shutdownSource: z.z.union([
|
|
131
|
+
z.z.enum(["mobile-app", "cli", "os-signal", "unknown"]),
|
|
132
|
+
z.z.string()
|
|
133
|
+
// Forward compatibility
|
|
134
|
+
]).optional(),
|
|
135
|
+
/**
|
|
136
|
+
* Push channel for this machine's web-terminal list (see
|
|
137
|
+
* terminal/webTerminal.ts list tracking). The daemon rewrites this field
|
|
138
|
+
* whenever the tracked list signature changes; the server persists it with
|
|
139
|
+
* the rest of daemonState and broadcasts `update-machine`, so every web
|
|
140
|
+
* client gets the terminal list/titles/agent states pushed instead of
|
|
141
|
+
* polling `list-terminals` — and an OFFLINE machine's last list stays
|
|
142
|
+
* readable from the server's persisted copy.
|
|
143
|
+
*
|
|
144
|
+
* Trust rule for consumers: the snapshot is only authoritative when
|
|
145
|
+
* `updatedAt >= startedAt` — i.e. it was written by the CURRENT daemon run.
|
|
146
|
+
* A downgraded daemon spreads the stale field forward (`{...state}`) but
|
|
147
|
+
* bumps `startedAt` on connect without restamping `updatedAt`, which is
|
|
148
|
+
* exactly what makes clients fall back to polling. Old clients ignore the
|
|
149
|
+
* field entirely.
|
|
150
|
+
*/
|
|
151
|
+
webTerminals: z.z.object({
|
|
152
|
+
updatedAt: z.z.number(),
|
|
153
|
+
terminals: z.z.array(WebTerminalListItemSchema)
|
|
154
|
+
}).optional(),
|
|
155
|
+
/**
|
|
156
|
+
* Recently closed terminals (B-084), newest first, capped at 20 — written
|
|
157
|
+
* alongside webTerminals in the same daemonState pushes (every close also
|
|
158
|
+
* changes the live list, so the two always travel together). Old clients
|
|
159
|
+
* ignore the field; old daemons never write it (web renders nothing).
|
|
160
|
+
*/
|
|
161
|
+
closedTerminals: z.z.array(ClosedTerminalRecordSchema).optional(),
|
|
162
|
+
/**
|
|
163
|
+
* B-265 capability flag: this daemon answers `restore-terminal`. Same trust
|
|
164
|
+
* rule as webTerminals — only `detectedAt >= startedAt` counts, because a
|
|
165
|
+
* downgraded daemon spreads the stale field forward on connect.
|
|
166
|
+
*/
|
|
167
|
+
terminalRestore: z.z.object({
|
|
168
|
+
rpcAvailable: z.z.boolean(),
|
|
169
|
+
detectedAt: z.z.number()
|
|
170
|
+
}).optional(),
|
|
171
|
+
/**
|
|
172
|
+
* B-273 capability flag: this daemon answers `list-tmux-sessions` and
|
|
173
|
+
* honours `open-terminal.attachTmux`. Same trust rule (`detectedAt >=
|
|
174
|
+
* startedAt`). Stamped unconditionally — on a machine without tmux the
|
|
175
|
+
* RPC just answers an empty list.
|
|
176
|
+
*/
|
|
177
|
+
tmuxSessions: z.z.object({
|
|
178
|
+
rpcAvailable: z.z.boolean(),
|
|
179
|
+
detectedAt: z.z.number(),
|
|
180
|
+
/** B-282: `kill-terminal` honours `alsoAttached`. */
|
|
181
|
+
killAttached: z.z.boolean().optional()
|
|
182
|
+
}).optional(),
|
|
183
|
+
/**
|
|
184
|
+
* B-290 capability flag: this daemon answers `claude-list-history` (import a
|
|
185
|
+
* Claude Code conversation that was never started through very-happy).
|
|
186
|
+
* Same trust rule (`detectedAt >= startedAt`).
|
|
187
|
+
*/
|
|
188
|
+
claudeHistory: z.z.object({
|
|
189
|
+
rpcAvailable: z.z.boolean(),
|
|
190
|
+
detectedAt: z.z.number()
|
|
191
|
+
}).optional(),
|
|
192
|
+
/**
|
|
193
|
+
* B-464 capability flag: this daemon answers `codex-list-history` /
|
|
194
|
+
* `codex-import-session` (import a Codex CLI / desktop thread that was never
|
|
195
|
+
* started through very-happy). Same trust rule (`detectedAt >= startedAt`).
|
|
196
|
+
*/
|
|
197
|
+
codexHistory: z.z.object({
|
|
198
|
+
rpcAvailable: z.z.boolean(),
|
|
199
|
+
detectedAt: z.z.number()
|
|
200
|
+
}).optional(),
|
|
201
|
+
/**
|
|
202
|
+
* B-486: can web terminals on this machine be durable? `tmuxAvailable:
|
|
203
|
+
* false` ⇒ every new terminal is a direct shell that dies with the daemon,
|
|
204
|
+
* so the web tells the user to install tmux. Same trust rule
|
|
205
|
+
* (`detectedAt >= startedAt`); old webs ignore it.
|
|
206
|
+
*/
|
|
207
|
+
terminalHost: z.z.object({
|
|
208
|
+
tmuxAvailable: z.z.boolean(),
|
|
209
|
+
tmuxVersion: z.z.string().optional(),
|
|
210
|
+
detectedAt: z.z.number()
|
|
211
|
+
}).optional(),
|
|
212
|
+
/** Relay-owned CLI compatibility/update policy last checked by this daemon. */
|
|
213
|
+
cliUpdate: CliUpdateStateSchema.optional(),
|
|
214
|
+
/**
|
|
215
|
+
* B-276: result of the daemon-context Claude auth preflight (spec
|
|
216
|
+
* 2026-09-claude-auth-preflight). Trust rule for consumers:
|
|
217
|
+
* `claudeAuth.daemonPid === daemonState.pid` — daemonState survives daemon
|
|
218
|
+
* restarts (the server returns the existing row and connect spreads it
|
|
219
|
+
* forward), so a downgraded daemon carries this field along unchanged.
|
|
220
|
+
*/
|
|
221
|
+
claudeAuth: ClaudeAuthStateSchema.optional()
|
|
222
|
+
});
|
|
223
|
+
const MessageMetaSchema = z.z.object({
|
|
224
|
+
sentFrom: z.z.string().optional(),
|
|
225
|
+
// Source identifier
|
|
226
|
+
permissionMode: z.z.enum(["default", "acceptEdits", "bypassPermissions", "plan", "read-only", "safe-yolo", "yolo"]).optional(),
|
|
227
|
+
// Permission mode for this message
|
|
228
|
+
model: z.z.string().nullable().optional(),
|
|
229
|
+
// Model name for this message (null = reset)
|
|
230
|
+
fallbackModel: z.z.string().nullable().optional(),
|
|
231
|
+
// Fallback model for this message (null = reset)
|
|
232
|
+
customSystemPrompt: z.z.string().nullable().optional(),
|
|
233
|
+
// Custom system prompt for this message (null = reset)
|
|
234
|
+
appendSystemPrompt: z.z.string().nullable().optional(),
|
|
235
|
+
// Append to system prompt for this message (null = reset)
|
|
236
|
+
allowedTools: z.z.array(z.z.string()).nullable().optional(),
|
|
237
|
+
// Allowed tools for this message (null = reset)
|
|
238
|
+
disallowedTools: z.z.array(z.z.string()).nullable().optional(),
|
|
239
|
+
// Disallowed tools for this message (null = reset)
|
|
240
|
+
/**
|
|
241
|
+
* Thinking depth for this message (null = reset to the machine default).
|
|
242
|
+
* Deliberately a plain string, not an enum: an unknown value must not make
|
|
243
|
+
* zod reject the WHOLE message the way the `dontAsk` permission enum did
|
|
244
|
+
* (AGENTS 铁律 14). runClaude validates it against its own allow-list and
|
|
245
|
+
* ignores anything else. Absent here until 0.2.105, which is why every
|
|
246
|
+
* released CLI silently dropped the web's effort selection.
|
|
247
|
+
*/
|
|
248
|
+
effort: z.z.string().nullable().optional(),
|
|
249
|
+
/** Omitted/queue waits for the current turn; steer targets the live turn. */
|
|
250
|
+
delivery: z.z.enum(["queue", "steer"]).optional()
|
|
251
|
+
});
|
|
252
|
+
z.z.object({
|
|
253
|
+
session: z.z.object({
|
|
254
|
+
id: z.z.string(),
|
|
255
|
+
tag: z.z.string(),
|
|
256
|
+
seq: z.z.number(),
|
|
257
|
+
createdAt: z.z.number(),
|
|
258
|
+
updatedAt: z.z.number(),
|
|
259
|
+
metadata: z.z.string(),
|
|
260
|
+
metadataVersion: z.z.number(),
|
|
261
|
+
agentState: z.z.string().nullable(),
|
|
262
|
+
agentStateVersion: z.z.number()
|
|
263
|
+
})
|
|
264
|
+
});
|
|
265
|
+
const UserMessageSchema = z.z.object({
|
|
266
|
+
role: z.z.literal("user"),
|
|
267
|
+
content: z.z.object({
|
|
268
|
+
type: z.z.literal("text"),
|
|
269
|
+
text: z.z.string()
|
|
270
|
+
}),
|
|
271
|
+
localKey: z.z.string().optional(),
|
|
272
|
+
// Mobile messages include this
|
|
273
|
+
meta: MessageMetaSchema.optional()
|
|
274
|
+
});
|
|
275
|
+
const FileEventMessageSchema = z.z.object({
|
|
276
|
+
role: z.z.literal("session"),
|
|
277
|
+
content: z.z.object({
|
|
278
|
+
type: z.z.literal("session"),
|
|
279
|
+
data: z.z.object({
|
|
280
|
+
id: z.z.string(),
|
|
281
|
+
time: z.z.number(),
|
|
282
|
+
role: z.z.literal("user"),
|
|
283
|
+
ev: z.z.object({
|
|
284
|
+
t: z.z.literal("file"),
|
|
285
|
+
ref: z.z.string(),
|
|
286
|
+
name: z.z.string(),
|
|
287
|
+
size: z.z.number(),
|
|
288
|
+
mimeType: z.z.string().optional(),
|
|
289
|
+
image: z.z.object({
|
|
290
|
+
width: z.z.number(),
|
|
291
|
+
height: z.z.number(),
|
|
292
|
+
// Optional — native iOS picker has no Canvas to compute thumbhash.
|
|
293
|
+
// App-side schema relaxed this in the same commit; keeping CLI in
|
|
294
|
+
// sync so the file event isn't silently rejected by Zod and the
|
|
295
|
+
// attachment never reaches Claude.
|
|
296
|
+
thumbhash: z.z.string().optional()
|
|
297
|
+
}).optional()
|
|
298
|
+
})
|
|
299
|
+
})
|
|
300
|
+
})
|
|
301
|
+
});
|
|
302
|
+
const AgentMessageSchema = z.z.object({
|
|
303
|
+
role: z.z.literal("agent"),
|
|
304
|
+
content: z.z.object({
|
|
305
|
+
type: z.z.literal("output"),
|
|
306
|
+
data: z.z.any()
|
|
307
|
+
}),
|
|
308
|
+
meta: MessageMetaSchema.optional()
|
|
309
|
+
});
|
|
310
|
+
z.z.union([UserMessageSchema, AgentMessageSchema]);
|
|
311
|
+
|
|
312
|
+
class AsyncLock {
|
|
313
|
+
permits = 1;
|
|
314
|
+
promiseResolverQueue = [];
|
|
315
|
+
async inLock(func) {
|
|
316
|
+
try {
|
|
317
|
+
await this.lock();
|
|
318
|
+
return await func();
|
|
319
|
+
} finally {
|
|
320
|
+
this.unlock();
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
async lock() {
|
|
324
|
+
if (this.permits > 0) {
|
|
325
|
+
this.permits = this.permits - 1;
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
await new Promise((resolve) => this.promiseResolverQueue.push(resolve));
|
|
329
|
+
}
|
|
330
|
+
unlock() {
|
|
331
|
+
this.permits += 1;
|
|
332
|
+
if (this.permits > 1 && this.promiseResolverQueue.length > 0) {
|
|
333
|
+
throw new Error("this.permits should never be > 0 when there is someone waiting.");
|
|
334
|
+
} else if (this.permits === 1 && this.promiseResolverQueue.length > 0) {
|
|
335
|
+
this.permits -= 1;
|
|
336
|
+
const nextResolver = this.promiseResolverQueue.shift();
|
|
337
|
+
if (nextResolver) {
|
|
338
|
+
setTimeout(() => {
|
|
339
|
+
nextResolver(true);
|
|
340
|
+
}, 0);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const MAX_CHAT_ATTACHMENT_SOURCE_BYTES = 50 * 1024 * 1024;
|
|
347
|
+
const CHAT_ATTACHMENT_ENCRYPTION_OVERHEAD_BYTES = 40;
|
|
348
|
+
const MAX_CHAT_ATTACHMENT_ENCRYPTED_BYTES = MAX_CHAT_ATTACHMENT_SOURCE_BYTES + CHAT_ATTACHMENT_ENCRYPTION_OVERHEAD_BYTES;
|
|
349
|
+
|
|
350
|
+
exports.AsyncLock = AsyncLock;
|
|
351
|
+
exports.FileEventMessageSchema = FileEventMessageSchema;
|
|
352
|
+
exports.MAX_CHAT_ATTACHMENT_ENCRYPTED_BYTES = MAX_CHAT_ATTACHMENT_ENCRYPTED_BYTES;
|
|
353
|
+
exports.MAX_CHAT_ATTACHMENT_SOURCE_BYTES = MAX_CHAT_ATTACHMENT_SOURCE_BYTES;
|
|
354
|
+
exports.UserMessageSchema = UserMessageSchema;
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { k as AgentVersionsSchema } from './index-qdS1friN.mjs';
|
|
3
|
+
|
|
4
|
+
z.object({
|
|
5
|
+
teamsVersion: z.number().int().positive().optional(),
|
|
6
|
+
teamLaunchVersion: z.number().int().positive().optional(),
|
|
7
|
+
host: z.string(),
|
|
8
|
+
platform: z.string(),
|
|
9
|
+
happyCliVersion: z.string(),
|
|
10
|
+
homeDir: z.string(),
|
|
11
|
+
happyHomeDir: z.string(),
|
|
12
|
+
happyLibDir: z.string(),
|
|
13
|
+
cliAvailability: z.object({
|
|
14
|
+
claude: z.boolean(),
|
|
15
|
+
codex: z.boolean(),
|
|
16
|
+
gemini: z.boolean(),
|
|
17
|
+
openclaw: z.boolean(),
|
|
18
|
+
pi: z.boolean().optional(),
|
|
19
|
+
// absent on daemons that predate the pi runner
|
|
20
|
+
detectedAt: z.number()
|
|
21
|
+
}).optional(),
|
|
22
|
+
resumeSupport: z.object({
|
|
23
|
+
rpcAvailable: z.boolean(),
|
|
24
|
+
requiresSameMachine: z.boolean(),
|
|
25
|
+
requiresHappyAgentAuth: z.boolean(),
|
|
26
|
+
happyAgentAuthenticated: z.boolean(),
|
|
27
|
+
detectedAt: z.number()
|
|
28
|
+
}).optional()
|
|
29
|
+
});
|
|
30
|
+
const ClaudeAuthStateSchema = z.object({
|
|
31
|
+
probeVersion: z.number(),
|
|
32
|
+
daemonPid: z.number(),
|
|
33
|
+
status: z.union([z.enum(["ok", "not-logged-in", "unknown", "error", "claude-missing"]), z.string()]),
|
|
34
|
+
authMethod: z.string().optional(),
|
|
35
|
+
subscriptionType: z.string().optional(),
|
|
36
|
+
diagnosis: z.string().optional(),
|
|
37
|
+
detail: z.string().optional(),
|
|
38
|
+
repairable: z.string().optional(),
|
|
39
|
+
context: z.object({
|
|
40
|
+
platform: z.string(),
|
|
41
|
+
lineage: z.string(),
|
|
42
|
+
credentialStore: z.string()
|
|
43
|
+
}),
|
|
44
|
+
checkedAt: z.number()
|
|
45
|
+
});
|
|
46
|
+
const CliUpdateStateSchema = z.object({
|
|
47
|
+
currentVersion: z.string(),
|
|
48
|
+
recommendedVersion: z.string().nullable(),
|
|
49
|
+
minimumVersion: z.string().nullable(),
|
|
50
|
+
status: z.enum(["current", "available", "required"]),
|
|
51
|
+
/** B-351/B-503: the version this machine may install by itself, as decided
|
|
52
|
+
* by the relay (exact pin or the promoted `latest`); null means no
|
|
53
|
+
* unattended install. */
|
|
54
|
+
autoUpdateVersion: z.string().nullable().optional(),
|
|
55
|
+
retrySupported: z.boolean().optional(),
|
|
56
|
+
manualUpdateSupported: z.boolean().optional(),
|
|
57
|
+
checkedAt: z.number(),
|
|
58
|
+
/**
|
|
59
|
+
* B-321: a new bundle is on disk but refused to run, so the daemon is still
|
|
60
|
+
* serving the old code. Present only while that is true. Optional and additive:
|
|
61
|
+
* old web builds ignore it, old daemons never send it (iron rule 4).
|
|
62
|
+
*/
|
|
63
|
+
handoverHold: z.object({ reason: z.string(), at: z.number() }).nullable().optional(),
|
|
64
|
+
/** B-327: the last thing the machine's auto-update did, or why it did nothing. */
|
|
65
|
+
autoUpdate: z.object({
|
|
66
|
+
source: z.string().optional(),
|
|
67
|
+
state: z.union([z.enum(["installing", "installed", "failed", "skipped"]), z.string()]),
|
|
68
|
+
version: z.string().nullable(),
|
|
69
|
+
detail: z.string().optional(),
|
|
70
|
+
at: z.number()
|
|
71
|
+
}).nullable().optional()
|
|
72
|
+
});
|
|
73
|
+
const WebTerminalListItemSchema = z.object({
|
|
74
|
+
id: z.string(),
|
|
75
|
+
title: z.string().optional(),
|
|
76
|
+
/** New daemons always send an array (including []); absence identifies an
|
|
77
|
+
* old daemon that cannot persist terminal tags. */
|
|
78
|
+
tags: z.array(z.string()).optional(),
|
|
79
|
+
cwd: z.string().optional(),
|
|
80
|
+
createdAt: z.number().optional(),
|
|
81
|
+
activityAt: z.number().optional(),
|
|
82
|
+
agentState: z.enum(["working", "needs_input", "idle", "shell"]).optional(),
|
|
83
|
+
agentKind: z.string().optional(),
|
|
84
|
+
agentObservedAt: z.number().optional(),
|
|
85
|
+
/** B-105: mirror session of the claude running inside the terminal. */
|
|
86
|
+
mirrorSessionId: z.string().optional(),
|
|
87
|
+
/** B-150: auto-restored after a restart (ms epoch) — the directory and the
|
|
88
|
+
* conversation carried over, the processes did not. Cleared once opened. */
|
|
89
|
+
restoredAt: z.number().optional(),
|
|
90
|
+
/** B-265: @vh_title_manual is set (user renamed it). */
|
|
91
|
+
manual: z.boolean().optional(),
|
|
92
|
+
/** B-273: opened attached to the user's tmux session of this name. */
|
|
93
|
+
attachTmux: z.string().optional(),
|
|
94
|
+
/** B-486: direct-pty shell (no tmux) — not restorable after a daemon restart. */
|
|
95
|
+
direct: z.boolean().optional()
|
|
96
|
+
});
|
|
97
|
+
const ClosedTerminalRecordSchema = z.object({
|
|
98
|
+
id: z.string(),
|
|
99
|
+
title: z.string().optional(),
|
|
100
|
+
cwd: z.string().optional(),
|
|
101
|
+
/** B-105: shadow mirror session — structured history of the claude that ran
|
|
102
|
+
* inside the terminal, still reachable after the terminal is gone. */
|
|
103
|
+
mirrorSessionId: z.string().optional(),
|
|
104
|
+
/** B-149: claude conversation id, for one-click resume of a dead terminal. */
|
|
105
|
+
claudeSessionId: z.string().optional(),
|
|
106
|
+
/** B-149: 'daemon-gap' = died while no daemon was watching (restart/reboot);
|
|
107
|
+
* absent means an ordinary observed close. */
|
|
108
|
+
reason: z.enum(["closed", "daemon-gap"]).optional(),
|
|
109
|
+
/** B-265: tags + manual-rename flag at close time (restored verbatim). */
|
|
110
|
+
tags: z.array(z.string()).optional(),
|
|
111
|
+
manual: z.boolean().optional(),
|
|
112
|
+
/** B-273: attached user tmux session name — restore re-attaches. */
|
|
113
|
+
attachTmux: z.string().optional(),
|
|
114
|
+
closedAt: z.number()
|
|
115
|
+
});
|
|
116
|
+
z.object({
|
|
117
|
+
agentVersions: AgentVersionsSchema.optional(),
|
|
118
|
+
agentVersionEpoch: z.number().optional(),
|
|
119
|
+
status: z.union([
|
|
120
|
+
z.enum(["running", "shutting-down"]),
|
|
121
|
+
z.string()
|
|
122
|
+
// Forward compatibility
|
|
123
|
+
]),
|
|
124
|
+
pid: z.number().optional(),
|
|
125
|
+
httpPort: z.number().optional(),
|
|
126
|
+
startedAt: z.number().optional(),
|
|
127
|
+
shutdownRequestedAt: z.number().optional(),
|
|
128
|
+
shutdownSource: z.union([
|
|
129
|
+
z.enum(["mobile-app", "cli", "os-signal", "unknown"]),
|
|
130
|
+
z.string()
|
|
131
|
+
// Forward compatibility
|
|
132
|
+
]).optional(),
|
|
133
|
+
/**
|
|
134
|
+
* Push channel for this machine's web-terminal list (see
|
|
135
|
+
* terminal/webTerminal.ts list tracking). The daemon rewrites this field
|
|
136
|
+
* whenever the tracked list signature changes; the server persists it with
|
|
137
|
+
* the rest of daemonState and broadcasts `update-machine`, so every web
|
|
138
|
+
* client gets the terminal list/titles/agent states pushed instead of
|
|
139
|
+
* polling `list-terminals` — and an OFFLINE machine's last list stays
|
|
140
|
+
* readable from the server's persisted copy.
|
|
141
|
+
*
|
|
142
|
+
* Trust rule for consumers: the snapshot is only authoritative when
|
|
143
|
+
* `updatedAt >= startedAt` — i.e. it was written by the CURRENT daemon run.
|
|
144
|
+
* A downgraded daemon spreads the stale field forward (`{...state}`) but
|
|
145
|
+
* bumps `startedAt` on connect without restamping `updatedAt`, which is
|
|
146
|
+
* exactly what makes clients fall back to polling. Old clients ignore the
|
|
147
|
+
* field entirely.
|
|
148
|
+
*/
|
|
149
|
+
webTerminals: z.object({
|
|
150
|
+
updatedAt: z.number(),
|
|
151
|
+
terminals: z.array(WebTerminalListItemSchema)
|
|
152
|
+
}).optional(),
|
|
153
|
+
/**
|
|
154
|
+
* Recently closed terminals (B-084), newest first, capped at 20 — written
|
|
155
|
+
* alongside webTerminals in the same daemonState pushes (every close also
|
|
156
|
+
* changes the live list, so the two always travel together). Old clients
|
|
157
|
+
* ignore the field; old daemons never write it (web renders nothing).
|
|
158
|
+
*/
|
|
159
|
+
closedTerminals: z.array(ClosedTerminalRecordSchema).optional(),
|
|
160
|
+
/**
|
|
161
|
+
* B-265 capability flag: this daemon answers `restore-terminal`. Same trust
|
|
162
|
+
* rule as webTerminals — only `detectedAt >= startedAt` counts, because a
|
|
163
|
+
* downgraded daemon spreads the stale field forward on connect.
|
|
164
|
+
*/
|
|
165
|
+
terminalRestore: z.object({
|
|
166
|
+
rpcAvailable: z.boolean(),
|
|
167
|
+
detectedAt: z.number()
|
|
168
|
+
}).optional(),
|
|
169
|
+
/**
|
|
170
|
+
* B-273 capability flag: this daemon answers `list-tmux-sessions` and
|
|
171
|
+
* honours `open-terminal.attachTmux`. Same trust rule (`detectedAt >=
|
|
172
|
+
* startedAt`). Stamped unconditionally — on a machine without tmux the
|
|
173
|
+
* RPC just answers an empty list.
|
|
174
|
+
*/
|
|
175
|
+
tmuxSessions: z.object({
|
|
176
|
+
rpcAvailable: z.boolean(),
|
|
177
|
+
detectedAt: z.number(),
|
|
178
|
+
/** B-282: `kill-terminal` honours `alsoAttached`. */
|
|
179
|
+
killAttached: z.boolean().optional()
|
|
180
|
+
}).optional(),
|
|
181
|
+
/**
|
|
182
|
+
* B-290 capability flag: this daemon answers `claude-list-history` (import a
|
|
183
|
+
* Claude Code conversation that was never started through very-happy).
|
|
184
|
+
* Same trust rule (`detectedAt >= startedAt`).
|
|
185
|
+
*/
|
|
186
|
+
claudeHistory: z.object({
|
|
187
|
+
rpcAvailable: z.boolean(),
|
|
188
|
+
detectedAt: z.number()
|
|
189
|
+
}).optional(),
|
|
190
|
+
/**
|
|
191
|
+
* B-464 capability flag: this daemon answers `codex-list-history` /
|
|
192
|
+
* `codex-import-session` (import a Codex CLI / desktop thread that was never
|
|
193
|
+
* started through very-happy). Same trust rule (`detectedAt >= startedAt`).
|
|
194
|
+
*/
|
|
195
|
+
codexHistory: z.object({
|
|
196
|
+
rpcAvailable: z.boolean(),
|
|
197
|
+
detectedAt: z.number()
|
|
198
|
+
}).optional(),
|
|
199
|
+
/**
|
|
200
|
+
* B-486: can web terminals on this machine be durable? `tmuxAvailable:
|
|
201
|
+
* false` ⇒ every new terminal is a direct shell that dies with the daemon,
|
|
202
|
+
* so the web tells the user to install tmux. Same trust rule
|
|
203
|
+
* (`detectedAt >= startedAt`); old webs ignore it.
|
|
204
|
+
*/
|
|
205
|
+
terminalHost: z.object({
|
|
206
|
+
tmuxAvailable: z.boolean(),
|
|
207
|
+
tmuxVersion: z.string().optional(),
|
|
208
|
+
detectedAt: z.number()
|
|
209
|
+
}).optional(),
|
|
210
|
+
/** Relay-owned CLI compatibility/update policy last checked by this daemon. */
|
|
211
|
+
cliUpdate: CliUpdateStateSchema.optional(),
|
|
212
|
+
/**
|
|
213
|
+
* B-276: result of the daemon-context Claude auth preflight (spec
|
|
214
|
+
* 2026-09-claude-auth-preflight). Trust rule for consumers:
|
|
215
|
+
* `claudeAuth.daemonPid === daemonState.pid` — daemonState survives daemon
|
|
216
|
+
* restarts (the server returns the existing row and connect spreads it
|
|
217
|
+
* forward), so a downgraded daemon carries this field along unchanged.
|
|
218
|
+
*/
|
|
219
|
+
claudeAuth: ClaudeAuthStateSchema.optional()
|
|
220
|
+
});
|
|
221
|
+
const MessageMetaSchema = z.object({
|
|
222
|
+
sentFrom: z.string().optional(),
|
|
223
|
+
// Source identifier
|
|
224
|
+
permissionMode: z.enum(["default", "acceptEdits", "bypassPermissions", "plan", "read-only", "safe-yolo", "yolo"]).optional(),
|
|
225
|
+
// Permission mode for this message
|
|
226
|
+
model: z.string().nullable().optional(),
|
|
227
|
+
// Model name for this message (null = reset)
|
|
228
|
+
fallbackModel: z.string().nullable().optional(),
|
|
229
|
+
// Fallback model for this message (null = reset)
|
|
230
|
+
customSystemPrompt: z.string().nullable().optional(),
|
|
231
|
+
// Custom system prompt for this message (null = reset)
|
|
232
|
+
appendSystemPrompt: z.string().nullable().optional(),
|
|
233
|
+
// Append to system prompt for this message (null = reset)
|
|
234
|
+
allowedTools: z.array(z.string()).nullable().optional(),
|
|
235
|
+
// Allowed tools for this message (null = reset)
|
|
236
|
+
disallowedTools: z.array(z.string()).nullable().optional(),
|
|
237
|
+
// Disallowed tools for this message (null = reset)
|
|
238
|
+
/**
|
|
239
|
+
* Thinking depth for this message (null = reset to the machine default).
|
|
240
|
+
* Deliberately a plain string, not an enum: an unknown value must not make
|
|
241
|
+
* zod reject the WHOLE message the way the `dontAsk` permission enum did
|
|
242
|
+
* (AGENTS 铁律 14). runClaude validates it against its own allow-list and
|
|
243
|
+
* ignores anything else. Absent here until 0.2.105, which is why every
|
|
244
|
+
* released CLI silently dropped the web's effort selection.
|
|
245
|
+
*/
|
|
246
|
+
effort: z.string().nullable().optional(),
|
|
247
|
+
/** Omitted/queue waits for the current turn; steer targets the live turn. */
|
|
248
|
+
delivery: z.enum(["queue", "steer"]).optional()
|
|
249
|
+
});
|
|
250
|
+
z.object({
|
|
251
|
+
session: z.object({
|
|
252
|
+
id: z.string(),
|
|
253
|
+
tag: z.string(),
|
|
254
|
+
seq: z.number(),
|
|
255
|
+
createdAt: z.number(),
|
|
256
|
+
updatedAt: z.number(),
|
|
257
|
+
metadata: z.string(),
|
|
258
|
+
metadataVersion: z.number(),
|
|
259
|
+
agentState: z.string().nullable(),
|
|
260
|
+
agentStateVersion: z.number()
|
|
261
|
+
})
|
|
262
|
+
});
|
|
263
|
+
const UserMessageSchema = z.object({
|
|
264
|
+
role: z.literal("user"),
|
|
265
|
+
content: z.object({
|
|
266
|
+
type: z.literal("text"),
|
|
267
|
+
text: z.string()
|
|
268
|
+
}),
|
|
269
|
+
localKey: z.string().optional(),
|
|
270
|
+
// Mobile messages include this
|
|
271
|
+
meta: MessageMetaSchema.optional()
|
|
272
|
+
});
|
|
273
|
+
const FileEventMessageSchema = z.object({
|
|
274
|
+
role: z.literal("session"),
|
|
275
|
+
content: z.object({
|
|
276
|
+
type: z.literal("session"),
|
|
277
|
+
data: z.object({
|
|
278
|
+
id: z.string(),
|
|
279
|
+
time: z.number(),
|
|
280
|
+
role: z.literal("user"),
|
|
281
|
+
ev: z.object({
|
|
282
|
+
t: z.literal("file"),
|
|
283
|
+
ref: z.string(),
|
|
284
|
+
name: z.string(),
|
|
285
|
+
size: z.number(),
|
|
286
|
+
mimeType: z.string().optional(),
|
|
287
|
+
image: z.object({
|
|
288
|
+
width: z.number(),
|
|
289
|
+
height: z.number(),
|
|
290
|
+
// Optional — native iOS picker has no Canvas to compute thumbhash.
|
|
291
|
+
// App-side schema relaxed this in the same commit; keeping CLI in
|
|
292
|
+
// sync so the file event isn't silently rejected by Zod and the
|
|
293
|
+
// attachment never reaches Claude.
|
|
294
|
+
thumbhash: z.string().optional()
|
|
295
|
+
}).optional()
|
|
296
|
+
})
|
|
297
|
+
})
|
|
298
|
+
})
|
|
299
|
+
});
|
|
300
|
+
const AgentMessageSchema = z.object({
|
|
301
|
+
role: z.literal("agent"),
|
|
302
|
+
content: z.object({
|
|
303
|
+
type: z.literal("output"),
|
|
304
|
+
data: z.any()
|
|
305
|
+
}),
|
|
306
|
+
meta: MessageMetaSchema.optional()
|
|
307
|
+
});
|
|
308
|
+
z.union([UserMessageSchema, AgentMessageSchema]);
|
|
309
|
+
|
|
310
|
+
class AsyncLock {
|
|
311
|
+
permits = 1;
|
|
312
|
+
promiseResolverQueue = [];
|
|
313
|
+
async inLock(func) {
|
|
314
|
+
try {
|
|
315
|
+
await this.lock();
|
|
316
|
+
return await func();
|
|
317
|
+
} finally {
|
|
318
|
+
this.unlock();
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
async lock() {
|
|
322
|
+
if (this.permits > 0) {
|
|
323
|
+
this.permits = this.permits - 1;
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
await new Promise((resolve) => this.promiseResolverQueue.push(resolve));
|
|
327
|
+
}
|
|
328
|
+
unlock() {
|
|
329
|
+
this.permits += 1;
|
|
330
|
+
if (this.permits > 1 && this.promiseResolverQueue.length > 0) {
|
|
331
|
+
throw new Error("this.permits should never be > 0 when there is someone waiting.");
|
|
332
|
+
} else if (this.permits === 1 && this.promiseResolverQueue.length > 0) {
|
|
333
|
+
this.permits -= 1;
|
|
334
|
+
const nextResolver = this.promiseResolverQueue.shift();
|
|
335
|
+
if (nextResolver) {
|
|
336
|
+
setTimeout(() => {
|
|
337
|
+
nextResolver(true);
|
|
338
|
+
}, 0);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const MAX_CHAT_ATTACHMENT_SOURCE_BYTES = 50 * 1024 * 1024;
|
|
345
|
+
const CHAT_ATTACHMENT_ENCRYPTION_OVERHEAD_BYTES = 40;
|
|
346
|
+
const MAX_CHAT_ATTACHMENT_ENCRYPTED_BYTES = MAX_CHAT_ATTACHMENT_SOURCE_BYTES + CHAT_ATTACHMENT_ENCRYPTION_OVERHEAD_BYTES;
|
|
347
|
+
|
|
348
|
+
export { AsyncLock as A, FileEventMessageSchema as F, MAX_CHAT_ATTACHMENT_SOURCE_BYTES as M, UserMessageSchema as U, MAX_CHAT_ATTACHMENT_ENCRYPTED_BYTES as a };
|