very-happy-cli 0.2.178 → 0.2.179
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{AcpBackend-DCQXHRzT.mjs → AcpBackend-CHp3y7cb.mjs} +135 -16
- package/dist/{AcpBackend-CDkAQXYf.cjs → AcpBackend-DFipFF7-.cjs} +135 -16
- package/dist/{AcpSessionManager-DckmUZza.cjs → AcpSessionManager-0zpvRJXc.cjs} +38 -4
- package/dist/{AcpSessionManager-BXrQcqwC.mjs → AcpSessionManager-d2-rKWWa.mjs} +38 -4
- package/dist/{BasePermissionHandler-DyLmKKtO.cjs → BasePermissionHandler-CH3zuEkA.cjs} +5 -2
- package/dist/{BasePermissionHandler-BVlrEhIi.mjs → BasePermissionHandler-DdZBYIR4.mjs} +5 -2
- package/dist/acpSessionResume-DTGmAPLt.mjs +67 -0
- package/dist/acpSessionResume-oiCBnAVA.cjs +74 -0
- package/dist/{agentHome-CEp9RMyK.cjs → agentHome-BWcz8mz0.cjs} +4 -4
- package/dist/{agentHome-C1xi37as.mjs → agentHome-CghLvL_1.mjs} +4 -4
- package/dist/{api-JANhFdZV.cjs → api-Cmjfr8Z7.cjs} +28 -260
- package/dist/{api-Dib0dmqC.mjs → api-CzwFpJQc.mjs} +21 -253
- package/dist/{apiMachine-DNTJidYH.mjs → apiMachine-DJkTEiqy.mjs} +43 -15
- package/dist/{apiMachine-QhK-sKcr.cjs → apiMachine-G6OogT08.cjs} +43 -15
- package/dist/{attachmentContent-DkkdpSSJ.mjs → attachmentContent-B2os4HbA.mjs} +2 -2
- package/dist/{attachmentContent-bpQTBJ0y.cjs → attachmentContent-Bo0UAsSu.cjs} +4 -4
- package/dist/{auth-BRjd2esb.mjs → auth-BS6PaOOG.mjs} +5 -5
- package/dist/{auth-DgIV0Cvt.cjs → auth-D6bBUwZa.cjs} +5 -5
- package/dist/{auth-DNct7VUi.mjs → auth-DMX0xPNK.mjs} +8 -8
- package/dist/{auth-omWDtgR8.cjs → auth-HEhRaNgL.cjs} +8 -8
- package/dist/{auto-CI16FZmX.cjs → auto-C6I55iOh.cjs} +18 -17
- package/dist/{auto-DKGFOJBo.mjs → auto-Cl1SEDcD.mjs} +18 -17
- package/dist/{bootstrap-DCQ87Aan.cjs → bootstrap-exVucYav.cjs} +2 -2
- package/dist/{bootstrap-BUagGC_-.mjs → bootstrap-iuyufnp3.mjs} +2 -2
- package/dist/{browser-CSKhc0Bl.cjs → browser-BohJK12g.cjs} +1 -1
- package/dist/{browser-Dj_DYQEh.mjs → browser-CSYum7xH.mjs} +1 -1
- package/dist/{claudeLocal-CCCvAeMd.mjs → claudeLocal-Dq_R3Ax_.mjs} +6 -5
- package/dist/{claudeLocal-CdIVnOZp.cjs → claudeLocal-re4yjSTx.cjs} +6 -5
- package/dist/{claudeLocalLauncher-21-xh5gc.cjs → claudeLocalLauncher-B4hJHpCA.cjs} +11 -10
- package/dist/{claudeLocalLauncher-BmrpaRYJ.mjs → claudeLocalLauncher-CN67lN7-.mjs} +11 -10
- package/dist/{claudeSessionFork-DvxMKAmY.mjs → claudeSessionFork-BihfD0Ik.mjs} +1 -1
- package/dist/{claudeSessionFork-kYCP1IJB.cjs → claudeSessionFork-DiSMYerV.cjs} +1 -1
- package/dist/{client-Dnza1hgN.cjs → client-BKcK1Bi-.cjs} +3 -3
- package/dist/client-BhoEBnuN.mjs +71 -0
- package/dist/{client-C4zKGjiJ.cjs → client-CuVdN6PP.cjs} +2 -2
- package/dist/{client-BTX9hsbr.mjs → client-DuTDwWSQ.mjs} +3 -3
- package/dist/client-ZjOsn6nZ.cjs +76 -0
- package/dist/{client-CnlkkrZO.mjs → client-wo9nbxuf.mjs} +2 -2
- package/dist/codex/happyMcpStdioBridge.cjs +24 -15
- package/dist/codex/happyMcpStdioBridge.mjs +24 -15
- package/dist/{codexAppServerClient-DvkpQgyv.mjs → codexAppServerClient-BK3zra_1.mjs} +3 -3
- package/dist/{codexAppServerClient-CRlBWGn3.cjs → codexAppServerClient-Dt5zxrun.cjs} +3 -3
- package/dist/{codexCommand-BxjogBzU.mjs → codexCommand-B6pY7CMh.mjs} +65 -60
- package/dist/{codexCommand-DzxIWXIT.cjs → codexCommand-CAZ1SLjg.cjs} +88 -83
- package/dist/{codexTermination-ySDNMEhd.mjs → codexTermination-Cd1Eon_4.mjs} +1 -1
- package/dist/{codexTermination-C28FzlLb.cjs → codexTermination-DmGbHxcD.cjs} +1 -1
- package/dist/{config-DwfEpFr3.mjs → config-2oMG_fEI.mjs} +3 -3
- package/dist/{config-BFB5uJ4t.cjs → config-B0uK6K7n.cjs} +3 -3
- package/dist/{configuration-4TGMrjul.cjs → configuration-CMHZnp6G.cjs} +1 -1
- package/dist/{configuration-DVrb61aY.mjs → configuration-WMi4idBB.mjs} +1 -1
- package/dist/{connect-C7FPY0PI.mjs → connect-BLVHhHzA.mjs} +14 -14
- package/dist/{connect-QH2VJGBG.cjs → connect-uaglGrde.cjs} +14 -14
- package/dist/{context-JoKu0V54.cjs → context-DXzU5bFM.cjs} +1 -1
- package/dist/{context-B3XPVJlj.mjs → context-DploEcoN.mjs} +1 -1
- package/dist/{controlClient-BYKyGyxj.mjs → controlClient-BWUJrj3t.mjs} +3 -3
- package/dist/{controlClient-BTaZlbC6.cjs → controlClient-C-5qCt8W.cjs} +3 -3
- package/dist/{createSessionMetadata-8Fuj2-IV.mjs → createSessionMetadata-3uXrJgOW.mjs} +2 -2
- package/dist/{createSessionMetadata-B2NynaWZ.cjs → createSessionMetadata-BkIzHALd.cjs} +2 -2
- package/dist/{defaultPermissionMode-B8kJG9uI.mjs → defaultPermissionMode-BzxLh20a.mjs} +2 -2
- package/dist/{defaultPermissionMode-BEWCqJU-.cjs → defaultPermissionMode-pS3vmiSg.cjs} +2 -2
- package/dist/{deterministicJson-BjNQsAjO.cjs → deterministicJson-B8z2GPi9.cjs} +220 -14
- package/dist/{deterministicJson-C5ZwZ7hu.mjs → deterministicJson-D_whDMFd.mjs} +217 -12
- package/dist/{doctor-BshRnjLi.cjs → doctor-Br1Kcy2J.cjs} +7 -7
- package/dist/{doctor-0BiGwJXk.mjs → doctor-CmtSsR2-.mjs} +7 -7
- package/dist/{downloadTarget-BN5vZt3K.cjs → downloadTarget-BQJK_6oH.cjs} +6 -6
- package/dist/{downloadTarget-DJPwAZlu.mjs → downloadTarget-BoNwTIH_.mjs} +6 -6
- package/dist/{ensureDaemonRunning-C5QfToCe.cjs → ensureDaemonRunning-BRUmsq6J.cjs} +5 -5
- package/dist/{ensureDaemonRunning-CSmb_mqt.mjs → ensureDaemonRunning-Czo9IHJQ.mjs} +5 -5
- package/dist/{handleResumeCommand-CgjpsdDe.mjs → handleResumeCommand-C8thKjqf.mjs} +21 -5
- package/dist/{handleResumeCommand-BwnUZmbo.cjs → handleResumeCommand-tKD_Hpxc.cjs} +21 -5
- package/dist/{index-BYOZ_8WZ.cjs → index-B0UjHlAe.cjs} +4 -4
- package/dist/{index-BehVbAsA.mjs → index-BTxHphpV.mjs} +254 -49
- package/dist/index-BiyC7cZ3.mjs +18 -0
- package/dist/{index-_l1Sdmbi.cjs → index-C6O2vVjm.cjs} +154 -33
- package/dist/index-CUuc6iCn.cjs +24 -0
- package/dist/{index-Bvldtdny.mjs → index-CdQI0C9p.mjs} +4 -4
- package/dist/{index-BRClDe07.cjs → index-D09T1m8Y.cjs} +3 -3
- package/dist/{index-BYgfern_.mjs → index-D3bidoG8.mjs} +3 -3
- package/dist/{index-piJPsTsm.cjs → index-DMqDMT1Q.cjs} +256 -51
- package/dist/{index-Clqlu17M.mjs → index-DPOa4NhL.mjs} +153 -34
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/dist/{install-BdvKiOQw.mjs → install-BX3lv3NO.mjs} +1 -1
- package/dist/{install-Cf6AFSWC.cjs → install-BXvf2E3o.cjs} +1 -1
- package/dist/{install-TO4taKW7.cjs → install-CYRZxS87.cjs} +3 -3
- package/dist/{install-fYWHrPcC.mjs → install-hnve_9vq.mjs} +3 -3
- package/dist/lib.cjs +13 -13
- package/dist/lib.d.cts +62 -1
- package/dist/lib.d.mts +62 -1
- package/dist/lib.mjs +13 -13
- package/dist/{lidState-DNMlIhX0.mjs → lidState-Bb8fgXg3.mjs} +1 -1
- package/dist/{lidState-BeOwj6eW.cjs → lidState-Dv2wwFTj.cjs} +1 -1
- package/dist/{localHappyAgentAuth-Br-mgogg.cjs → localHappyAgentAuth-DjYvkXvV.cjs} +1 -1
- package/dist/{localHappyAgentAuth-BezKSFDi.mjs → localHappyAgentAuth-NEU7fax7.mjs} +1 -1
- package/dist/{logger--vAVtXB_.mjs → logger-BtVhHnD8.mjs} +2 -2
- package/dist/{logger-DXTWlPzP.cjs → logger-C1GWx3gi.cjs} +2 -2
- package/dist/{machineMetadata-DcUupMje.cjs → machineMetadata-CLHS9sv_.cjs} +3 -3
- package/dist/{machineMetadata-B1H9gNbN.mjs → machineMetadata-D-g--oU_.mjs} +3 -3
- package/dist/{main-CshDb5-1.mjs → main-B2LWV8DI.mjs} +58 -45
- package/dist/{main-DoMFJ2Cl.cjs → main-CWhSsbtU.cjs} +58 -45
- package/dist/{mcp-pNc1EbQf.cjs → mcp-CARUsXHV.cjs} +14 -14
- package/dist/{mcp-DKT_lrvQ.mjs → mcp-ext92q3Y.mjs} +14 -14
- package/dist/{mirrorProtocol-6IFGPpjJ.mjs → mirrorProtocol-BwYibqry.mjs} +3 -3
- package/dist/{mirrorProtocol-qKflWTX_.cjs → mirrorProtocol-DEy2g1CB.cjs} +3 -3
- package/dist/{package-B7B03ejW.mjs → package-BPPebGQF.mjs} +7 -7
- package/dist/{package-DY4zTbKS.cjs → package-SgqTYsjn.cjs} +7 -7
- package/dist/panels-BZ0_Tt7B.mjs +137 -0
- package/dist/panels-D1c7q2dD.cjs +142 -0
- package/dist/{peerTools-3R9RUARX.mjs → peerTools-CWKzcQ7u.mjs} +60 -10
- package/dist/{peerTools-iy3_6Yc5.cjs → peerTools-DRQETXaz.cjs} +60 -9
- package/dist/{persistence-BfX72dne.cjs → persistence-BegE7NPa.cjs} +2 -2
- package/dist/{persistence-DTk4sNpd.mjs → persistence-Cr-wutZ4.mjs} +3 -3
- package/dist/{piRunnerArgs-CRQVR9o-.cjs → piRunnerArgs-Cs-378Vz.cjs} +8 -2
- package/dist/{piRunnerArgs-AT8QJY7x.mjs → piRunnerArgs-DwvM_yWA.mjs} +7 -1
- package/dist/{piRuntime-BHRT5MKO.cjs → piRuntime-BG-1td_n.cjs} +2 -2
- package/dist/{piRuntime-E44qTVQ4.mjs → piRuntime-Bue5mnlc.mjs} +2 -2
- package/dist/{piTerminal-De8nbciM.mjs → piTerminal-B5x9X5yV.mjs} +17 -17
- package/dist/{piTerminal-hI4WFdWm.cjs → piTerminal-G4z-xVyy.cjs} +17 -17
- package/dist/processTreeSnapshot-CuLJDNC-.mjs +101 -0
- package/dist/processTreeSnapshot-mDbnuojn.cjs +105 -0
- package/dist/prompt-BOouDaTM.mjs +99 -0
- package/dist/prompt-lgF9IE82.cjs +105 -0
- package/dist/{attachmentLimits-UyFn8fkQ.mjs → pushNotifications-BdFjDjQe.mjs} +303 -3
- package/dist/{attachmentLimits-SqeAHrVC.cjs → pushNotifications-DaLQUyi0.cjs} +304 -2
- package/dist/{index-DFPT4HOO.cjs → query-Ctfg-5gy.cjs} +25 -5
- package/dist/{index-CEjJnq05.mjs → query-DYP_W1wp.mjs} +26 -3
- package/dist/{rateLimitWindows-XrJiiBpU.mjs → rateLimitWindows-CuEqk_0g.mjs} +1 -1
- package/dist/{rateLimitWindows-Czb7_7cK.cjs → rateLimitWindows-Dj_8voBK.cjs} +1 -1
- package/dist/{registerCommonHandlers-CvIedVRf.mjs → registerCommonHandlers-BAlP7SGc.mjs} +2 -2
- package/dist/{registerCommonHandlers-C0_fyBQ0.cjs → registerCommonHandlers-Cj084Sg7.cjs} +2 -2
- package/dist/{registerKillSessionHandler-gwJ5lTf0.mjs → registerKillSessionHandler-PD0jWtQo.mjs} +6 -6
- package/dist/{registerKillSessionHandler-DYl7l4Ts.cjs → registerKillSessionHandler-qMju0ZfF.cjs} +6 -6
- package/dist/{remoteSessionClient-BRTIOX5b.cjs → remoteSessionClient-B7i7MkYV.cjs} +5 -5
- package/dist/{remoteSessionClient-DRb2Jr5s.mjs → remoteSessionClient-Bn2qu5C5.mjs} +5 -5
- package/dist/{reportProgressTool-B9nCzbkL.cjs → reportProgressTool-CM1JFAHg.cjs} +84 -2
- package/dist/{reportProgressTool-D5tEoXMW.mjs → reportProgressTool-gHItlSzz.mjs} +82 -3
- package/dist/{resources-JDPugcDq.cjs → resources-CvIlkzpP.cjs} +30 -0
- package/dist/{resources-BdFBQi8r.mjs → resources-y9jfyO-_.mjs} +30 -0
- package/dist/{run-BQ_FGaOL.mjs → run-BM4TxiyN.mjs} +177 -41
- package/dist/{run-CKe_WeLW.cjs → run-CNXwIe0A.cjs} +191 -55
- package/dist/{runClaude-MHI5IKM-.cjs → runClaude-CWhj2V4Q.cjs} +36 -40
- package/dist/{runClaude-zrrNcQC_.mjs → runClaude-C_3I8hvR.mjs} +36 -40
- package/dist/{runClaudeDeps-RRw-Nusc.cjs → runClaudeDeps-B81cOKnH.cjs} +294 -156
- package/dist/{runClaudeDeps-CVBCokOS.mjs → runClaudeDeps-QGrOeDe2.mjs} +294 -159
- package/dist/{runGemini-kipag2ag.mjs → runGemini-BEdWEZLR.mjs} +60 -54
- package/dist/{runGemini-D7Lg9yCr.cjs → runGemini-CgRLYbt5.cjs} +60 -54
- package/dist/{runOpenClaw-DCcQ0L2N.cjs → runOpenClaw-C1NVmzOL.cjs} +18 -18
- package/dist/{runOpenClaw-C_lRY3Do.mjs → runOpenClaw-DdQZAYj1.mjs} +18 -18
- package/dist/{sandbox-BSyXFVFp.mjs → sandbox-DjQUdCMG.mjs} +4 -4
- package/dist/{sandbox-dMwPTmjm.cjs → sandbox-nocIjliq.cjs} +4 -4
- package/dist/selfCheck-CjCF4C3v.mjs +85 -0
- package/dist/{selfCheck-DkzDDUsE.cjs → selfCheck-DCt4Uzbq.cjs} +36 -35
- package/dist/{send-C-k9nsd3.mjs → send-Ct7X4pPU.mjs} +8 -8
- package/dist/{send-dxC0miIA.cjs → send-Dydf_hwZ.cjs} +8 -8
- package/dist/{server-B-W6P7Qr.cjs → server-CosABFbd.cjs} +6 -6
- package/dist/{server-DxoTYNlw.mjs → server-DTQGZMxh.mjs} +4 -4
- package/dist/{sessionLock-DWX6BbiU.cjs → sessionLock-DokGab2R.cjs} +16 -3
- package/dist/{sessionLock-DBdtZGOL.mjs → sessionLock-WYIyaVO4.mjs} +16 -4
- package/dist/{sessionOps-BVoXe12O.mjs → sessionOps-BIGgRube.mjs} +10 -5
- package/dist/{sessionOps-BAnr7n8t.cjs → sessionOps-S-qPBLFf.cjs} +10 -5
- package/dist/{sessionScanner-CDOYsEUD.cjs → sessionScanner-CIMM2hvZ.cjs} +3 -3
- package/dist/{sessionScanner-BtxoeluY.mjs → sessionScanner-o5hnMi5e.mjs} +3 -3
- package/dist/{sessions-C3sZJkzI.mjs → sessions-BJHEZpi2.mjs} +39 -17
- package/dist/{sessions-hAitoN-m.cjs → sessions-JchI1w3z.cjs} +39 -16
- package/dist/{setupOfflineReconnection-C2EeYTFH.cjs → setupOfflineReconnection-CNiAt5ZP.cjs} +2 -2
- package/dist/{setupOfflineReconnection-_eD4cuUT.mjs → setupOfflineReconnection-DMiBO2y9.mjs} +2 -2
- package/dist/{spawn-Bc9v7pIf.cjs → spawn-6PD7nnoC.cjs} +48 -17
- package/dist/{spawn-qNrB2CD_.mjs → spawn-DgvUNYEo.mjs} +48 -17
- package/dist/{spawnAgents-BVEaz35W.cjs → spawnAgents-DsXgegHM.cjs} +37 -1
- package/dist/spawnAgents-P006Hqio.mjs +79 -0
- package/dist/{spawnHappyCLI-C2stUioM.mjs → spawnHappyCLI-CCOrEtf9.mjs} +1 -1
- package/dist/{spawnHappyCLI-fzUagkKV.cjs → spawnHappyCLI-Dywezwk6.cjs} +1 -1
- package/dist/{specialCommands-C6W-rVyh.mjs → specialCommands-DPcd9edP.mjs} +3 -3
- package/dist/{specialCommands-BJ-nqY4s.cjs → specialCommands-QxPpkGKf.cjs} +3 -3
- package/dist/{startFileWatcher-CR09Snmz.mjs → startFileWatcher-DghDOCO4.mjs} +1 -1
- package/dist/{startFileWatcher-Bqlqjt93.cjs → startFileWatcher-RECH5qY8.cjs} +1 -1
- package/dist/{streamRelay-CJoMk_d2.mjs → streamRelay-DMV_TXfS.mjs} +1 -1
- package/dist/{streamRelay-9kBPpbvU.cjs → streamRelay-DlUWKUpo.cjs} +1 -1
- package/dist/{sync-DbW07iQS.mjs → sync-CSe0Rf45.mjs} +1 -1
- package/dist/{sync-Dhmtk66S.cjs → sync-D23jbqVa.cjs} +1 -1
- package/dist/{systemPrompt-3PYi3EUY.cjs → systemPrompt-BOy4kU4P.cjs} +4 -3
- package/dist/{systemPrompt-CQcuUmVp.mjs → systemPrompt-CFNKnh65.mjs} +4 -3
- package/dist/{teams-CwF4Z2fA.mjs → teams-DyY669f0.mjs} +8 -8
- package/dist/{teams-DpxLcUU_.cjs → teams-Ov2BDT-A.cjs} +8 -8
- package/dist/{time-BuGWTVP6.mjs → time-65DcU6Jx.mjs} +1 -1
- package/dist/{time-A6zR3Iy6.cjs → time-CrwIMHta.cjs} +1 -1
- package/dist/{titleGenerator-D26gvNaS.cjs → titleGenerator-CS_rh2_J.cjs} +9 -8
- package/dist/{titleGenerator-BGEzNWC9.mjs → titleGenerator-CiAMxf7s.mjs} +9 -8
- package/dist/{todo-DrZc76H5.mjs → todo-BDONw0sK.mjs} +6 -6
- package/dist/{todo-73g3NCIO.cjs → todo-KY-okGii.cjs} +6 -6
- package/dist/{tools-BtsrQnNS.mjs → tools-D8-PnZEG.mjs} +1 -1
- package/dist/{tools-CxJp4T1T.cjs → tools-_w52DZG6.cjs} +1 -1
- package/dist/{uninstall-DWNYvewQ.cjs → uninstall-8vnLN-IE.cjs} +3 -3
- package/dist/{uninstall-DOb2mTwV.mjs → uninstall-_fjGRP9b.mjs} +3 -3
- package/dist/webPanels-B2_C2-3g.mjs +49 -0
- package/dist/webPanels-FCgFKvVe.cjs +53 -0
- package/package.json +7 -7
- package/dist/selfCheck-CF7XGJPb.mjs +0 -84
- package/dist/sessionModeFile-ByLbXTbg.mjs +0 -32
- package/dist/sessionModeFile-CLLdidiJ.cjs +0 -36
- package/dist/spawnAgents-Bw6j4tqz.mjs +0 -45
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { c as configuration } from './configuration-WMi4idBB.mjs';
|
|
4
|
+
import { b as readCredentialsForConfiguredRelay, r as readSettings } from './persistence-Cr-wutZ4.mjs';
|
|
5
|
+
import { n as normalizeWebPanels, w as webPanelPath } from './webPanels-B2_C2-3g.mjs';
|
|
6
|
+
import 'node:fs';
|
|
7
|
+
import 'node:os';
|
|
8
|
+
import 'node:path';
|
|
9
|
+
import './package-BPPebGQF.mjs';
|
|
10
|
+
import 'node:fs/promises';
|
|
11
|
+
import 'zod';
|
|
12
|
+
import './authRelay-DhQhkBvX.mjs';
|
|
13
|
+
import 'node:crypto';
|
|
14
|
+
import 'tweetnacl';
|
|
15
|
+
import './logger-BtVhHnD8.mjs';
|
|
16
|
+
import 'node:util';
|
|
17
|
+
|
|
18
|
+
function frameVerdict(headers) {
|
|
19
|
+
const xfo = headers["x-frame-options"]?.trim().toUpperCase();
|
|
20
|
+
if (xfo === "DENY" || xfo === "SAMEORIGIN") return { embeddable: false, reason: `X-Frame-Options: ${xfo}` };
|
|
21
|
+
const csp = headers["content-security-policy"] ?? "";
|
|
22
|
+
const fa = csp.split(";").map((d) => d.trim()).find((d) => d.toLowerCase().startsWith("frame-ancestors"));
|
|
23
|
+
if (fa) {
|
|
24
|
+
const sources = fa.split(/\s+/).slice(1);
|
|
25
|
+
if (!sources.includes("*") && !sources.some((s) => /veryhappy\.dev/.test(s))) {
|
|
26
|
+
return { embeddable: false, reason: `CSP ${fa}` };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return { embeddable: true };
|
|
30
|
+
}
|
|
31
|
+
function printPanels(panels, problems) {
|
|
32
|
+
if (panels.length === 0 && problems.length === 0) {
|
|
33
|
+
console.log("No webPanels declared in", configuration.settingsFile);
|
|
34
|
+
console.log(chalk.gray('Add e.g. "webPanels": [{ "id": "desktop", "title": "Desktop", "url": "https://host.example.ts.net:6443/vnc.html" }]'));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
for (const p of panels) console.log(`${chalk.bold(p.id.padEnd(16))} ${p.title.padEnd(20)} ${p.url}${p.embed ? "" : chalk.gray(" (open in new window)")}`);
|
|
38
|
+
for (const p of problems) console.log(chalk.yellow(`skipped #${p.index}${p.id ? ` (${p.id})` : ""}: ${p.reason}`));
|
|
39
|
+
}
|
|
40
|
+
async function handlePanelsCommand(args) {
|
|
41
|
+
const action = args[0] ?? "list";
|
|
42
|
+
const { panels, problems } = normalizeWebPanels((await readSettings()).webPanels);
|
|
43
|
+
if (action === "list") {
|
|
44
|
+
printPanels(panels, problems);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (action !== "check") {
|
|
48
|
+
console.log(`${chalk.bold("very-happy panels")} \u2014 web panels declared in ${configuration.settingsFile}
|
|
49
|
+
|
|
50
|
+
very-happy panels list Show the declared panels (and skipped entries)
|
|
51
|
+
very-happy panels check Fetch each URL from THIS machine: reachable? embeddable?`);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
printPanels(panels, problems);
|
|
55
|
+
for (const p of panels) {
|
|
56
|
+
try {
|
|
57
|
+
const res = await axios.get(p.url, { timeout: 8e3, maxRedirects: 3, validateStatus: () => true, responseType: "stream" });
|
|
58
|
+
res.data.destroy?.();
|
|
59
|
+
const headers = Object.fromEntries(Object.entries(res.headers).map(([k, v]) => [k.toLowerCase(), Array.isArray(v) ? v.join(", ") : v == null ? void 0 : String(v)]));
|
|
60
|
+
const frame = frameVerdict(headers);
|
|
61
|
+
const notes = [
|
|
62
|
+
`HTTP ${res.status}`,
|
|
63
|
+
p.url.startsWith("https:") ? "https" : chalk.yellow("http (only usable from this machine)"),
|
|
64
|
+
frame.embeddable ? "embeddable" : chalk.yellow(`not embeddable (${frame.reason}) \u2192 set "embed": false`)
|
|
65
|
+
];
|
|
66
|
+
console.log(`${p.id}: ${notes.join(" \xB7 ")}`);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
console.log(chalk.red(`${p.id}: unreachable from this machine (${error instanceof Error ? error.message : String(error)})`));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
console.log(chalk.gray("Reachable here \u2260 reachable from your phone: the viewer's browser connects to the URL directly (tailnet / tunnel + HTTPS)."));
|
|
72
|
+
}
|
|
73
|
+
function parseAttentionArgs(args) {
|
|
74
|
+
let panel;
|
|
75
|
+
let session;
|
|
76
|
+
const words = [];
|
|
77
|
+
for (let i = 0; i < args.length; i++) {
|
|
78
|
+
if (args[i] === "--panel") panel = args[++i];
|
|
79
|
+
else if (args[i] === "--session") session = args[++i];
|
|
80
|
+
else if (args[i].startsWith("--")) return { error: `unknown option ${args[i]}` };
|
|
81
|
+
else words.push(args[i]);
|
|
82
|
+
}
|
|
83
|
+
const reason = words.join(" ").replace(/\s+/g, " ").trim().slice(0, 200);
|
|
84
|
+
if (!reason) return { error: 'usage: very-happy attention "<reason>" [--panel <id>] [--session <sessionId>]' };
|
|
85
|
+
if (args.includes("--panel") && !panel || args.includes("--session") && !session) return { error: "missing value after --panel / --session" };
|
|
86
|
+
return { reason, ...panel ? { panel } : {}, ...session ? { session } : {} };
|
|
87
|
+
}
|
|
88
|
+
async function handleAttentionCommand(args) {
|
|
89
|
+
const parsed = parseAttentionArgs(args);
|
|
90
|
+
if ("error" in parsed) {
|
|
91
|
+
console.error(parsed.error);
|
|
92
|
+
process.exitCode = 1;
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const credentials = await readCredentialsForConfiguredRelay();
|
|
96
|
+
const settings = await readSettings();
|
|
97
|
+
if (!credentials || !settings.machineId) {
|
|
98
|
+
console.error('Not authenticated on this machine. Run "very-happy auth login" first.');
|
|
99
|
+
process.exitCode = 1;
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
let link;
|
|
103
|
+
if (parsed.panel) {
|
|
104
|
+
const { panels } = normalizeWebPanels(settings.webPanels);
|
|
105
|
+
if (panels.some((p) => p.id === parsed.panel)) link = webPanelPath(settings.machineId, parsed.panel);
|
|
106
|
+
else console.error(chalk.yellow(`panel "${parsed.panel}" is not declared in ${configuration.settingsFile}; the notification will not deep-link`));
|
|
107
|
+
}
|
|
108
|
+
if (parsed.session) {
|
|
109
|
+
const { ApiClient } = await import('./api-CzwFpJQc.mjs').then(function (n) { return n.b; });
|
|
110
|
+
const api = await ApiClient.create(credentials);
|
|
111
|
+
const r = await api.push().sendAttention({ sessionId: parsed.session, reason: parsed.reason, url: link ?? `/session/${encodeURIComponent(parsed.session)}` });
|
|
112
|
+
if (!r.sent) {
|
|
113
|
+
console.error(`Failed: ${r.error}`);
|
|
114
|
+
process.exitCode = 1;
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
console.log(r.kind === "attention" ? "Sent." : 'Sent (this server predates "attention"; delivered as a question).');
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
const res = await axios.post(`${configuration.serverUrl}/v1/webhook/notify`, {
|
|
122
|
+
title: "Needs you",
|
|
123
|
+
message: parsed.reason,
|
|
124
|
+
event: "permission",
|
|
125
|
+
...link ? { link } : {}
|
|
126
|
+
}, {
|
|
127
|
+
headers: { Authorization: `Bearer ${credentials.token}`, "Content-Type": "application/json", "X-Happy-Client": `cli/${configuration.currentCliVersion}` },
|
|
128
|
+
timeout: 15e3
|
|
129
|
+
});
|
|
130
|
+
console.log(res.data?.delivered ? "Sent (devices + webhook)." : "Sent to devices (no webhook delivery).");
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.error(`Failed: ${error?.response ? `HTTP ${error.response.status}` : error?.message ?? error}`);
|
|
133
|
+
process.exitCode = 1;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export { frameVerdict, handleAttentionCommand, handlePanelsCommand, parseAttentionArgs };
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var axios = require('axios');
|
|
4
|
+
var chalk = require('chalk');
|
|
5
|
+
var configuration = require('./configuration-CMHZnp6G.cjs');
|
|
6
|
+
var persistence = require('./persistence-BegE7NPa.cjs');
|
|
7
|
+
var webPanels = require('./webPanels-FCgFKvVe.cjs');
|
|
8
|
+
require('node:fs');
|
|
9
|
+
require('node:os');
|
|
10
|
+
require('node:path');
|
|
11
|
+
require('./package-SgqTYsjn.cjs');
|
|
12
|
+
require('node:fs/promises');
|
|
13
|
+
require('zod');
|
|
14
|
+
require('./authRelay-Dy1qU9td.cjs');
|
|
15
|
+
require('node:crypto');
|
|
16
|
+
require('tweetnacl');
|
|
17
|
+
require('./logger-C1GWx3gi.cjs');
|
|
18
|
+
require('node:util');
|
|
19
|
+
|
|
20
|
+
function frameVerdict(headers) {
|
|
21
|
+
const xfo = headers["x-frame-options"]?.trim().toUpperCase();
|
|
22
|
+
if (xfo === "DENY" || xfo === "SAMEORIGIN") return { embeddable: false, reason: `X-Frame-Options: ${xfo}` };
|
|
23
|
+
const csp = headers["content-security-policy"] ?? "";
|
|
24
|
+
const fa = csp.split(";").map((d) => d.trim()).find((d) => d.toLowerCase().startsWith("frame-ancestors"));
|
|
25
|
+
if (fa) {
|
|
26
|
+
const sources = fa.split(/\s+/).slice(1);
|
|
27
|
+
if (!sources.includes("*") && !sources.some((s) => /veryhappy\.dev/.test(s))) {
|
|
28
|
+
return { embeddable: false, reason: `CSP ${fa}` };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return { embeddable: true };
|
|
32
|
+
}
|
|
33
|
+
function printPanels(panels, problems) {
|
|
34
|
+
if (panels.length === 0 && problems.length === 0) {
|
|
35
|
+
console.log("No webPanels declared in", configuration.configuration.settingsFile);
|
|
36
|
+
console.log(chalk.gray('Add e.g. "webPanels": [{ "id": "desktop", "title": "Desktop", "url": "https://host.example.ts.net:6443/vnc.html" }]'));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
for (const p of panels) console.log(`${chalk.bold(p.id.padEnd(16))} ${p.title.padEnd(20)} ${p.url}${p.embed ? "" : chalk.gray(" (open in new window)")}`);
|
|
40
|
+
for (const p of problems) console.log(chalk.yellow(`skipped #${p.index}${p.id ? ` (${p.id})` : ""}: ${p.reason}`));
|
|
41
|
+
}
|
|
42
|
+
async function handlePanelsCommand(args) {
|
|
43
|
+
const action = args[0] ?? "list";
|
|
44
|
+
const { panels, problems } = webPanels.normalizeWebPanels((await persistence.readSettings()).webPanels);
|
|
45
|
+
if (action === "list") {
|
|
46
|
+
printPanels(panels, problems);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (action !== "check") {
|
|
50
|
+
console.log(`${chalk.bold("very-happy panels")} \u2014 web panels declared in ${configuration.configuration.settingsFile}
|
|
51
|
+
|
|
52
|
+
very-happy panels list Show the declared panels (and skipped entries)
|
|
53
|
+
very-happy panels check Fetch each URL from THIS machine: reachable? embeddable?`);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
printPanels(panels, problems);
|
|
57
|
+
for (const p of panels) {
|
|
58
|
+
try {
|
|
59
|
+
const res = await axios.get(p.url, { timeout: 8e3, maxRedirects: 3, validateStatus: () => true, responseType: "stream" });
|
|
60
|
+
res.data.destroy?.();
|
|
61
|
+
const headers = Object.fromEntries(Object.entries(res.headers).map(([k, v]) => [k.toLowerCase(), Array.isArray(v) ? v.join(", ") : v == null ? void 0 : String(v)]));
|
|
62
|
+
const frame = frameVerdict(headers);
|
|
63
|
+
const notes = [
|
|
64
|
+
`HTTP ${res.status}`,
|
|
65
|
+
p.url.startsWith("https:") ? "https" : chalk.yellow("http (only usable from this machine)"),
|
|
66
|
+
frame.embeddable ? "embeddable" : chalk.yellow(`not embeddable (${frame.reason}) \u2192 set "embed": false`)
|
|
67
|
+
];
|
|
68
|
+
console.log(`${p.id}: ${notes.join(" \xB7 ")}`);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.log(chalk.red(`${p.id}: unreachable from this machine (${error instanceof Error ? error.message : String(error)})`));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
console.log(chalk.gray("Reachable here \u2260 reachable from your phone: the viewer's browser connects to the URL directly (tailnet / tunnel + HTTPS)."));
|
|
74
|
+
}
|
|
75
|
+
function parseAttentionArgs(args) {
|
|
76
|
+
let panel;
|
|
77
|
+
let session;
|
|
78
|
+
const words = [];
|
|
79
|
+
for (let i = 0; i < args.length; i++) {
|
|
80
|
+
if (args[i] === "--panel") panel = args[++i];
|
|
81
|
+
else if (args[i] === "--session") session = args[++i];
|
|
82
|
+
else if (args[i].startsWith("--")) return { error: `unknown option ${args[i]}` };
|
|
83
|
+
else words.push(args[i]);
|
|
84
|
+
}
|
|
85
|
+
const reason = words.join(" ").replace(/\s+/g, " ").trim().slice(0, 200);
|
|
86
|
+
if (!reason) return { error: 'usage: very-happy attention "<reason>" [--panel <id>] [--session <sessionId>]' };
|
|
87
|
+
if (args.includes("--panel") && !panel || args.includes("--session") && !session) return { error: "missing value after --panel / --session" };
|
|
88
|
+
return { reason, ...panel ? { panel } : {}, ...session ? { session } : {} };
|
|
89
|
+
}
|
|
90
|
+
async function handleAttentionCommand(args) {
|
|
91
|
+
const parsed = parseAttentionArgs(args);
|
|
92
|
+
if ("error" in parsed) {
|
|
93
|
+
console.error(parsed.error);
|
|
94
|
+
process.exitCode = 1;
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const credentials = await persistence.readCredentialsForConfiguredRelay();
|
|
98
|
+
const settings = await persistence.readSettings();
|
|
99
|
+
if (!credentials || !settings.machineId) {
|
|
100
|
+
console.error('Not authenticated on this machine. Run "very-happy auth login" first.');
|
|
101
|
+
process.exitCode = 1;
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
let link;
|
|
105
|
+
if (parsed.panel) {
|
|
106
|
+
const { panels } = webPanels.normalizeWebPanels(settings.webPanels);
|
|
107
|
+
if (panels.some((p) => p.id === parsed.panel)) link = webPanels.webPanelPath(settings.machineId, parsed.panel);
|
|
108
|
+
else console.error(chalk.yellow(`panel "${parsed.panel}" is not declared in ${configuration.configuration.settingsFile}; the notification will not deep-link`));
|
|
109
|
+
}
|
|
110
|
+
if (parsed.session) {
|
|
111
|
+
const { ApiClient } = await Promise.resolve().then(function () { return require('./api-Cmjfr8Z7.cjs'); }).then(function (n) { return n.api; });
|
|
112
|
+
const api = await ApiClient.create(credentials);
|
|
113
|
+
const r = await api.push().sendAttention({ sessionId: parsed.session, reason: parsed.reason, url: link ?? `/session/${encodeURIComponent(parsed.session)}` });
|
|
114
|
+
if (!r.sent) {
|
|
115
|
+
console.error(`Failed: ${r.error}`);
|
|
116
|
+
process.exitCode = 1;
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
console.log(r.kind === "attention" ? "Sent." : 'Sent (this server predates "attention"; delivered as a question).');
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
try {
|
|
123
|
+
const res = await axios.post(`${configuration.configuration.serverUrl}/v1/webhook/notify`, {
|
|
124
|
+
title: "Needs you",
|
|
125
|
+
message: parsed.reason,
|
|
126
|
+
event: "permission",
|
|
127
|
+
...link ? { link } : {}
|
|
128
|
+
}, {
|
|
129
|
+
headers: { Authorization: `Bearer ${credentials.token}`, "Content-Type": "application/json", "X-Happy-Client": `cli/${configuration.configuration.currentCliVersion}` },
|
|
130
|
+
timeout: 15e3
|
|
131
|
+
});
|
|
132
|
+
console.log(res.data?.delivered ? "Sent (devices + webhook)." : "Sent to devices (no webhook delivery).");
|
|
133
|
+
} catch (error) {
|
|
134
|
+
console.error(`Failed: ${error?.response ? `HTTP ${error.response.status}` : error?.message ?? error}`);
|
|
135
|
+
process.exitCode = 1;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
exports.frameVerdict = frameVerdict;
|
|
140
|
+
exports.handleAttentionCommand = handleAttentionCommand;
|
|
141
|
+
exports.handlePanelsCommand = handlePanelsCommand;
|
|
142
|
+
exports.parseAttentionArgs = parseAttentionArgs;
|
|
@@ -2,12 +2,13 @@ import { randomUUID } from 'node:crypto';
|
|
|
2
2
|
import { userInfo, hostname } from 'node:os';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { i as isValidSessionId } from './ids-DU6sLx4C.mjs';
|
|
5
|
-
import { g as listDaemonPeers } from './controlClient-
|
|
6
|
-
import {
|
|
7
|
-
import { s as sessionWebUrl, e as sendUserMessage } from './sessionOps-
|
|
8
|
-
import {
|
|
5
|
+
import { g as listDaemonPeers } from './controlClient-BWUJrj3t.mjs';
|
|
6
|
+
import { c as readPersistedSessions } from './persistence-Cr-wutZ4.mjs';
|
|
7
|
+
import { s as sessionWebUrl, e as sendUserMessage } from './sessionOps-BIGgRube.mjs';
|
|
8
|
+
import { a as listRemotePeers, b as sendRemotePeerMessage, d as deliverToSession } from './remoteSessionClient-Bn2qu5C5.mjs';
|
|
9
9
|
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
10
10
|
import { resolve, isAbsolute, dirname } from 'node:path';
|
|
11
|
+
import { P as ProjectsUnsupportedError, s as sharedProjectsClient } from './client-BhoEBnuN.mjs';
|
|
11
12
|
|
|
12
13
|
const SESSION_PEER_SENT_FROM = "session-peer";
|
|
13
14
|
const CLI_PEER_SENDER_ID = "cli";
|
|
@@ -110,7 +111,7 @@ const SESSION_PEER_TOOL_SCHEMAS = {
|
|
|
110
111
|
session_message: {
|
|
111
112
|
title: "Message Another Session",
|
|
112
113
|
readOnly: false,
|
|
113
|
-
description: "Send a message to another agent session (find ids with session_peers). It lands in that session's chat with your title, session id and cwd, and tells the peer how to reply to you. Use it to coordinate when you both edit the same files: say what you are changing and ask what they are changing. Returns as soon as the message is queued; the reply arrives later as a message from that session. Sessions on this machine are reached directly; a session spawned by another machine of this account is routed to that machine's daemon (it must be online). Terminal-mirror sessions cannot receive messages.",
|
|
114
|
+
description: "Send a message to another agent session (find ids with session_peers). It lands in that session's chat with your title, session id and cwd, and tells the peer how to reply to you. Use it to coordinate when you both edit the same files: say what you are changing and ask what they are changing. Returns as soon as the message is queued; the reply arrives later as a message from that session. Sessions on this machine are reached directly; a session spawned by another machine of this account is routed to that machine's daemon (it must be online). If the target is not running but is in your Very Happy project, the message is stored and read at its next turn (stored: true). Terminal-mirror sessions cannot receive messages.",
|
|
114
115
|
inputSchema: {
|
|
115
116
|
to: z.string().min(1).max(128).describe("Target session id (from session_peers, or a peer's message header)"),
|
|
116
117
|
body: z.string().min(1).max(16e3).describe("The message text"),
|
|
@@ -121,9 +122,9 @@ const SESSION_PEER_TOOL_SCHEMAS = {
|
|
|
121
122
|
session_peers: {
|
|
122
123
|
title: "List Peer Sessions",
|
|
123
124
|
readOnly: true,
|
|
124
|
-
description: 'List the other agent sessions running on this machine and the files each edited in the last 30 minutes. Default scope "repo": sessions in the same git repository, including its other worktrees (sameWorktree says whether they share your checkout). "cwd": the same directory only. "machine": every live session here. With machineId, list the live sessions on that other machine of this account instead (scope "machine" unless you pass a cwd that exists there).',
|
|
125
|
+
description: 'List the other agent sessions running on this machine and the files each edited in the last 30 minutes. Default scope "repo": sessions in the same git repository, including its other worktrees (sameWorktree says whether they share your checkout). "cwd": the same directory only. "machine": every live session here. "project": the other sessions of your Very Happy project on any machine (title, agent, what it is doing). With machineId, list the live sessions on that other machine of this account instead (scope "machine" unless you pass a cwd that exists there).',
|
|
125
126
|
inputSchema: {
|
|
126
|
-
scope: z.enum(["repo", "cwd", "machine"]).optional().describe("repo (default) | cwd | machine"),
|
|
127
|
+
scope: z.enum(["repo", "cwd", "machine", "project"]).optional().describe("repo (default) | cwd | machine | project"),
|
|
127
128
|
machineId: z.string().min(1).max(128).optional().describe("Another machine of this account (from the web's machine list) to list instead of this one"),
|
|
128
129
|
cwd: z.string().min(1).max(4096).optional().describe("With machineId: a directory on that machine to compute repo/cwd scope from")
|
|
129
130
|
}
|
|
@@ -131,6 +132,31 @@ const SESSION_PEER_TOOL_SCHEMAS = {
|
|
|
131
132
|
};
|
|
132
133
|
const PEER_MESSAGE_RATE_LIMIT = 8;
|
|
133
134
|
const PEER_MESSAGE_RATE_WINDOW_MS = 10 * 6e4;
|
|
135
|
+
async function defaultStoreOffline(args) {
|
|
136
|
+
const client = sharedProjectsClient();
|
|
137
|
+
try {
|
|
138
|
+
const [mine, theirs] = await Promise.all([client.membership(args.from), client.membership(args.to)]);
|
|
139
|
+
if (!mine.projectId || mine.projectId !== theirs.projectId) return null;
|
|
140
|
+
const { message } = await client.message(mine.projectId, { fromSessionId: args.from, toSessionId: args.to, body: args.body });
|
|
141
|
+
return { projectId: mine.projectId, messageId: message.id };
|
|
142
|
+
} catch {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const OFFLINE_STORED_NOTE = "stored, will be read at recipient's next turn";
|
|
147
|
+
async function storeOfflineOrThrow(context, self, to, body, original) {
|
|
148
|
+
const stored = await (context.storeOffline ?? defaultStoreOffline)({ from: self.sessionId, to, body });
|
|
149
|
+
if (!stored) throw original;
|
|
150
|
+
return { delivered: false, stored: true, status: "offline-stored", messageId: stored.messageId.slice(0, 8), to, url: sessionWebUrl(to), note: OFFLINE_STORED_NOTE };
|
|
151
|
+
}
|
|
152
|
+
async function defaultProjectPeers(sessionId) {
|
|
153
|
+
const ctx = await sharedProjectsClient().context(sessionId, { full: true, peek: true });
|
|
154
|
+
return {
|
|
155
|
+
scope: "project",
|
|
156
|
+
project: ctx.project ? { id: ctx.project.id, name: ctx.project.name } : null,
|
|
157
|
+
peers: ctx.sessions.map((s) => ({ sessionId: s.sessionId, title: s.title, agent: s.agent, machine: s.machine, branch: s.branch, state: s.state, doing: s.doing, updatedAt: s.updatedAt, url: sessionWebUrl(s.sessionId) }))
|
|
158
|
+
};
|
|
159
|
+
}
|
|
134
160
|
async function listPeerSessions(context, scope = "repo") {
|
|
135
161
|
const self = context.self();
|
|
136
162
|
const repoOf = context.repoOf ?? resolveRepoIdentity;
|
|
@@ -177,12 +203,28 @@ async function sendPeerMessage(context, args) {
|
|
|
177
203
|
const budget = checkPeerSendBudget(context.sentTo, args.to, now);
|
|
178
204
|
if (!budget.ok) throw new Error(replyLoopRefusal(budget.count, args.to));
|
|
179
205
|
}
|
|
180
|
-
|
|
206
|
+
let result2;
|
|
207
|
+
try {
|
|
208
|
+
result2 = await remote({ to: args.to, body, replyTo: args.replyTo, from: self, machineId: args.machineId });
|
|
209
|
+
} catch (error) {
|
|
210
|
+
const stored = await storeOfflineOrThrow(context, self, args.to, body, error instanceof Error ? error : new Error(String(error)));
|
|
211
|
+
context.sentTo?.get(args.to)?.push(now);
|
|
212
|
+
return stored;
|
|
213
|
+
}
|
|
181
214
|
context.sentTo?.get(args.to)?.push(now);
|
|
182
215
|
return result2;
|
|
183
216
|
}
|
|
184
217
|
const live = (await (context.listPeers ?? listDaemonPeers)()).find((session) => session.sessionId === args.to);
|
|
185
|
-
if (!live)
|
|
218
|
+
if (!live) {
|
|
219
|
+
const notRunning = new Error(`Session ${args.to} is not running on this machine; nothing would read the message`);
|
|
220
|
+
if (context.sentTo) {
|
|
221
|
+
const budget = checkPeerSendBudget(context.sentTo, args.to, now);
|
|
222
|
+
if (!budget.ok) throw new Error(replyLoopRefusal(budget.count, args.to));
|
|
223
|
+
}
|
|
224
|
+
const stored = await storeOfflineOrThrow(context, self, args.to, body, notRunning);
|
|
225
|
+
context.sentTo?.get(args.to)?.push(now);
|
|
226
|
+
return stored;
|
|
227
|
+
}
|
|
186
228
|
if (live.kind === "mirror") throw new Error(`Session ${args.to} is a terminal mirror (a person typing claude in a terminal); it cannot receive messages`);
|
|
187
229
|
if (context.sentTo) {
|
|
188
230
|
const budget = checkPeerSendBudget(context.sentTo, args.to, now);
|
|
@@ -216,6 +258,14 @@ async function executeSessionPeerTool(name, args, context) {
|
|
|
216
258
|
});
|
|
217
259
|
case "session_peers": {
|
|
218
260
|
const scope = args?.scope;
|
|
261
|
+
if (scope === "project") {
|
|
262
|
+
try {
|
|
263
|
+
return await (context.projectPeers ?? defaultProjectPeers)(context.self().sessionId);
|
|
264
|
+
} catch (error) {
|
|
265
|
+
if (error instanceof ProjectsUnsupportedError) throw new Error('This Very Happy server does not support projects yet; use scope "repo"');
|
|
266
|
+
throw error;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
219
269
|
if (scope !== void 0 && !PEER_SCOPES.includes(scope)) throw new Error(`scope must be one of ${PEER_SCOPES.join(", ")}`);
|
|
220
270
|
if (args?.machineId) {
|
|
221
271
|
return (context.remotePeers ?? listRemotePeers)(String(args.machineId), {
|
|
@@ -269,4 +319,4 @@ function registerSessionPeerTools(server, execute) {
|
|
|
269
319
|
}
|
|
270
320
|
}
|
|
271
321
|
|
|
272
|
-
export { CLI_PEER_SENDER_ID as C, PEER_SCOPES as P, SESSION_PEER_TOOL_NAMES as S, createSessionPeerToolExecutor as a, SESSION_PEER_SENT_FROM as b, cliPeerSelf as c, formatEditConflictNotice as f, listPeerSessions as l, registerSessionPeerTools as r, sendPeerMessage as s };
|
|
322
|
+
export { CLI_PEER_SENDER_ID as C, PEER_SCOPES as P, SESSION_PEER_TOOL_NAMES as S, createSessionPeerToolExecutor as a, SESSION_PEER_SENT_FROM as b, cliPeerSelf as c, executeSessionPeerTool as e, formatEditConflictNotice as f, listPeerSessions as l, registerSessionPeerTools as r, sendPeerMessage as s };
|
|
@@ -4,12 +4,13 @@ var node_crypto = require('node:crypto');
|
|
|
4
4
|
var os = require('node:os');
|
|
5
5
|
var z = require('zod');
|
|
6
6
|
var ids = require('./ids-B6ZC0HGt.cjs');
|
|
7
|
-
var controlClient = require('./controlClient-
|
|
8
|
-
var persistence = require('./persistence-
|
|
9
|
-
var sessionOps = require('./sessionOps-
|
|
10
|
-
var remoteSessionClient = require('./remoteSessionClient-
|
|
7
|
+
var controlClient = require('./controlClient-C-5qCt8W.cjs');
|
|
8
|
+
var persistence = require('./persistence-BegE7NPa.cjs');
|
|
9
|
+
var sessionOps = require('./sessionOps-S-qPBLFf.cjs');
|
|
10
|
+
var remoteSessionClient = require('./remoteSessionClient-B7i7MkYV.cjs');
|
|
11
11
|
var node_fs = require('node:fs');
|
|
12
12
|
var path = require('node:path');
|
|
13
|
+
var client = require('./client-ZjOsn6nZ.cjs');
|
|
13
14
|
|
|
14
15
|
const SESSION_PEER_SENT_FROM = "session-peer";
|
|
15
16
|
const CLI_PEER_SENDER_ID = "cli";
|
|
@@ -112,7 +113,7 @@ const SESSION_PEER_TOOL_SCHEMAS = {
|
|
|
112
113
|
session_message: {
|
|
113
114
|
title: "Message Another Session",
|
|
114
115
|
readOnly: false,
|
|
115
|
-
description: "Send a message to another agent session (find ids with session_peers). It lands in that session's chat with your title, session id and cwd, and tells the peer how to reply to you. Use it to coordinate when you both edit the same files: say what you are changing and ask what they are changing. Returns as soon as the message is queued; the reply arrives later as a message from that session. Sessions on this machine are reached directly; a session spawned by another machine of this account is routed to that machine's daemon (it must be online). Terminal-mirror sessions cannot receive messages.",
|
|
116
|
+
description: "Send a message to another agent session (find ids with session_peers). It lands in that session's chat with your title, session id and cwd, and tells the peer how to reply to you. Use it to coordinate when you both edit the same files: say what you are changing and ask what they are changing. Returns as soon as the message is queued; the reply arrives later as a message from that session. Sessions on this machine are reached directly; a session spawned by another machine of this account is routed to that machine's daemon (it must be online). If the target is not running but is in your Very Happy project, the message is stored and read at its next turn (stored: true). Terminal-mirror sessions cannot receive messages.",
|
|
116
117
|
inputSchema: {
|
|
117
118
|
to: z.z.string().min(1).max(128).describe("Target session id (from session_peers, or a peer's message header)"),
|
|
118
119
|
body: z.z.string().min(1).max(16e3).describe("The message text"),
|
|
@@ -123,9 +124,9 @@ const SESSION_PEER_TOOL_SCHEMAS = {
|
|
|
123
124
|
session_peers: {
|
|
124
125
|
title: "List Peer Sessions",
|
|
125
126
|
readOnly: true,
|
|
126
|
-
description: 'List the other agent sessions running on this machine and the files each edited in the last 30 minutes. Default scope "repo": sessions in the same git repository, including its other worktrees (sameWorktree says whether they share your checkout). "cwd": the same directory only. "machine": every live session here. With machineId, list the live sessions on that other machine of this account instead (scope "machine" unless you pass a cwd that exists there).',
|
|
127
|
+
description: 'List the other agent sessions running on this machine and the files each edited in the last 30 minutes. Default scope "repo": sessions in the same git repository, including its other worktrees (sameWorktree says whether they share your checkout). "cwd": the same directory only. "machine": every live session here. "project": the other sessions of your Very Happy project on any machine (title, agent, what it is doing). With machineId, list the live sessions on that other machine of this account instead (scope "machine" unless you pass a cwd that exists there).',
|
|
127
128
|
inputSchema: {
|
|
128
|
-
scope: z.z.enum(["repo", "cwd", "machine"]).optional().describe("repo (default) | cwd | machine"),
|
|
129
|
+
scope: z.z.enum(["repo", "cwd", "machine", "project"]).optional().describe("repo (default) | cwd | machine | project"),
|
|
129
130
|
machineId: z.z.string().min(1).max(128).optional().describe("Another machine of this account (from the web's machine list) to list instead of this one"),
|
|
130
131
|
cwd: z.z.string().min(1).max(4096).optional().describe("With machineId: a directory on that machine to compute repo/cwd scope from")
|
|
131
132
|
}
|
|
@@ -133,6 +134,31 @@ const SESSION_PEER_TOOL_SCHEMAS = {
|
|
|
133
134
|
};
|
|
134
135
|
const PEER_MESSAGE_RATE_LIMIT = 8;
|
|
135
136
|
const PEER_MESSAGE_RATE_WINDOW_MS = 10 * 6e4;
|
|
137
|
+
async function defaultStoreOffline(args) {
|
|
138
|
+
const client$1 = client.sharedProjectsClient();
|
|
139
|
+
try {
|
|
140
|
+
const [mine, theirs] = await Promise.all([client$1.membership(args.from), client$1.membership(args.to)]);
|
|
141
|
+
if (!mine.projectId || mine.projectId !== theirs.projectId) return null;
|
|
142
|
+
const { message } = await client$1.message(mine.projectId, { fromSessionId: args.from, toSessionId: args.to, body: args.body });
|
|
143
|
+
return { projectId: mine.projectId, messageId: message.id };
|
|
144
|
+
} catch {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const OFFLINE_STORED_NOTE = "stored, will be read at recipient's next turn";
|
|
149
|
+
async function storeOfflineOrThrow(context, self, to, body, original) {
|
|
150
|
+
const stored = await (context.storeOffline ?? defaultStoreOffline)({ from: self.sessionId, to, body });
|
|
151
|
+
if (!stored) throw original;
|
|
152
|
+
return { delivered: false, stored: true, status: "offline-stored", messageId: stored.messageId.slice(0, 8), to, url: sessionOps.sessionWebUrl(to), note: OFFLINE_STORED_NOTE };
|
|
153
|
+
}
|
|
154
|
+
async function defaultProjectPeers(sessionId) {
|
|
155
|
+
const ctx = await client.sharedProjectsClient().context(sessionId, { full: true, peek: true });
|
|
156
|
+
return {
|
|
157
|
+
scope: "project",
|
|
158
|
+
project: ctx.project ? { id: ctx.project.id, name: ctx.project.name } : null,
|
|
159
|
+
peers: ctx.sessions.map((s) => ({ sessionId: s.sessionId, title: s.title, agent: s.agent, machine: s.machine, branch: s.branch, state: s.state, doing: s.doing, updatedAt: s.updatedAt, url: sessionOps.sessionWebUrl(s.sessionId) }))
|
|
160
|
+
};
|
|
161
|
+
}
|
|
136
162
|
async function listPeerSessions(context, scope = "repo") {
|
|
137
163
|
const self = context.self();
|
|
138
164
|
const repoOf = context.repoOf ?? resolveRepoIdentity;
|
|
@@ -179,12 +205,28 @@ async function sendPeerMessage(context, args) {
|
|
|
179
205
|
const budget = checkPeerSendBudget(context.sentTo, args.to, now);
|
|
180
206
|
if (!budget.ok) throw new Error(replyLoopRefusal(budget.count, args.to));
|
|
181
207
|
}
|
|
182
|
-
|
|
208
|
+
let result2;
|
|
209
|
+
try {
|
|
210
|
+
result2 = await remote({ to: args.to, body, replyTo: args.replyTo, from: self, machineId: args.machineId });
|
|
211
|
+
} catch (error) {
|
|
212
|
+
const stored = await storeOfflineOrThrow(context, self, args.to, body, error instanceof Error ? error : new Error(String(error)));
|
|
213
|
+
context.sentTo?.get(args.to)?.push(now);
|
|
214
|
+
return stored;
|
|
215
|
+
}
|
|
183
216
|
context.sentTo?.get(args.to)?.push(now);
|
|
184
217
|
return result2;
|
|
185
218
|
}
|
|
186
219
|
const live = (await (context.listPeers ?? controlClient.listDaemonPeers)()).find((session) => session.sessionId === args.to);
|
|
187
|
-
if (!live)
|
|
220
|
+
if (!live) {
|
|
221
|
+
const notRunning = new Error(`Session ${args.to} is not running on this machine; nothing would read the message`);
|
|
222
|
+
if (context.sentTo) {
|
|
223
|
+
const budget = checkPeerSendBudget(context.sentTo, args.to, now);
|
|
224
|
+
if (!budget.ok) throw new Error(replyLoopRefusal(budget.count, args.to));
|
|
225
|
+
}
|
|
226
|
+
const stored = await storeOfflineOrThrow(context, self, args.to, body, notRunning);
|
|
227
|
+
context.sentTo?.get(args.to)?.push(now);
|
|
228
|
+
return stored;
|
|
229
|
+
}
|
|
188
230
|
if (live.kind === "mirror") throw new Error(`Session ${args.to} is a terminal mirror (a person typing claude in a terminal); it cannot receive messages`);
|
|
189
231
|
if (context.sentTo) {
|
|
190
232
|
const budget = checkPeerSendBudget(context.sentTo, args.to, now);
|
|
@@ -218,6 +260,14 @@ async function executeSessionPeerTool(name, args, context) {
|
|
|
218
260
|
});
|
|
219
261
|
case "session_peers": {
|
|
220
262
|
const scope = args?.scope;
|
|
263
|
+
if (scope === "project") {
|
|
264
|
+
try {
|
|
265
|
+
return await (context.projectPeers ?? defaultProjectPeers)(context.self().sessionId);
|
|
266
|
+
} catch (error) {
|
|
267
|
+
if (error instanceof client.ProjectsUnsupportedError) throw new Error('This Very Happy server does not support projects yet; use scope "repo"');
|
|
268
|
+
throw error;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
221
271
|
if (scope !== void 0 && !PEER_SCOPES.includes(scope)) throw new Error(`scope must be one of ${PEER_SCOPES.join(", ")}`);
|
|
222
272
|
if (args?.machineId) {
|
|
223
273
|
return (context.remotePeers ?? remoteSessionClient.listRemotePeers)(String(args.machineId), {
|
|
@@ -277,6 +327,7 @@ exports.SESSION_PEER_SENT_FROM = SESSION_PEER_SENT_FROM;
|
|
|
277
327
|
exports.SESSION_PEER_TOOL_NAMES = SESSION_PEER_TOOL_NAMES;
|
|
278
328
|
exports.cliPeerSelf = cliPeerSelf;
|
|
279
329
|
exports.createSessionPeerToolExecutor = createSessionPeerToolExecutor;
|
|
330
|
+
exports.executeSessionPeerTool = executeSessionPeerTool;
|
|
280
331
|
exports.formatEditConflictNotice = formatEditConflictNotice;
|
|
281
332
|
exports.listPeerSessions = listPeerSessions;
|
|
282
333
|
exports.registerSessionPeerTools = registerSessionPeerTools;
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
var promises = require('node:fs/promises');
|
|
4
4
|
var node_fs = require('node:fs');
|
|
5
|
-
var configuration = require('./configuration-
|
|
5
|
+
var configuration = require('./configuration-CMHZnp6G.cjs');
|
|
6
6
|
var z = require('zod');
|
|
7
7
|
var authRelay = require('./authRelay-Dy1qU9td.cjs');
|
|
8
|
-
var logger = require('./logger-
|
|
8
|
+
var logger = require('./logger-C1GWx3gi.cjs');
|
|
9
9
|
|
|
10
10
|
function _interopNamespaceDefault(e) {
|
|
11
11
|
var n = Object.create(null);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { readFile, open, unlink, stat, rename } from 'node:fs/promises';
|
|
2
2
|
import { existsSync, constants, readFileSync, unlinkSync, renameSync } from 'node:fs';
|
|
3
|
-
import { c as configuration, P as PRIVATE_FILE_MODE, w as writePrivateFileSync, a as hardenPrivateFileSync, e as ensurePrivateDirectory, b as writePrivateFile, h as hardenPrivateFile } from './configuration-
|
|
3
|
+
import { c as configuration, P as PRIVATE_FILE_MODE, w as writePrivateFileSync, a as hardenPrivateFileSync, e as ensurePrivateDirectory, b as writePrivateFile, h as hardenPrivateFile } from './configuration-WMi4idBB.mjs';
|
|
4
4
|
import * as z from 'zod';
|
|
5
5
|
import { c as credentialRelayProblem, e as encodeBase64 } from './authRelay-DhQhkBvX.mjs';
|
|
6
|
-
import { l as logger } from './logger
|
|
6
|
+
import { l as logger } from './logger-BtVhHnD8.mjs';
|
|
7
7
|
|
|
8
8
|
const HIBERNATION_CAPABILITY = "agent-hibernation-v1";
|
|
9
9
|
const HOUR_MS = 60 * 60 * 1e3;
|
|
@@ -477,4 +477,4 @@ var persistence = /*#__PURE__*/Object.freeze({
|
|
|
477
477
|
writeSettings: writeSettings
|
|
478
478
|
});
|
|
479
479
|
|
|
480
|
-
export { writeDaemonState as A, writeSettings as B, settingIdleMs as C, rewriteCredentialsForRelay as D, releaseDaemonLock as E, persistence as F, HIBERNATION_CAPABILITY as H, SandboxConfigSchema as S, resolveCheckMs as a,
|
|
480
|
+
export { writeDaemonState as A, writeSettings as B, settingIdleMs as C, rewriteCredentialsForRelay as D, releaseDaemonLock as E, persistence as F, HIBERNATION_CAPABILITY as H, SandboxConfigSchema as S, resolveCheckMs as a, readCredentialsForConfiguredRelay as b, readPersistedSessions as c, readDaemonState as d, evaluateWrapperIdle as e, clearDaemonState as f, readCredentials as g, clearCredentials as h, clearMachineId as i, HIBERNATION_UNSUPPORTED_BACKOFF_MS as j, readSettingsOutcome as k, latchKeepAwake as l, writeCredentialsDataKey as m, hibernationReplaySeq as n, readTrackedClaudeSessionIds as o, readTrackedCodexThreadIds as p, reportSignature as q, readSettings as r, decideDaemonHibernation as s, nextCheckDelay as t, updateSettings as u, persistSession as v, writeCredentialsLegacy as w, acquireDaemonLock as x, resolveIdleMs as y, deletePersistedSessions as z };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var acpSessionResume = require('./acpSessionResume-oiCBnAVA.cjs');
|
|
4
4
|
|
|
5
5
|
function sanitizeSpawnModel(value) {
|
|
6
6
|
if (typeof value !== "string") return null;
|
|
@@ -62,8 +62,14 @@ function parsePiRunnerArgs(args) {
|
|
|
62
62
|
parsed.model = model;
|
|
63
63
|
continue;
|
|
64
64
|
}
|
|
65
|
+
if (arg === "--resume") {
|
|
66
|
+
const id = acpSessionResume.sanitizeAgentSessionId(args[++i]);
|
|
67
|
+
if (!id) throw new Error("Invalid --resume session id");
|
|
68
|
+
parsed.resume = id;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
65
71
|
if (arg === "--permission-mode") {
|
|
66
|
-
const mode =
|
|
72
|
+
const mode = acpSessionResume.normalizeAcpPermissionMode(args[++i]);
|
|
67
73
|
if (mode) parsed.permissionMode = mode;
|
|
68
74
|
continue;
|
|
69
75
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as normalizeAcpPermissionMode } from './
|
|
1
|
+
import { s as sanitizeAgentSessionId, n as normalizeAcpPermissionMode } from './acpSessionResume-DTGmAPLt.mjs';
|
|
2
2
|
|
|
3
3
|
function sanitizeSpawnModel(value) {
|
|
4
4
|
if (typeof value !== "string") return null;
|
|
@@ -60,6 +60,12 @@ function parsePiRunnerArgs(args) {
|
|
|
60
60
|
parsed.model = model;
|
|
61
61
|
continue;
|
|
62
62
|
}
|
|
63
|
+
if (arg === "--resume") {
|
|
64
|
+
const id = sanitizeAgentSessionId(args[++i]);
|
|
65
|
+
if (!id) throw new Error("Invalid --resume session id");
|
|
66
|
+
parsed.resume = id;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
63
69
|
if (arg === "--permission-mode") {
|
|
64
70
|
const mode = normalizeAcpPermissionMode(args[++i]);
|
|
65
71
|
if (mode) parsed.permissionMode = mode;
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
var promises = require('node:fs/promises');
|
|
4
4
|
var node_crypto = require('node:crypto');
|
|
5
5
|
var path = require('node:path');
|
|
6
|
-
var configuration = require('./configuration-
|
|
7
|
-
var resources = require('./resources-
|
|
6
|
+
var configuration = require('./configuration-CMHZnp6G.cjs');
|
|
7
|
+
var resources = require('./resources-CvIlkzpP.cjs');
|
|
8
8
|
|
|
9
9
|
async function publish(path, content, mode) {
|
|
10
10
|
const temporary = `${path}.${node_crypto.randomUUID()}.new`;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { mkdir, chmod, writeFile, rename } from 'node:fs/promises';
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
|
-
import { c as configuration } from './configuration-
|
|
5
|
-
import { P as PI_TEAMS_EXTENSION } from './resources-
|
|
4
|
+
import { c as configuration } from './configuration-WMi4idBB.mjs';
|
|
5
|
+
import { P as PI_TEAMS_EXTENSION } from './resources-y9jfyO-_.mjs';
|
|
6
6
|
|
|
7
7
|
async function publish(path, content, mode) {
|
|
8
8
|
const temporary = `${path}.${randomUUID()}.new`;
|