very-happy-cli 0.2.158 → 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-DIDRig5G.cjs → AcpBackend-Bm2rdke8.cjs} +78 -76
- package/dist/{AcpBackend-vDVLHuYJ.mjs → AcpBackend-mzv8Dhba.mjs} +4 -2
- package/dist/{AcpSessionManager-C44U99CC.cjs → AcpSessionManager-BAY1Pggx.cjs} +9 -9
- package/dist/{AcpSessionManager-CmRjfhn3.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-Dw8Jx_CJ.cjs → agentHome-CboCeKWq.cjs} +14 -28
- package/dist/{agentHome-CyLmGH5L.mjs → agentHome-Dj1C43aJ.mjs} +8 -22
- package/dist/api-CLMUr-SX.mjs +3339 -0
- package/dist/api-CgundNNX.cjs +3346 -0
- package/dist/{types-DIBF4U0Y.mjs → apiMachine-B9dLW_p5.mjs} +9116 -16015
- package/dist/{types-DnrPeN80.cjs → apiMachine-Bn8482VM.cjs} +9104 -16057
- 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-DZbNcTXx.cjs → auto-BOX_fgmR.cjs} +70 -79
- package/dist/{auto-BlMZPwOk.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-BtPArqRH.mjs → config-CTx_jb-C.mjs} +7 -40
- package/dist/{config-DG84bjwF.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-DPCsWlWK.cjs → index-B6pAdvJx.cjs} +131 -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-ZChGsuB7.mjs → index-DMZqWwsP.mjs} +79 -39
- 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-DarS_Wco.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-wKQGgXvN.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-DcQfee_O.cjs → installTerminalHooks-BQZbvxsZ.cjs} +5 -40
- package/dist/{installTerminalHooks-CpNbRFPz.mjs → installTerminalHooks-By7gBMEF.mjs} +3 -38
- package/dist/lib.cjs +28 -19
- package/dist/lib.d.cts +126 -2
- package/dist/lib.d.mts +126 -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-BN6bKIGb.mjs → mcp-B1A4I3TK.mjs} +27 -33
- package/dist/{mcp-DGdeUUDJ.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-bkw2NAZU.mjs → piRuntime-CSGkwCKQ.mjs} +2 -2
- package/dist/{piRuntime-3qtbKujX.cjs → piRuntime-C_H7MJCM.cjs} +4 -4
- package/dist/{piTerminal-DilKwM7B.mjs → piTerminal-C8a1OrNQ.mjs} +32 -35
- package/dist/{piTerminal-BYxp3LMr.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-Cjii069p.mjs → runGemini-BGeTz57m.mjs} +58 -31
- package/dist/{runGemini-28O2sqyI.cjs → runGemini-DSr9LIxL.cjs} +202 -175
- package/dist/{runOpenClaw-CiMZad-H.cjs → runOpenClaw-B1mTxN35.cjs} +64 -65
- package/dist/{runOpenClaw-jaLr7KF1.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-D5ejHPXG.cjs → send-B7J_eaG3.cjs} +16 -9
- package/dist/{send-C9mOtChi.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-W6771g3X.mjs → sessions-BEG_HTSi.mjs} +17 -8
- package/dist/{sessions-BNMPQoLE.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-D0QVhzRb.mjs → spawn-B7yro0b2.mjs} +26 -38
- package/dist/{spawn-Ddtom1cb.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-CqSwtw2O.mjs → teams-C32F1hqd.mjs} +9 -40
- package/dist/{teams-BZ1tayg_.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-BYMg0fR0.cjs → todo-BvUOTa8G.cjs} +15 -12
- package/dist/{todo-BbusB1zM.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-CrR9l62U.mjs +0 -2145
- package/dist/agentGuidance-DwOWbX55.cjs +0 -2217
- package/dist/index-BG932eCh.cjs +0 -19655
- package/dist/index-CVCt3kSt.mjs +0 -19591
- package/dist/index-D5ScEErM.cjs +0 -58
- package/dist/index-DgO0FHOx.mjs +0 -52
- package/dist/limits-D2uN090G.mjs +0 -2528
- package/dist/limits-kqFqhfsh.cjs +0 -2652
|
@@ -4,51 +4,20 @@ var os = require('node:os');
|
|
|
4
4
|
var promises = require('node:fs/promises');
|
|
5
5
|
var z = require('zod');
|
|
6
6
|
var node_crypto = require('node:crypto');
|
|
7
|
-
var
|
|
8
|
-
var persistence = require('./
|
|
9
|
-
var install = require('./install-
|
|
7
|
+
var client = require('./client-3Ac-O4pw.cjs');
|
|
8
|
+
var persistence = require('./persistence-yKTH3-5X.cjs');
|
|
9
|
+
var install = require('./install-Cs5qAPrB.cjs');
|
|
10
|
+
require('./configuration-BSYpcPwE.cjs');
|
|
10
11
|
require('node:fs');
|
|
11
12
|
require('node:path');
|
|
12
|
-
require('
|
|
13
|
-
require('
|
|
14
|
-
require('
|
|
13
|
+
require('./package-BwMrPwqH.cjs');
|
|
14
|
+
require('./context-DsDr6E2t.cjs');
|
|
15
|
+
require('./authRelay-BdYkC1Po.cjs');
|
|
15
16
|
require('tweetnacl');
|
|
17
|
+
require('./logger-CS0mw3fa.cjs');
|
|
16
18
|
require('chalk');
|
|
17
19
|
require('node:util');
|
|
18
|
-
require('./
|
|
19
|
-
require('./types-DnrPeN80.cjs');
|
|
20
|
-
require('node:events');
|
|
21
|
-
require('child_process');
|
|
22
|
-
require('util');
|
|
23
|
-
require('fs/promises');
|
|
24
|
-
require('crypto');
|
|
25
|
-
require('path');
|
|
26
|
-
require('cross-spawn');
|
|
27
|
-
require('./terminalTitleSuggest-Dji8I0Jy.cjs');
|
|
28
|
-
require('url');
|
|
29
|
-
require('os');
|
|
30
|
-
require('node:child_process');
|
|
31
|
-
require('node-pty');
|
|
32
|
-
require('fs');
|
|
33
|
-
require('node:readline');
|
|
34
|
-
require('@anthropic-ai/sandbox-runtime');
|
|
35
|
-
require('expo-server-sdk');
|
|
36
|
-
require('ink');
|
|
37
|
-
require('react');
|
|
38
|
-
require('@anthropic-ai/claude-agent-sdk');
|
|
39
|
-
require('ps-list');
|
|
40
|
-
require('tmp');
|
|
41
|
-
require('open');
|
|
42
|
-
require('fastify');
|
|
43
|
-
require('fastify-type-provider-zod');
|
|
44
|
-
require('node:module');
|
|
45
|
-
require('@modelcontextprotocol/sdk/server/mcp.js');
|
|
46
|
-
require('node:http');
|
|
47
|
-
require('@modelcontextprotocol/sdk/server/streamableHttp.js');
|
|
48
|
-
require('http');
|
|
49
|
-
require('inquirer');
|
|
50
|
-
require('node:url');
|
|
51
|
-
require('node:readline/promises');
|
|
20
|
+
require('./resources-JDPugcDq.cjs');
|
|
52
21
|
|
|
53
22
|
const legacyTask = z.z.object({
|
|
54
23
|
id: z.z.string().regex(/^T-\d{3,}$/),
|
|
@@ -90,7 +59,7 @@ async function setTeamPermissionMode(teamId, mode, requestId) {
|
|
|
90
59
|
if (mode !== "default" && mode !== "bypassPermissions") throw new Error("Mode must be default or bypassPermissions");
|
|
91
60
|
const credentials = await persistence.readCredentialsForConfiguredRelay();
|
|
92
61
|
if (!credentials) throw new Error("Sign in before changing team execution mode");
|
|
93
|
-
const result = await
|
|
62
|
+
const result = await client.teamRequest(
|
|
94
63
|
`/v1/teams/${encodeURIComponent(teamId)}/actions`,
|
|
95
64
|
"POST",
|
|
96
65
|
credentials.token,
|
|
@@ -148,21 +117,21 @@ async function handleTeamsCommand(args) {
|
|
|
148
117
|
console.log(JSON.stringify(await setTeamPermissionMode(teamId, mode, requestId)));
|
|
149
118
|
return;
|
|
150
119
|
}
|
|
151
|
-
const client =
|
|
120
|
+
const client$1 = client.createTeamsClient(value("--session-id"));
|
|
152
121
|
let result;
|
|
153
|
-
if (command === "inspect") result = await client.inspect();
|
|
122
|
+
if (command === "inspect") result = await client$1.inspect();
|
|
154
123
|
else if (command === "create" || command === "join") {
|
|
155
124
|
const name = value("--name");
|
|
156
125
|
if (!name) throw new Error("--name is required");
|
|
157
126
|
if (command === "join" && !value("--team-id")) throw new Error("--team-id is required");
|
|
158
|
-
result = await client.initialize({ name, teamId: command === "join" ? value("--team-id") : void 0, machineId: value("--machine-id"), botId: value("--bot-id"), requestId: value("--request-id") ?? node_crypto.randomUUID() });
|
|
127
|
+
result = await client$1.initialize({ name, teamId: command === "join" ? value("--team-id") : void 0, machineId: value("--machine-id"), botId: value("--bot-id"), requestId: value("--request-id") ?? node_crypto.randomUUID() });
|
|
159
128
|
} else if (command === "action") {
|
|
160
129
|
const payload = value("--json");
|
|
161
130
|
const requestId = value("--request-id");
|
|
162
131
|
if (!payload || !requestId) throw new Error("--json and --request-id are required");
|
|
163
132
|
const action = JSON.parse(payload);
|
|
164
133
|
if (!["delegate", "message", "submit", "accept", "return", "cancel", "handoff", "schedule-create", "schedule-pause", "schedule-resume", "schedule-cancel"].includes(action.type)) throw new Error("Unsupported team action");
|
|
165
|
-
result = await client.action(action, requestId);
|
|
134
|
+
result = await client$1.action(action, requestId);
|
|
166
135
|
} else throw new Error("Unknown teams command; use teams --help");
|
|
167
136
|
console.log(JSON.stringify(result));
|
|
168
137
|
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function payloadJson(payload) {
|
|
4
|
+
if (!payload) return void 0;
|
|
5
|
+
try {
|
|
6
|
+
return JSON.parse(payload);
|
|
7
|
+
} catch {
|
|
8
|
+
return void 0;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function lookupPath(root, path) {
|
|
12
|
+
let current = root;
|
|
13
|
+
for (const segment of path) {
|
|
14
|
+
if (current === null || typeof current !== "object") return void 0;
|
|
15
|
+
current = current[segment];
|
|
16
|
+
}
|
|
17
|
+
return current;
|
|
18
|
+
}
|
|
19
|
+
function scalar(value) {
|
|
20
|
+
if (value === void 0 || value === null) return "";
|
|
21
|
+
if (typeof value === "string") return value;
|
|
22
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
23
|
+
try {
|
|
24
|
+
return JSON.stringify(value);
|
|
25
|
+
} catch {
|
|
26
|
+
return "";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function formatNow(now, tz) {
|
|
30
|
+
if (!tz) return new Date(now).toISOString();
|
|
31
|
+
try {
|
|
32
|
+
const parts = new Intl.DateTimeFormat("en-CA", { timeZone: tz, hourCycle: "h23", year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit", timeZoneName: "longOffset" }).formatToParts(new Date(now));
|
|
33
|
+
const get = (type) => parts.find((p) => p.type === type)?.value ?? "";
|
|
34
|
+
const offset = get("timeZoneName").replace(/^GMT$/, "+00:00").replace(/^GMT/, "");
|
|
35
|
+
return `${get("year")}-${get("month")}-${get("day")}T${get("hour")}:${get("minute")}:${get("second")}${offset || "Z"}`;
|
|
36
|
+
} catch {
|
|
37
|
+
return new Date(now).toISOString();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function renderTemplate(text, context) {
|
|
41
|
+
const json = payloadJson(context.payload);
|
|
42
|
+
return text.replace(/\{\{\s*([a-zA-Z_][a-zA-Z0-9_.-]*)\s*\}\}/g, (whole, name) => {
|
|
43
|
+
if (name === "payload") return context.payload ?? "";
|
|
44
|
+
if (name.startsWith("payload.")) return scalar(lookupPath(json, name.slice("payload.".length).split(".")));
|
|
45
|
+
if (name === "run.id") return context.runId;
|
|
46
|
+
if (name === "automation.name") return context.automationName;
|
|
47
|
+
if (name === "now") return formatNow(context.now ?? Date.now(), context.tz);
|
|
48
|
+
return whole;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function renderAction(action, context) {
|
|
52
|
+
const r = (value) => renderTemplate(value, context);
|
|
53
|
+
if (action.kind === "spawn") return { ...action, prompt: r(action.prompt) };
|
|
54
|
+
if (action.kind === "send") return { ...action, prompt: r(action.prompt) };
|
|
55
|
+
return { ...action, command: action.command.map(r), ...action.env ? { env: Object.fromEntries(Object.entries(action.env).map(([k, v]) => [k, r(v)])) } : {} };
|
|
56
|
+
}
|
|
57
|
+
function clipText(text, maxChars, keep = "head") {
|
|
58
|
+
if (text.length <= maxChars) return text;
|
|
59
|
+
return keep === "head" ? text.slice(0, maxChars) : text.slice(text.length - maxChars);
|
|
60
|
+
}
|
|
61
|
+
const DURATION_UNITS = { ms: 1, s: 1e3, m: 6e4, h: 36e5, d: 864e5 };
|
|
62
|
+
function parseDuration(raw) {
|
|
63
|
+
const text = raw.trim();
|
|
64
|
+
if (/^\d+$/.test(text)) return Number(text);
|
|
65
|
+
const re = /(\d+(?:\.\d+)?)(ms|s|m|h|d)/gy;
|
|
66
|
+
let total = 0;
|
|
67
|
+
let matched = 0;
|
|
68
|
+
let last = 0;
|
|
69
|
+
let m;
|
|
70
|
+
while ((m = re.exec(text)) !== null) {
|
|
71
|
+
total += Number(m[1]) * DURATION_UNITS[m[2]];
|
|
72
|
+
matched++;
|
|
73
|
+
last = re.lastIndex;
|
|
74
|
+
}
|
|
75
|
+
if (matched === 0 || last !== text.length) throw new Error(`Invalid duration: ${raw} (use e.g. 90s, 5m, 1h30m, 2d)`);
|
|
76
|
+
return Math.round(total);
|
|
77
|
+
}
|
|
78
|
+
function formatDuration(ms) {
|
|
79
|
+
if (ms % 864e5 === 0) return `${ms / 864e5}d`;
|
|
80
|
+
if (ms % 36e5 === 0) return `${ms / 36e5}h`;
|
|
81
|
+
if (ms % 6e4 === 0) return `${ms / 6e4}m`;
|
|
82
|
+
if (ms % 1e3 === 0) return `${ms / 1e3}s`;
|
|
83
|
+
return `${ms}ms`;
|
|
84
|
+
}
|
|
85
|
+
function triggerFromFlags(flags, now = Date.now()) {
|
|
86
|
+
const given = [flags.cron !== void 0, flags.every !== void 0, flags.at !== void 0, flags.manual === true].filter(Boolean).length;
|
|
87
|
+
if (given === 0) {
|
|
88
|
+
if (flags.tz !== void 0) throw new Error("--tz only applies with --cron");
|
|
89
|
+
return void 0;
|
|
90
|
+
}
|
|
91
|
+
if (given > 1) throw new Error("Use exactly one of --cron, --every, --at, --manual");
|
|
92
|
+
if (flags.cron !== void 0) {
|
|
93
|
+
if (!flags.tz) throw new Error("--cron requires --tz <IANA zone> (e.g. Asia/Singapore)");
|
|
94
|
+
return { kind: "cron", expr: flags.cron, tz: flags.tz };
|
|
95
|
+
}
|
|
96
|
+
if (flags.tz !== void 0) throw new Error("--tz only applies with --cron");
|
|
97
|
+
if (flags.every !== void 0) return { kind: "interval", everyMs: parseDuration(flags.every), anchorAt: now };
|
|
98
|
+
if (flags.at !== void 0) {
|
|
99
|
+
const at = Date.parse(flags.at);
|
|
100
|
+
if (!Number.isFinite(at)) throw new Error(`--at must be an ISO 8601 timestamp, got: ${flags.at}`);
|
|
101
|
+
return { kind: "once", at };
|
|
102
|
+
}
|
|
103
|
+
return { kind: "manual" };
|
|
104
|
+
}
|
|
105
|
+
function describeTrigger(trigger) {
|
|
106
|
+
switch (trigger.kind) {
|
|
107
|
+
case "cron":
|
|
108
|
+
return `cron ${trigger.expr} (${trigger.tz})`;
|
|
109
|
+
case "interval":
|
|
110
|
+
return `every ${formatDuration(trigger.everyMs)}`;
|
|
111
|
+
case "once":
|
|
112
|
+
return `once at ${new Date(trigger.at).toISOString()}`;
|
|
113
|
+
default:
|
|
114
|
+
return "manual";
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function describeAction(action) {
|
|
118
|
+
if (action.kind === "spawn") return `spawn ${action.agent} in ${action.directory}${action.sticky ? ` (sticky ${action.sticky.key})` : ""}`;
|
|
119
|
+
if (action.kind === "send") return `send to session ${action.sessionId}`;
|
|
120
|
+
return `script ${action.command.join(" ")}`;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
exports.clipText = clipText;
|
|
124
|
+
exports.describeAction = describeAction;
|
|
125
|
+
exports.describeTrigger = describeTrigger;
|
|
126
|
+
exports.parseDuration = parseDuration;
|
|
127
|
+
exports.renderAction = renderAction;
|
|
128
|
+
exports.renderTemplate = renderTemplate;
|
|
129
|
+
exports.triggerFromFlags = triggerFromFlags;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
function payloadJson(payload) {
|
|
2
|
+
if (!payload) return void 0;
|
|
3
|
+
try {
|
|
4
|
+
return JSON.parse(payload);
|
|
5
|
+
} catch {
|
|
6
|
+
return void 0;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
function lookupPath(root, path) {
|
|
10
|
+
let current = root;
|
|
11
|
+
for (const segment of path) {
|
|
12
|
+
if (current === null || typeof current !== "object") return void 0;
|
|
13
|
+
current = current[segment];
|
|
14
|
+
}
|
|
15
|
+
return current;
|
|
16
|
+
}
|
|
17
|
+
function scalar(value) {
|
|
18
|
+
if (value === void 0 || value === null) return "";
|
|
19
|
+
if (typeof value === "string") return value;
|
|
20
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
21
|
+
try {
|
|
22
|
+
return JSON.stringify(value);
|
|
23
|
+
} catch {
|
|
24
|
+
return "";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function formatNow(now, tz) {
|
|
28
|
+
if (!tz) return new Date(now).toISOString();
|
|
29
|
+
try {
|
|
30
|
+
const parts = new Intl.DateTimeFormat("en-CA", { timeZone: tz, hourCycle: "h23", year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit", timeZoneName: "longOffset" }).formatToParts(new Date(now));
|
|
31
|
+
const get = (type) => parts.find((p) => p.type === type)?.value ?? "";
|
|
32
|
+
const offset = get("timeZoneName").replace(/^GMT$/, "+00:00").replace(/^GMT/, "");
|
|
33
|
+
return `${get("year")}-${get("month")}-${get("day")}T${get("hour")}:${get("minute")}:${get("second")}${offset || "Z"}`;
|
|
34
|
+
} catch {
|
|
35
|
+
return new Date(now).toISOString();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function renderTemplate(text, context) {
|
|
39
|
+
const json = payloadJson(context.payload);
|
|
40
|
+
return text.replace(/\{\{\s*([a-zA-Z_][a-zA-Z0-9_.-]*)\s*\}\}/g, (whole, name) => {
|
|
41
|
+
if (name === "payload") return context.payload ?? "";
|
|
42
|
+
if (name.startsWith("payload.")) return scalar(lookupPath(json, name.slice("payload.".length).split(".")));
|
|
43
|
+
if (name === "run.id") return context.runId;
|
|
44
|
+
if (name === "automation.name") return context.automationName;
|
|
45
|
+
if (name === "now") return formatNow(context.now ?? Date.now(), context.tz);
|
|
46
|
+
return whole;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function renderAction(action, context) {
|
|
50
|
+
const r = (value) => renderTemplate(value, context);
|
|
51
|
+
if (action.kind === "spawn") return { ...action, prompt: r(action.prompt) };
|
|
52
|
+
if (action.kind === "send") return { ...action, prompt: r(action.prompt) };
|
|
53
|
+
return { ...action, command: action.command.map(r), ...action.env ? { env: Object.fromEntries(Object.entries(action.env).map(([k, v]) => [k, r(v)])) } : {} };
|
|
54
|
+
}
|
|
55
|
+
function clipText(text, maxChars, keep = "head") {
|
|
56
|
+
if (text.length <= maxChars) return text;
|
|
57
|
+
return keep === "head" ? text.slice(0, maxChars) : text.slice(text.length - maxChars);
|
|
58
|
+
}
|
|
59
|
+
const DURATION_UNITS = { ms: 1, s: 1e3, m: 6e4, h: 36e5, d: 864e5 };
|
|
60
|
+
function parseDuration(raw) {
|
|
61
|
+
const text = raw.trim();
|
|
62
|
+
if (/^\d+$/.test(text)) return Number(text);
|
|
63
|
+
const re = /(\d+(?:\.\d+)?)(ms|s|m|h|d)/gy;
|
|
64
|
+
let total = 0;
|
|
65
|
+
let matched = 0;
|
|
66
|
+
let last = 0;
|
|
67
|
+
let m;
|
|
68
|
+
while ((m = re.exec(text)) !== null) {
|
|
69
|
+
total += Number(m[1]) * DURATION_UNITS[m[2]];
|
|
70
|
+
matched++;
|
|
71
|
+
last = re.lastIndex;
|
|
72
|
+
}
|
|
73
|
+
if (matched === 0 || last !== text.length) throw new Error(`Invalid duration: ${raw} (use e.g. 90s, 5m, 1h30m, 2d)`);
|
|
74
|
+
return Math.round(total);
|
|
75
|
+
}
|
|
76
|
+
function formatDuration(ms) {
|
|
77
|
+
if (ms % 864e5 === 0) return `${ms / 864e5}d`;
|
|
78
|
+
if (ms % 36e5 === 0) return `${ms / 36e5}h`;
|
|
79
|
+
if (ms % 6e4 === 0) return `${ms / 6e4}m`;
|
|
80
|
+
if (ms % 1e3 === 0) return `${ms / 1e3}s`;
|
|
81
|
+
return `${ms}ms`;
|
|
82
|
+
}
|
|
83
|
+
function triggerFromFlags(flags, now = Date.now()) {
|
|
84
|
+
const given = [flags.cron !== void 0, flags.every !== void 0, flags.at !== void 0, flags.manual === true].filter(Boolean).length;
|
|
85
|
+
if (given === 0) {
|
|
86
|
+
if (flags.tz !== void 0) throw new Error("--tz only applies with --cron");
|
|
87
|
+
return void 0;
|
|
88
|
+
}
|
|
89
|
+
if (given > 1) throw new Error("Use exactly one of --cron, --every, --at, --manual");
|
|
90
|
+
if (flags.cron !== void 0) {
|
|
91
|
+
if (!flags.tz) throw new Error("--cron requires --tz <IANA zone> (e.g. Asia/Singapore)");
|
|
92
|
+
return { kind: "cron", expr: flags.cron, tz: flags.tz };
|
|
93
|
+
}
|
|
94
|
+
if (flags.tz !== void 0) throw new Error("--tz only applies with --cron");
|
|
95
|
+
if (flags.every !== void 0) return { kind: "interval", everyMs: parseDuration(flags.every), anchorAt: now };
|
|
96
|
+
if (flags.at !== void 0) {
|
|
97
|
+
const at = Date.parse(flags.at);
|
|
98
|
+
if (!Number.isFinite(at)) throw new Error(`--at must be an ISO 8601 timestamp, got: ${flags.at}`);
|
|
99
|
+
return { kind: "once", at };
|
|
100
|
+
}
|
|
101
|
+
return { kind: "manual" };
|
|
102
|
+
}
|
|
103
|
+
function describeTrigger(trigger) {
|
|
104
|
+
switch (trigger.kind) {
|
|
105
|
+
case "cron":
|
|
106
|
+
return `cron ${trigger.expr} (${trigger.tz})`;
|
|
107
|
+
case "interval":
|
|
108
|
+
return `every ${formatDuration(trigger.everyMs)}`;
|
|
109
|
+
case "once":
|
|
110
|
+
return `once at ${new Date(trigger.at).toISOString()}`;
|
|
111
|
+
default:
|
|
112
|
+
return "manual";
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function describeAction(action) {
|
|
116
|
+
if (action.kind === "spawn") return `spawn ${action.agent} in ${action.directory}${action.sticky ? ` (sticky ${action.sticky.key})` : ""}`;
|
|
117
|
+
if (action.kind === "send") return `send to session ${action.sessionId}`;
|
|
118
|
+
return `script ${action.command.join(" ")}`;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export { describeAction as a, renderTemplate as b, clipText as c, describeTrigger as d, parseDuration as p, renderAction as r, triggerFromFlags as t };
|
|
@@ -1,13 +1,5 @@
|
|
|
1
|
-
import { dirname, resolve } from 'path';
|
|
2
|
-
import { fileURLToPath } from 'url';
|
|
3
1
|
import { z } from 'zod';
|
|
4
2
|
|
|
5
|
-
const __dirname$1 = dirname(fileURLToPath(import.meta.url));
|
|
6
|
-
function projectPath() {
|
|
7
|
-
const path = resolve(__dirname$1, "..");
|
|
8
|
-
return path;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
3
|
const TERMINAL_TITLE_SUGGEST_METHOD = "very-happy/terminal-title-suggest";
|
|
12
4
|
const TerminalTitleSuggestRequestSchema = z.object({
|
|
13
5
|
method: z.literal(TERMINAL_TITLE_SUGGEST_METHOD),
|
|
@@ -35,4 +27,4 @@ function piSessionNameFromTitle(title, cwd) {
|
|
|
35
27
|
return name || void 0;
|
|
36
28
|
}
|
|
37
29
|
|
|
38
|
-
export { TERMINAL_TITLE_SUGGEST_METHOD as T, TerminalTitleSuggestResultSchema as a, TerminalTitleSuggestRequestSchema as b, piSessionNameFromTitle as
|
|
30
|
+
export { TERMINAL_TITLE_SUGGEST_METHOD as T, TerminalTitleSuggestResultSchema as a, TerminalTitleSuggestRequestSchema as b, piSessionNameFromTitle as p };
|
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var path = require('path');
|
|
4
|
-
var url = require('url');
|
|
5
3
|
var z = require('zod');
|
|
6
4
|
|
|
7
|
-
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
8
|
-
const __dirname$1 = path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('terminalTitleSuggest-Dji8I0Jy.cjs', document.baseURI).href))));
|
|
9
|
-
function projectPath() {
|
|
10
|
-
const path$1 = path.resolve(__dirname$1, "..");
|
|
11
|
-
return path$1;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
5
|
const TERMINAL_TITLE_SUGGEST_METHOD = "very-happy/terminal-title-suggest";
|
|
15
6
|
const TerminalTitleSuggestRequestSchema = z.z.object({
|
|
16
7
|
method: z.z.literal(TERMINAL_TITLE_SUGGEST_METHOD),
|
|
@@ -42,4 +33,3 @@ exports.TERMINAL_TITLE_SUGGEST_METHOD = TERMINAL_TITLE_SUGGEST_METHOD;
|
|
|
42
33
|
exports.TerminalTitleSuggestRequestSchema = TerminalTitleSuggestRequestSchema;
|
|
43
34
|
exports.TerminalTitleSuggestResultSchema = TerminalTitleSuggestResultSchema;
|
|
44
35
|
exports.piSessionNameFromTitle = piSessionNameFromTitle;
|
|
45
|
-
exports.projectPath = projectPath;
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var os = require('node:os');
|
|
4
|
+
var node_child_process = require('node:child_process');
|
|
5
|
+
var terminalTitleSuggest = require('./terminalTitleSuggest-DhvRFX3H.cjs');
|
|
6
|
+
var tmuxSocket = require('./tmuxSocket-D-Xt6Vn-.cjs');
|
|
7
|
+
|
|
8
|
+
const USER_SESSION_FIELD_SEP = "<~|~>";
|
|
9
|
+
const USER_SESSIONS_FORMAT = [
|
|
10
|
+
"#{session_id}",
|
|
11
|
+
"#{session_name}",
|
|
12
|
+
"#{session_windows}",
|
|
13
|
+
"#{session_attached}",
|
|
14
|
+
"#{session_activity}",
|
|
15
|
+
"#{session_created}",
|
|
16
|
+
"#{pane_current_command}",
|
|
17
|
+
"#{pane_current_path}"
|
|
18
|
+
].join(USER_SESSION_FIELD_SEP);
|
|
19
|
+
const TMUX_SESSION_ID_RE = /^\$\d{1,9}$/;
|
|
20
|
+
const TMUX_SESSION_NAME_MAX = 128;
|
|
21
|
+
function isSafeTmuxSessionName(name) {
|
|
22
|
+
if (typeof name !== "string") return false;
|
|
23
|
+
if (name.length === 0 || name.length > TMUX_SESSION_NAME_MAX) return false;
|
|
24
|
+
return !/[\x00-\x1f\x7f]/.test(name);
|
|
25
|
+
}
|
|
26
|
+
function isVhSessionName(name) {
|
|
27
|
+
return name.startsWith("vh-");
|
|
28
|
+
}
|
|
29
|
+
function parseUserSessionLine(line) {
|
|
30
|
+
if (!line) return void 0;
|
|
31
|
+
const parts = line.split(USER_SESSION_FIELD_SEP);
|
|
32
|
+
if (parts.length < 8) return void 0;
|
|
33
|
+
const [id, name, windows, attached, activity, created, command] = parts;
|
|
34
|
+
if (!TMUX_SESSION_ID_RE.test(id) || !isSafeTmuxSessionName(name)) return void 0;
|
|
35
|
+
const cwd = parts.slice(7).join(USER_SESSION_FIELD_SEP);
|
|
36
|
+
const num = (v) => {
|
|
37
|
+
const n = Number(v);
|
|
38
|
+
return Number.isFinite(n) ? n : void 0;
|
|
39
|
+
};
|
|
40
|
+
return {
|
|
41
|
+
id,
|
|
42
|
+
name,
|
|
43
|
+
windows: Math.max(0, Math.floor(num(windows) ?? 0)),
|
|
44
|
+
attached: (num(attached) ?? 0) > 0,
|
|
45
|
+
activityAt: activity ? (num(activity) ?? 0) * 1e3 || void 0 : void 0,
|
|
46
|
+
createdAt: created ? (num(created) ?? 0) * 1e3 || void 0 : void 0,
|
|
47
|
+
command: command.trim() || void 0,
|
|
48
|
+
cwd: cwd || void 0
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const USER_SESSIONS_MAX = 50;
|
|
52
|
+
function parseUserSessions(stdout, max = USER_SESSIONS_MAX) {
|
|
53
|
+
const out = [];
|
|
54
|
+
for (const line of stdout.split("\n")) {
|
|
55
|
+
const s = parseUserSessionLine(line);
|
|
56
|
+
if (!s || isVhSessionName(s.name)) continue;
|
|
57
|
+
out.push(s);
|
|
58
|
+
}
|
|
59
|
+
out.sort((a, b) => (b.activityAt ?? 0) - (a.activityAt ?? 0));
|
|
60
|
+
return out.slice(0, max);
|
|
61
|
+
}
|
|
62
|
+
function attachStartupCommand(sessionId, socket) {
|
|
63
|
+
if (!TMUX_SESSION_ID_RE.test(sessionId)) throw new Error(`not a tmux session id: ${sessionId}`);
|
|
64
|
+
const sock = socket ? ` -S ${tmuxSocket.shellescape(socket)}` : "";
|
|
65
|
+
return ` TMUX= tmux${sock} attach-session -t ${tmuxSocket.shellescape(sessionId)}`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const SHELL_COMMANDS = /* @__PURE__ */ new Set(["zsh", "bash", "fish", "sh", "dash", "ksh", "tcsh", "csh"]);
|
|
69
|
+
const TITLE_MAX_CHARS = 60;
|
|
70
|
+
const JUNK_TITLES = /* @__PURE__ */ new Set(["tmux", "claude", "node", ...SHELL_COMMANDS]);
|
|
71
|
+
function deriveAutoTitle(paneTitle, hostname, cwd) {
|
|
72
|
+
if (typeof paneTitle !== "string") return void 0;
|
|
73
|
+
const t = paneTitle.replace(/^[^\p{L}\p{N}]+/u, "").replace(/\s+/g, " ").trim();
|
|
74
|
+
if (!t) return void 0;
|
|
75
|
+
const piName = terminalTitleSuggest.piSessionNameFromTitle(t, cwd);
|
|
76
|
+
if (piName) {
|
|
77
|
+
const chars2 = Array.from(piName);
|
|
78
|
+
return chars2.length > TITLE_MAX_CHARS ? chars2.slice(0, TITLE_MAX_CHARS).join("") : piName;
|
|
79
|
+
}
|
|
80
|
+
const lower = t.toLowerCase();
|
|
81
|
+
const host = (hostname || "").toLowerCase();
|
|
82
|
+
const shortHost = host.split(".")[0];
|
|
83
|
+
if (host && (lower === host || lower === shortHost)) return void 0;
|
|
84
|
+
if (JUNK_TITLES.has(lower)) return void 0;
|
|
85
|
+
const chars = Array.from(t);
|
|
86
|
+
return chars.length > TITLE_MAX_CHARS ? chars.slice(0, TITLE_MAX_CHARS).join("") : t;
|
|
87
|
+
}
|
|
88
|
+
const LIST_FIELD_SEP = "<~|~>";
|
|
89
|
+
const LIST_SESSIONS_FORMAT = [
|
|
90
|
+
"#{session_name}",
|
|
91
|
+
"#{session_created}",
|
|
92
|
+
"#{session_activity}",
|
|
93
|
+
"#{pane_current_path}",
|
|
94
|
+
"#{@vh_title}",
|
|
95
|
+
"#{@vh_title_manual}",
|
|
96
|
+
"#{@vh_tags}",
|
|
97
|
+
// B-273: the user tmux session this terminal was opened to attach (name),
|
|
98
|
+
// carried into close records so a restore can re-attach.
|
|
99
|
+
"#{@vh_attach}",
|
|
100
|
+
// B-287: the pane's REAL geometry, persisted with the live snapshot so a
|
|
101
|
+
// cold restore (daemon boot auto-restore, archive ↻) recreates the session
|
|
102
|
+
// at the size it last had — claude's one-shot welcome banner then never
|
|
103
|
+
// gets reflowed by the first web open (the "half-drawn logo").
|
|
104
|
+
"#{pane_width}",
|
|
105
|
+
"#{pane_height}",
|
|
106
|
+
// B-121: the control-mode client has no `pty.process`, so the agent-state
|
|
107
|
+
// fast path lost its live `#{pane_current_command}` equivalent. Carry it in
|
|
108
|
+
// the ONE list-sessions call the tracker already makes — the value goes
|
|
109
|
+
// from "live" to "≤ LIST_TRACK_INTERVAL_MS old", which classifyPane
|
|
110
|
+
// tolerates (its dialog/working judgments come from the pane TEXT; the
|
|
111
|
+
// command only separates shell/idle). MUST stay before pane_title: that
|
|
112
|
+
// field is deliberately last so a pathological 0x1f inside a title can only
|
|
113
|
+
// garble the title, never shift the fields.
|
|
114
|
+
"#{pane_current_command} #{pane_pid}",
|
|
115
|
+
"#{pane_title}"
|
|
116
|
+
].join(LIST_FIELD_SEP);
|
|
117
|
+
function parseSessionListLine(line) {
|
|
118
|
+
if (!line) return void 0;
|
|
119
|
+
const parts = line.split(LIST_FIELD_SEP);
|
|
120
|
+
if (parts.length < 12) return void 0;
|
|
121
|
+
const [name, created, activity, cwd, vhTitle, manual, vhTags, vhAttach, paneW, paneH, paneCommand] = parts;
|
|
122
|
+
if (!name) return void 0;
|
|
123
|
+
const geom = parsePositiveInt(paneW) !== void 0 && parsePositiveInt(paneH) !== void 0 ? { paneCols: parsePositiveInt(paneW), paneRows: parsePositiveInt(paneH) } : {};
|
|
124
|
+
return {
|
|
125
|
+
name,
|
|
126
|
+
created: created ? Number(created) * 1e3 : void 0,
|
|
127
|
+
activity: activity ? Number(activity) * 1e3 : void 0,
|
|
128
|
+
cwd: cwd || void 0,
|
|
129
|
+
vhTitle: vhTitle.trim() || void 0,
|
|
130
|
+
manual: manual.trim().length > 0,
|
|
131
|
+
tags: parseTerminalTags(vhTags),
|
|
132
|
+
paneCurrentCommand: paneCommand.trim().replace(/ \d+$/, "") || void 0,
|
|
133
|
+
.../ (\d+)$/.test(paneCommand) ? { panePid: Number(paneCommand.match(/ (\d+)$/)[1]) } : {},
|
|
134
|
+
// Verbatim (no trim): tmux allows edge spaces in a session name and the
|
|
135
|
+
// restore lookup / attach echo compare it exactly.
|
|
136
|
+
attachTmux: isSafeTmuxSessionName(vhAttach) ? vhAttach : void 0,
|
|
137
|
+
...geom,
|
|
138
|
+
// pane_title is last, so anything after field 11 is title content that
|
|
139
|
+
// contained the separator — rejoin it rather than dropping it.
|
|
140
|
+
paneTitle: parts.slice(11).join(LIST_FIELD_SEP) || void 0
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function parsePositiveInt(raw) {
|
|
144
|
+
if (raw === void 0 || !/^[0-9]{1,5}$/.test(raw.trim())) return void 0;
|
|
145
|
+
const n = Number(raw.trim());
|
|
146
|
+
return n > 0 ? n : void 0;
|
|
147
|
+
}
|
|
148
|
+
const TERMINAL_TAG_MAX_COUNT = 64;
|
|
149
|
+
const TERMINAL_TAG_MAX_LENGTH = 24;
|
|
150
|
+
const TERMINAL_TAGS_MAX_BYTES = 4096;
|
|
151
|
+
function validateTerminalTags(value) {
|
|
152
|
+
if (!Array.isArray(value) || value.length > TERMINAL_TAG_MAX_COUNT) return void 0;
|
|
153
|
+
const seen = /* @__PURE__ */ new Set();
|
|
154
|
+
const out = [];
|
|
155
|
+
for (const valueTag of value) {
|
|
156
|
+
if (typeof valueTag !== "string") return void 0;
|
|
157
|
+
const tag = valueTag.trim().replace(/^#+/, "").trim().replace(/\s+/g, "-").slice(0, TERMINAL_TAG_MAX_LENGTH);
|
|
158
|
+
if (!tag || tag !== valueTag) return void 0;
|
|
159
|
+
const key = tag.toLowerCase();
|
|
160
|
+
if (seen.has(key)) return void 0;
|
|
161
|
+
seen.add(key);
|
|
162
|
+
out.push(tag);
|
|
163
|
+
}
|
|
164
|
+
if (Buffer.byteLength(JSON.stringify(out), "utf8") > TERMINAL_TAGS_MAX_BYTES) return void 0;
|
|
165
|
+
return out;
|
|
166
|
+
}
|
|
167
|
+
function parseTerminalTags(raw) {
|
|
168
|
+
if (typeof raw !== "string" || !raw.trim()) return [];
|
|
169
|
+
try {
|
|
170
|
+
return validateTerminalTags(JSON.parse(raw)) ?? [];
|
|
171
|
+
} catch {
|
|
172
|
+
return [];
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const TMUX_TIMEOUT_MS = 3e3;
|
|
177
|
+
const VH_LIST_SESSIONS_FORMAT = LIST_SESSIONS_FORMAT;
|
|
178
|
+
function parseVhTerminals(stdout, hostname = os.hostname()) {
|
|
179
|
+
const out = [];
|
|
180
|
+
for (const line of stdout.split("\n")) {
|
|
181
|
+
const s = parseSessionListLine(line);
|
|
182
|
+
if (!s || !s.name.startsWith("vh-")) continue;
|
|
183
|
+
out.push({
|
|
184
|
+
id: s.name.slice(3),
|
|
185
|
+
title: s.vhTitle ?? deriveAutoTitle(s.paneTitle, hostname, s.cwd),
|
|
186
|
+
cwd: s.cwd,
|
|
187
|
+
createdAt: s.created,
|
|
188
|
+
activityAt: s.activity
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return out;
|
|
192
|
+
}
|
|
193
|
+
function runTmux(args, input) {
|
|
194
|
+
try {
|
|
195
|
+
const r = node_child_process.spawnSync("tmux", tmuxSocket.tmuxArgs(args), {
|
|
196
|
+
encoding: "utf8",
|
|
197
|
+
timeout: TMUX_TIMEOUT_MS,
|
|
198
|
+
input,
|
|
199
|
+
env: tmuxSocket.scrubTmuxClientEnv({ ...process.env })
|
|
200
|
+
});
|
|
201
|
+
if (r.error) return { ok: false, stdout: "", error: r.error.message };
|
|
202
|
+
if (r.status !== 0) return { ok: false, stdout: r.stdout ?? "", error: (r.stderr || `tmux exited with ${r.status}`).trim() };
|
|
203
|
+
return { ok: true, stdout: r.stdout ?? "" };
|
|
204
|
+
} catch (error) {
|
|
205
|
+
return { ok: false, stdout: "", error: error instanceof Error ? error.message : String(error) };
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
function listVhTerminals() {
|
|
209
|
+
const r = runTmux(["list-sessions", "-F", VH_LIST_SESSIONS_FORMAT]);
|
|
210
|
+
if (!r.ok) {
|
|
211
|
+
if ((r.error ?? "").includes("no server running")) return { ok: true, terminals: [] };
|
|
212
|
+
return { ok: false, terminals: [], error: r.error };
|
|
213
|
+
}
|
|
214
|
+
return { ok: true, terminals: parseVhTerminals(r.stdout) };
|
|
215
|
+
}
|
|
216
|
+
function target(terminalId) {
|
|
217
|
+
return `=vh-${terminalId}:`;
|
|
218
|
+
}
|
|
219
|
+
function readVhTerminal(terminalId, lines) {
|
|
220
|
+
const n = Math.max(1, Math.min(2e3, Math.floor(lines)));
|
|
221
|
+
const r = runTmux(["capture-pane", "-p", "-t", target(terminalId), "-S", `-${n}`]);
|
|
222
|
+
return { ok: r.ok, text: r.stdout, error: r.error };
|
|
223
|
+
}
|
|
224
|
+
const PASTE_BUFFER_NAME = "vh-assistant-paste";
|
|
225
|
+
function sendToVhTerminal(terminalId, text, submit) {
|
|
226
|
+
const load = runTmux(["load-buffer", "-b", PASTE_BUFFER_NAME, "-"], text);
|
|
227
|
+
if (!load.ok) return { ok: false, error: `load-buffer failed: ${load.error}` };
|
|
228
|
+
const paste = runTmux(["paste-buffer", "-p", "-d", "-b", PASTE_BUFFER_NAME, "-t", target(terminalId)]);
|
|
229
|
+
if (!paste.ok) return { ok: false, error: `paste-buffer failed: ${paste.error}` };
|
|
230
|
+
if (submit) {
|
|
231
|
+
const enter = runTmux(["send-keys", "-t", target(terminalId), "Enter"]);
|
|
232
|
+
if (!enter.ok) return { ok: false, error: `send-keys Enter failed: ${enter.error}` };
|
|
233
|
+
}
|
|
234
|
+
return { ok: true };
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
exports.LIST_FIELD_SEP = LIST_FIELD_SEP;
|
|
238
|
+
exports.LIST_SESSIONS_FORMAT = LIST_SESSIONS_FORMAT;
|
|
239
|
+
exports.TMUX_SESSION_ID_RE = TMUX_SESSION_ID_RE;
|
|
240
|
+
exports.USER_SESSIONS_FORMAT = USER_SESSIONS_FORMAT;
|
|
241
|
+
exports.attachStartupCommand = attachStartupCommand;
|
|
242
|
+
exports.deriveAutoTitle = deriveAutoTitle;
|
|
243
|
+
exports.isSafeTmuxSessionName = isSafeTmuxSessionName;
|
|
244
|
+
exports.isVhSessionName = isVhSessionName;
|
|
245
|
+
exports.listVhTerminals = listVhTerminals;
|
|
246
|
+
exports.parseSessionListLine = parseSessionListLine;
|
|
247
|
+
exports.parseUserSessions = parseUserSessions;
|
|
248
|
+
exports.readVhTerminal = readVhTerminal;
|
|
249
|
+
exports.sendToVhTerminal = sendToVhTerminal;
|
|
250
|
+
exports.validateTerminalTags = validateTerminalTags;
|