very-happy-cli 0.2.178 → 0.2.180
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-B8Zi30Zh.mjs} +135 -16
- package/dist/{AcpBackend-CDkAQXYf.cjs → AcpBackend-DfRDtMcG.cjs} +135 -16
- package/dist/{AcpSessionManager-DckmUZza.cjs → AcpSessionManager-CASKOnOj.cjs} +38 -4
- package/dist/{AcpSessionManager-BXrQcqwC.mjs → AcpSessionManager-i8Rab0xT.mjs} +38 -4
- package/dist/{BasePermissionHandler-BVlrEhIi.mjs → BasePermissionHandler-26fKbRCm.mjs} +5 -2
- package/dist/{BasePermissionHandler-DyLmKKtO.cjs → BasePermissionHandler-BlM_tfej.cjs} +5 -2
- package/dist/acpSessionResume-B9l54P-X.mjs +67 -0
- package/dist/acpSessionResume-CR5pmgVo.cjs +74 -0
- package/dist/{agentHome-CEp9RMyK.cjs → agentHome-C7Sb7-Tz.cjs} +4 -4
- package/dist/{agentHome-C1xi37as.mjs → agentHome-CmGy0NWv.mjs} +4 -4
- package/dist/{api-JANhFdZV.cjs → api-DM7b1OKj.cjs} +38 -262
- package/dist/{api-Dib0dmqC.mjs → api-Hov8p7CA.mjs} +32 -256
- package/dist/{apiMachine-DNTJidYH.mjs → apiMachine-CwGEhQDT.mjs} +62 -15
- package/dist/{apiMachine-QhK-sKcr.cjs → apiMachine-DkGRj-Ai.cjs} +64 -17
- package/dist/{attachmentContent-bpQTBJ0y.cjs → attachmentContent-CEm13_gF.cjs} +4 -4
- package/dist/{attachmentContent-DkkdpSSJ.mjs → attachmentContent-CIn4iPEk.mjs} +2 -2
- package/dist/{auth-BRjd2esb.mjs → auth-BG1DY0gj.mjs} +5 -5
- package/dist/{auth-DgIV0Cvt.cjs → auth-CBXnm-Mj.cjs} +5 -5
- package/dist/{auth-omWDtgR8.cjs → auth-Dawj7pP5.cjs} +8 -8
- package/dist/{auth-DNct7VUi.mjs → auth-rggxMpEE.mjs} +8 -8
- package/dist/{auto-DKGFOJBo.mjs → auto-CXXLXGeL.mjs} +19 -18
- package/dist/{auto-CI16FZmX.cjs → auto-CbYOfoPS.cjs} +19 -18
- package/dist/{backgroundTaskActivity-BVwJBl02.mjs → backgroundTaskActivity-8PdPxrvy.mjs} +1 -1
- package/dist/{bootstrap-DCQ87Aan.cjs → bootstrap-DoA7okld.cjs} +2 -2
- package/dist/{bootstrap-BUagGC_-.mjs → bootstrap-Dt5I1SOl.mjs} +2 -2
- package/dist/{browser-Dj_DYQEh.mjs → browser-DUNetFT4.mjs} +1 -1
- package/dist/{browser-CSKhc0Bl.cjs → browser-DZ6qRtfH.cjs} +1 -1
- package/dist/{claudeCliPath-U4HHmV4r.cjs → claudeCliPath-GaP3UUz1.cjs} +1 -1
- package/dist/{claudeLocal-CdIVnOZp.cjs → claudeLocal--DNyMOSv.cjs} +8 -7
- package/dist/{claudeLocal-CCCvAeMd.mjs → claudeLocal-OHWQigCl.mjs} +6 -5
- package/dist/{claudeLocalLauncher-BmrpaRYJ.mjs → claudeLocalLauncher-BStvfa7M.mjs} +11 -10
- package/dist/{claudeLocalLauncher-21-xh5gc.cjs → claudeLocalLauncher-BhvPbcyH.cjs} +13 -12
- package/dist/{claudeSessionFork-kYCP1IJB.cjs → claudeSessionFork-Be16vzGc.cjs} +1 -1
- package/dist/{claudeSessionFork-DvxMKAmY.mjs → claudeSessionFork-GAVWhiKG.mjs} +1 -1
- package/dist/{client-C4zKGjiJ.cjs → client-BWjaHKtj.cjs} +2 -2
- package/dist/client-Ca5Pcgy_.mjs +71 -0
- package/dist/{client-CnlkkrZO.mjs → client-CnB7kRCT.mjs} +2 -2
- package/dist/{client-BTX9hsbr.mjs → client-D4uPb1uu.mjs} +3 -3
- package/dist/client-DJplzPjD.cjs +76 -0
- package/dist/{client-Dnza1hgN.cjs → client-D_loZ9IK.cjs} +3 -3
- package/dist/codex/happyMcpStdioBridge.cjs +24 -15
- package/dist/codex/happyMcpStdioBridge.mjs +25 -16
- package/dist/{codexAppServerClient-DvkpQgyv.mjs → codexAppServerClient-CO4G6OS4.mjs} +3 -3
- package/dist/{codexAppServerClient-CRlBWGn3.cjs → codexAppServerClient-PE-12AsW.cjs} +3 -3
- package/dist/{codexCommand-DzxIWXIT.cjs → codexCommand-BNoD1t1C.cjs} +127 -116
- package/dist/{codexCommand-BxjogBzU.mjs → codexCommand-B_xUH79E.mjs} +77 -66
- package/dist/{codexTermination-C28FzlLb.cjs → codexTermination-BmBbizFK.cjs} +7 -2
- package/dist/{codexTermination-ySDNMEhd.mjs → codexTermination-Dx48ma6e.mjs} +7 -2
- package/dist/{config-BFB5uJ4t.cjs → config-CtwEUxUP.cjs} +26 -26
- package/dist/{config-DwfEpFr3.mjs → config-DSu0Blos.mjs} +3 -3
- package/dist/{configuration-4TGMrjul.cjs → configuration-CYO-kPOS.cjs} +1 -1
- package/dist/{configuration-DVrb61aY.mjs → configuration-PxzEJumr.mjs} +1 -1
- package/dist/{connect-C7FPY0PI.mjs → connect-BQrg3TB6.mjs} +15 -15
- package/dist/{connect-QH2VJGBG.cjs → connect-Dq7wndzR.cjs} +28 -28
- package/dist/{context-JoKu0V54.cjs → context-6TP-iz_c.cjs} +1 -1
- package/dist/{context-B3XPVJlj.mjs → context-CJGRRGWW.mjs} +1 -1
- package/dist/{controlClient-BTaZlbC6.cjs → controlClient-Bqv5v5OM.cjs} +3 -3
- package/dist/{controlClient-BYKyGyxj.mjs → controlClient-DoeYovwP.mjs} +4 -4
- package/dist/{createSessionMetadata-8Fuj2-IV.mjs → createSessionMetadata-DDIChCx8.mjs} +2 -2
- package/dist/{createSessionMetadata-B2NynaWZ.cjs → createSessionMetadata-xz767pcG.cjs} +3 -3
- package/dist/{defaultPermissionMode-BEWCqJU-.cjs → defaultPermissionMode-PkZGsQDk.cjs} +2 -2
- package/dist/{defaultPermissionMode-B8kJG9uI.mjs → defaultPermissionMode-i5KzdK09.mjs} +2 -2
- package/dist/{detectCLI-DR9ZaN6B.cjs → detectCLI-BuYR_Qxe.cjs} +4 -4
- package/dist/{deterministicJson-C5ZwZ7hu.mjs → deterministicJson-CTEJDqtS.mjs} +217 -12
- package/dist/{deterministicJson-BjNQsAjO.cjs → deterministicJson-xqA6DaOm.cjs} +222 -16
- package/dist/{doctor-BshRnjLi.cjs → doctor-BrgSlfXn.cjs} +9 -9
- package/dist/{doctor-0BiGwJXk.mjs → doctor-IctjVh9T.mjs} +8 -8
- package/dist/{doctorReadiness-BCZGcN0a.cjs → doctorReadiness-Dl6yRQCy.cjs} +1 -1
- package/dist/{downloadTarget-BN5vZt3K.cjs → downloadTarget-CEb9che-.cjs} +6 -6
- package/dist/{downloadTarget-DJPwAZlu.mjs → downloadTarget-jbOz1egC.mjs} +6 -6
- package/dist/{ensureDaemonRunning-C5QfToCe.cjs → ensureDaemonRunning-D-HyjGIX.cjs} +6 -6
- package/dist/{ensureDaemonRunning-CSmb_mqt.mjs → ensureDaemonRunning-b1e8LCSM.mjs} +5 -5
- package/dist/{handleResumeCommand-BwnUZmbo.cjs → handleResumeCommand-BvWVuRwH.cjs} +23 -7
- package/dist/{handleResumeCommand-CgjpsdDe.mjs → handleResumeCommand-DpaZvm2c.mjs} +22 -6
- package/dist/{index-piJPsTsm.cjs → index-B2p2Mut7.cjs} +259 -53
- package/dist/{index-BehVbAsA.mjs → index-BUNnpGFF.mjs} +256 -50
- package/dist/{index-Bvldtdny.mjs → index-Bsvbgh9e.mjs} +4 -4
- package/dist/{index-BYOZ_8WZ.cjs → index-C64Ufj4D.cjs} +4 -4
- package/dist/{index-Clqlu17M.mjs → index-C6Vn5Eac.mjs} +155 -34
- package/dist/index-CMf5VbzG.mjs +18 -0
- package/dist/index-DmTlDRSL.cjs +24 -0
- package/dist/{index-_l1Sdmbi.cjs → index-Dv0Q48P3.cjs} +156 -33
- package/dist/{index-BRClDe07.cjs → index-F2UejqYs.cjs} +3 -3
- package/dist/{index-BYgfern_.mjs → index-wCbtF4BK.mjs} +3 -3
- 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-C0ANcEAW.cjs} +7 -7
- package/dist/{install-fYWHrPcC.mjs → install-CdzSV7qO.mjs} +3 -3
- package/dist/{installPiTools-BKnXjrVu.cjs → installPiTools-CL_axh_6.cjs} +1 -1
- package/dist/{installTerminalHooks-BQZbvxsZ.cjs → installTerminalHooks-BETLKAtd.cjs} +3 -3
- package/dist/lib.cjs +14 -14
- package/dist/lib.d.cts +239 -2
- package/dist/lib.d.mts +239 -2
- package/dist/lib.mjs +14 -14
- package/dist/{lidState-BeOwj6eW.cjs → lidState-DWGnm2H4.cjs} +1 -1
- package/dist/{lidState-DNMlIhX0.mjs → lidState-bBrmaQd2.mjs} +1 -1
- package/dist/{localHappyAgentAuth-Br-mgogg.cjs → localHappyAgentAuth-DZHQnIW9.cjs} +1 -1
- package/dist/{localHappyAgentAuth-BezKSFDi.mjs → localHappyAgentAuth-Dn1jYDpt.mjs} +1 -1
- package/dist/{logger--vAVtXB_.mjs → logger-BUngm5Xg.mjs} +2 -2
- package/dist/{logger-DXTWlPzP.cjs → logger-CphW5nUE.cjs} +2 -2
- package/dist/machineMetadata-BQm9YTcI.cjs +79 -0
- package/dist/machineMetadata-BXN_bKU3.mjs +68 -0
- package/dist/{main-DoMFJ2Cl.cjs → main-B2UV51nK.cjs} +112 -132
- package/dist/{main-CshDb5-1.mjs → main-DGkdYfEq.mjs} +106 -126
- package/dist/{mcp-pNc1EbQf.cjs → mcp-BFvAEIRz.cjs} +15 -15
- package/dist/{mcp-DKT_lrvQ.mjs → mcp-CbTtbs0f.mjs} +15 -15
- package/dist/{mirrorProtocol-6IFGPpjJ.mjs → mirrorProtocol-BR4luBC0.mjs} +148 -7
- package/dist/{mirrorProtocol-qKflWTX_.cjs → mirrorProtocol-HKPivs5o.cjs} +150 -4
- package/dist/{package-B7B03ejW.mjs → package-7Ld1YMhh.mjs} +8 -7
- package/dist/{package-DY4zTbKS.cjs → package-KhLqBDX9.cjs} +8 -7
- package/dist/panels-C7IVqpJk.mjs +137 -0
- package/dist/panels-Njf6GelF.cjs +142 -0
- package/dist/{peerTools-3R9RUARX.mjs → peerTools-BOlDRyhi.mjs} +60 -10
- package/dist/{peerTools-iy3_6Yc5.cjs → peerTools-DQNlrcqM.cjs} +60 -9
- package/dist/{persistence-BfX72dne.cjs → persistence-9BMYspxG.cjs} +2 -2
- package/dist/{persistence-DTk4sNpd.mjs → persistence-BFUOHW5h.mjs} +3 -3
- package/dist/{piRunnerArgs-CRQVR9o-.cjs → piRunnerArgs-DGaq6VYM.cjs} +8 -2
- package/dist/{piRunnerArgs-AT8QJY7x.mjs → piRunnerArgs-H2pgpA5z.mjs} +7 -1
- package/dist/{piRuntime-BHRT5MKO.cjs → piRuntime-CT5xv_3h.cjs} +2 -2
- package/dist/{piRuntime-E44qTVQ4.mjs → piRuntime-CdN0JAsa.mjs} +2 -2
- package/dist/{piTerminal-hI4WFdWm.cjs → piTerminal-0FBtXTHK.cjs} +18 -18
- package/dist/{piTerminal-De8nbciM.mjs → piTerminal-C4m9YXAV.mjs} +18 -18
- package/dist/processTreeSnapshot-CuLJDNC-.mjs +101 -0
- package/dist/processTreeSnapshot-mDbnuojn.cjs +105 -0
- package/dist/projectPath-C3ioB4Bu.cjs +13 -0
- package/dist/prompt-BOouDaTM.mjs +99 -0
- package/dist/prompt-lgF9IE82.cjs +105 -0
- package/dist/{attachmentLimits-UyFn8fkQ.mjs → pushNotifications-DCiBEVeC.mjs} +307 -3
- package/dist/{attachmentLimits-SqeAHrVC.cjs → pushNotifications-DI92havG.cjs} +308 -2
- package/dist/{index-DFPT4HOO.cjs → query-BETKBrnz.cjs} +25 -5
- package/dist/{index-CEjJnq05.mjs → query-ywZbQUzR.mjs} +26 -3
- package/dist/{rateLimitWindows-XrJiiBpU.mjs → rateLimitWindows-BkfuUB1a.mjs} +1 -1
- package/dist/{rateLimitWindows-Czb7_7cK.cjs → rateLimitWindows-YRIYVdo4.cjs} +1 -1
- package/dist/{registerCommonHandlers-C0_fyBQ0.cjs → registerCommonHandlers-C7a_dUWs.cjs} +30 -30
- package/dist/{registerCommonHandlers-CvIedVRf.mjs → registerCommonHandlers-CTkCvjxt.mjs} +2 -2
- package/dist/{registerKillSessionHandler-DYl7l4Ts.cjs → registerKillSessionHandler-CIsvBrVe.cjs} +6 -6
- package/dist/{registerKillSessionHandler-gwJ5lTf0.mjs → registerKillSessionHandler-CaqqRYq6.mjs} +6 -6
- package/dist/{remoteSessionClient-BRTIOX5b.cjs → remoteSessionClient-D843fkzL.cjs} +5 -5
- package/dist/{remoteSessionClient-DRb2Jr5s.mjs → remoteSessionClient-PP-mOKmw.mjs} +5 -5
- package/dist/{reportProgressTool-B9nCzbkL.cjs → reportProgressTool-14AXr959.cjs} +84 -2
- package/dist/{reportProgressTool-D5tEoXMW.mjs → reportProgressTool-ZOCNjWHr.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-CKe_WeLW.cjs → run-CAOCYYfT.cjs} +2806 -110
- package/dist/{run-BQ_FGaOL.mjs → run-Dajw2E5j.mjs} +2787 -91
- package/dist/{runClaude-zrrNcQC_.mjs → runClaude-C6oxWYbp.mjs} +49 -47
- package/dist/{runClaude-MHI5IKM-.cjs → runClaude-CRRKt-tm.cjs} +50 -48
- package/dist/{runClaudeDeps-RRw-Nusc.cjs → runClaudeDeps-B1ysqTvx.cjs} +310 -237
- package/dist/{runClaudeDeps-CVBCokOS.mjs → runClaudeDeps-BcZ68cX3.mjs} +297 -226
- package/dist/{runGemini-kipag2ag.mjs → runGemini-D7yKc4wD.mjs} +61 -55
- package/dist/{runGemini-D7Lg9yCr.cjs → runGemini-DtKFXqf-.cjs} +89 -83
- package/dist/{runOpenClaw-C_lRY3Do.mjs → runOpenClaw-C8ilyLP9.mjs} +19 -19
- package/dist/{runOpenClaw-DCcQ0L2N.cjs → runOpenClaw-Cq29mryb.cjs} +20 -20
- package/dist/{sandbox-BSyXFVFp.mjs → sandbox-CbCutma4.mjs} +4 -4
- package/dist/{sandbox-dMwPTmjm.cjs → sandbox-gIj-EuF4.cjs} +4 -4
- package/dist/{selfCheck-DkzDDUsE.cjs → selfCheck-BTGBVthv.cjs} +39 -38
- package/dist/selfCheck-Smt-5Xiq.mjs +85 -0
- package/dist/{send-dxC0miIA.cjs → send-CZf5lLw_.cjs} +8 -8
- package/dist/{send-C-k9nsd3.mjs → send-YZRMQvMJ.mjs} +9 -9
- package/dist/{server-DxoTYNlw.mjs → server-BqwXRzFZ.mjs} +4 -4
- package/dist/{server-B-W6P7Qr.cjs → server-CknFq6xG.cjs} +6 -6
- package/dist/sessionExitLifecycle-CzkLIgNZ.mjs +142 -0
- package/dist/sessionExitLifecycle-DFltxXU8.cjs +148 -0
- package/dist/{sessionLock-DWX6BbiU.cjs → sessionLock-DRZUcKHT.cjs} +38 -5
- package/dist/{sessionLock-DBdtZGOL.mjs → sessionLock-nBXdJxJm.mjs} +36 -5
- package/dist/{sessionOps-BAnr7n8t.cjs → sessionOps-BrGiU9-s.cjs} +10 -5
- package/dist/{sessionOps-BVoXe12O.mjs → sessionOps-C58iDeD5.mjs} +11 -6
- package/dist/{sessionScanner-BtxoeluY.mjs → sessionScanner-Bm57LEXe.mjs} +3 -3
- package/dist/{sessionScanner-CDOYsEUD.cjs → sessionScanner-CaO8bLaG.cjs} +3 -3
- package/dist/{sessions-C3sZJkzI.mjs → sessions-BXyBHo8n.mjs} +40 -18
- package/dist/{sessions-hAitoN-m.cjs → sessions-uzqPCc37.cjs} +39 -16
- package/dist/{setupOfflineReconnection-_eD4cuUT.mjs → setupOfflineReconnection-1Qlek3wl.mjs} +2 -2
- package/dist/{setupOfflineReconnection-C2EeYTFH.cjs → setupOfflineReconnection-DvvVX3TB.cjs} +2 -2
- package/dist/{spawn-Bc9v7pIf.cjs → spawn-DBkodJEO.cjs} +49 -18
- package/dist/{spawn-qNrB2CD_.mjs → spawn-vn93PhYL.mjs} +49 -18
- package/dist/spawnAgents-CgPMWexP.mjs +79 -0
- package/dist/{spawnAgents-BVEaz35W.cjs → spawnAgents-DLNMlhWJ.cjs} +37 -1
- package/dist/{spawnHappyCLI-C2stUioM.mjs → spawnHappyCLI-BjFZc_7V.mjs} +1 -1
- package/dist/{spawnHappyCLI-fzUagkKV.cjs → spawnHappyCLI-DnUZv0X2.cjs} +2 -2
- package/dist/{specialCommands-BJ-nqY4s.cjs → specialCommands-BRufxlqe.cjs} +3 -3
- package/dist/{specialCommands-C6W-rVyh.mjs → specialCommands-D3ND9bdg.mjs} +3 -3
- package/dist/{startFileWatcher-Bqlqjt93.cjs → startFileWatcher-D9cYzZOq.cjs} +1 -1
- package/dist/{startFileWatcher-CR09Snmz.mjs → startFileWatcher-DXJ7yB5v.mjs} +1 -1
- package/dist/startupSessionCreate-kdr3m1uX.cjs +26 -0
- package/dist/startupSessionCreate-uZ6BM0ty.mjs +24 -0
- package/dist/{streamRelay-CJoMk_d2.mjs → streamRelay-DnMCMMfV.mjs} +1 -1
- package/dist/{streamRelay-9kBPpbvU.cjs → streamRelay-Dy6amlzx.cjs} +1 -1
- package/dist/{sync-Dhmtk66S.cjs → sync-Bn-idAoy.cjs} +1 -1
- package/dist/{sync-DbW07iQS.mjs → sync-BvVhDO40.mjs} +1 -1
- package/dist/{systemPrompt-CQcuUmVp.mjs → systemPrompt-CIZcJuJF.mjs} +4 -3
- package/dist/{systemPrompt-3PYi3EUY.cjs → systemPrompt-DlyEk35T.cjs} +4 -3
- package/dist/{teams-DpxLcUU_.cjs → teams-BLeRpDxv.cjs} +8 -8
- package/dist/{teams-CwF4Z2fA.mjs → teams-DLY3B5yi.mjs} +8 -8
- package/dist/{time-A6zR3Iy6.cjs → time-Cjv0zxQO.cjs} +1 -1
- package/dist/{time-BuGWTVP6.mjs → time-D3ETL7Jb.mjs} +1 -1
- package/dist/{titleGenerator-D26gvNaS.cjs → titleGenerator-Cgp5ihFb.cjs} +10 -9
- package/dist/{titleGenerator-BGEzNWC9.mjs → titleGenerator-Uzbd4utr.mjs} +9 -8
- package/dist/{todo-DrZc76H5.mjs → todo-C9Ga-oEM.mjs} +6 -6
- package/dist/{todo-73g3NCIO.cjs → todo-pOMcEECE.cjs} +6 -6
- package/dist/{tools-CxJp4T1T.cjs → tools-BL7Byl_x.cjs} +1 -1
- package/dist/{tools-BtsrQnNS.mjs → tools-Cho7iIWf.mjs} +1 -1
- package/dist/{uninstall-DWNYvewQ.cjs → uninstall-CbayEVoV.cjs} +6 -6
- package/dist/{uninstall-DOb2mTwV.mjs → uninstall-CvZHVY9C.mjs} +3 -3
- package/dist/webPanels-B2_C2-3g.mjs +49 -0
- package/dist/webPanels-FCgFKvVe.cjs +53 -0
- package/package.json +8 -7
- package/dist/machineMetadata-B1H9gNbN.mjs +0 -39
- package/dist/machineMetadata-DcUupMje.cjs +0 -42
- package/dist/messageBuffer-BWlGgR3A.mjs +0 -71
- package/dist/messageBuffer-fJMH6uY8.cjs +0 -73
- package/dist/projectPath-ChLhdOyt.cjs +0 -13
- 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
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
import { randomBytes, createHash, randomUUID } from 'node:crypto';
|
|
2
|
+
import { promises, constants, writeFileSync, chmodSync, openSync, fstatSync, closeSync, existsSync, readFileSync, renameSync, readdirSync, rmSync, lstatSync, realpathSync, statSync, mkdirSync, readSync, unlinkSync, rmdirSync } from 'node:fs';
|
|
3
|
+
import { join, dirname, basename, relative, isAbsolute, sep, resolve } from 'node:path';
|
|
1
4
|
import { spawn, execFileSync, execFile } from 'node:child_process';
|
|
2
|
-
import { createHash, randomUUID } from 'node:crypto';
|
|
3
|
-
import { constants, writeFileSync, chmodSync, openSync, fstatSync, closeSync, existsSync, readFileSync, renameSync, readdirSync, rmSync, lstatSync, realpathSync, statSync, mkdirSync, readSync, unlinkSync, rmdirSync } from 'node:fs';
|
|
4
|
-
import { relative, isAbsolute, sep, join, dirname, basename, resolve } from 'node:path';
|
|
5
5
|
import { realpath, lstat, stat, mkdir, copyFile, symlink, readdir } from 'node:fs/promises';
|
|
6
|
-
import { f as ensurePrivateDirectorySync, w as writePrivateFileSync } from './configuration-
|
|
7
|
-
import {
|
|
8
|
-
import { p as packageJson } from './package-
|
|
6
|
+
import { f as ensurePrivateDirectorySync, w as writePrivateFileSync } from './configuration-PxzEJumr.mjs';
|
|
7
|
+
import { r as AGENT_VERSION_SOURCES } from './index-C6Vn5Eac.mjs';
|
|
8
|
+
import { p as packageJson } from './package-7Ld1YMhh.mjs';
|
|
9
9
|
|
|
10
10
|
function summarizeSpawnSessionForLog(value) {
|
|
11
11
|
const input = value && typeof value === "object" ? value : {};
|
|
@@ -41,6 +41,147 @@ function registerWorktreeHandlers(rpc, service) {
|
|
|
41
41
|
rpc.registerHandler("worktree-remove", async (params) => service.remove(obj(params).path, obj(params).discardChanges, obj(params).expectedFingerprint));
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
const MAX_CONFIG_BYTES = 1024 * 1024;
|
|
45
|
+
const MAX_BACKUPS_PER_HARNESS = 20;
|
|
46
|
+
class ModelConfigError extends Error {
|
|
47
|
+
constructor(code, message) {
|
|
48
|
+
super(message);
|
|
49
|
+
this.code = code;
|
|
50
|
+
this.name = "ModelConfigError";
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function sha256(text) {
|
|
54
|
+
return createHash("sha256").update(text).digest("hex");
|
|
55
|
+
}
|
|
56
|
+
async function readConfigFile(path) {
|
|
57
|
+
let stat;
|
|
58
|
+
try {
|
|
59
|
+
stat = await promises.stat(path);
|
|
60
|
+
} catch (error) {
|
|
61
|
+
if (error.code === "ENOENT") {
|
|
62
|
+
return { path, exists: false, content: "", hash: sha256(""), mode: null };
|
|
63
|
+
}
|
|
64
|
+
throw new ModelConfigError("read-failed", `Cannot read ${path}: ${error.message}`);
|
|
65
|
+
}
|
|
66
|
+
if (!stat.isFile()) throw new ModelConfigError("not-a-file", `${path} is not a regular file`);
|
|
67
|
+
if (stat.size > MAX_CONFIG_BYTES) throw new ModelConfigError("file-too-large", `${path} is larger than ${MAX_CONFIG_BYTES} bytes`);
|
|
68
|
+
const content = await promises.readFile(path, "utf8");
|
|
69
|
+
return { path, exists: true, content, hash: sha256(content), mode: stat.mode & 511 };
|
|
70
|
+
}
|
|
71
|
+
async function resolveWriteTarget(path) {
|
|
72
|
+
try {
|
|
73
|
+
return await promises.realpath(path);
|
|
74
|
+
} catch (error) {
|
|
75
|
+
if (error.code === "ENOENT") {
|
|
76
|
+
try {
|
|
77
|
+
const link = await promises.readlink(path);
|
|
78
|
+
return link.startsWith("/") ? link : join(dirname(path), link);
|
|
79
|
+
} catch {
|
|
80
|
+
return path;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async function atomicWriteFile(path, content, mode) {
|
|
87
|
+
const target = await resolveWriteTarget(path);
|
|
88
|
+
const dir = dirname(target);
|
|
89
|
+
await promises.mkdir(dir, { recursive: true, mode: 448 });
|
|
90
|
+
const tmp = join(dir, `.${basename(target)}.vh-tmp-${process.pid}-${randomBytes(4).toString("hex")}`);
|
|
91
|
+
const handle = await promises.open(tmp, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL, mode ?? 384);
|
|
92
|
+
try {
|
|
93
|
+
await handle.writeFile(content, "utf8");
|
|
94
|
+
await handle.sync();
|
|
95
|
+
} catch (error) {
|
|
96
|
+
await handle.close().catch(() => {
|
|
97
|
+
});
|
|
98
|
+
await promises.unlink(tmp).catch(() => {
|
|
99
|
+
});
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
await handle.close();
|
|
103
|
+
try {
|
|
104
|
+
if (mode !== null) await promises.chmod(tmp, mode);
|
|
105
|
+
await promises.rename(tmp, target);
|
|
106
|
+
} catch (error) {
|
|
107
|
+
await promises.unlink(tmp).catch(() => {
|
|
108
|
+
});
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
const dirHandle = await promises.open(dir, "r");
|
|
113
|
+
await dirHandle.sync().catch(() => {
|
|
114
|
+
});
|
|
115
|
+
await dirHandle.close();
|
|
116
|
+
} catch {
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const BACKUP_ID = /^\d{13}-[0-9a-f]{8}$/;
|
|
120
|
+
const HARNESS_DIR = /^[a-z][a-z0-9-]{0,31}$/;
|
|
121
|
+
class BackupStore {
|
|
122
|
+
constructor(root) {
|
|
123
|
+
this.root = root;
|
|
124
|
+
}
|
|
125
|
+
harnessDir(harness) {
|
|
126
|
+
if (!HARNESS_DIR.test(harness)) throw new ModelConfigError("invalid-harness", "Invalid harness");
|
|
127
|
+
return join(this.root, harness);
|
|
128
|
+
}
|
|
129
|
+
async create(harness, reason, files, now = Date.now()) {
|
|
130
|
+
const id = `${now}-${randomBytes(4).toString("hex")}`;
|
|
131
|
+
const dir = join(this.harnessDir(harness), id);
|
|
132
|
+
await promises.mkdir(dir, { recursive: true, mode: 448 });
|
|
133
|
+
const manifest = { id, createdAt: now, reason, files: files.map((f, i) => ({ path: f.path, blob: f.content === null ? null : `f${i}`, mode: f.mode })) };
|
|
134
|
+
for (const [i, file] of files.entries()) {
|
|
135
|
+
if (file.content !== null) await promises.writeFile(join(dir, `f${i}`), file.content, { encoding: "utf8", mode: 384 });
|
|
136
|
+
}
|
|
137
|
+
await promises.writeFile(join(dir, "manifest.json"), JSON.stringify(manifest, null, 2), { encoding: "utf8", mode: 384 });
|
|
138
|
+
await this.prune(harness);
|
|
139
|
+
return { id, createdAt: now, reason, files: files.map((f) => f.path) };
|
|
140
|
+
}
|
|
141
|
+
async list(harness) {
|
|
142
|
+
let names;
|
|
143
|
+
try {
|
|
144
|
+
names = await promises.readdir(this.harnessDir(harness));
|
|
145
|
+
} catch {
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
const entries = [];
|
|
149
|
+
for (const name of names.filter((n) => BACKUP_ID.test(n))) {
|
|
150
|
+
try {
|
|
151
|
+
const manifest = JSON.parse(await promises.readFile(join(this.harnessDir(harness), name, "manifest.json"), "utf8"));
|
|
152
|
+
entries.push({ id: name, createdAt: Number(manifest.createdAt) || 0, reason: String(manifest.reason ?? ""), files: (manifest.files ?? []).map((f) => f.path) });
|
|
153
|
+
} catch {
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return entries.sort((a, b) => b.createdAt - a.createdAt);
|
|
157
|
+
}
|
|
158
|
+
async read(harness, id) {
|
|
159
|
+
if (!BACKUP_ID.test(id)) throw new ModelConfigError("invalid-backup", "Invalid backup id");
|
|
160
|
+
const dir = join(this.harnessDir(harness), id);
|
|
161
|
+
let manifest;
|
|
162
|
+
try {
|
|
163
|
+
manifest = JSON.parse(await promises.readFile(join(dir, "manifest.json"), "utf8"));
|
|
164
|
+
} catch {
|
|
165
|
+
throw new ModelConfigError("backup-not-found", "Backup not found");
|
|
166
|
+
}
|
|
167
|
+
const out = [];
|
|
168
|
+
for (const file of manifest.files) {
|
|
169
|
+
out.push({
|
|
170
|
+
path: file.path,
|
|
171
|
+
content: file.blob === null ? null : await promises.readFile(join(dir, file.blob), "utf8"),
|
|
172
|
+
mode: typeof file.mode === "number" ? file.mode : null
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
return out;
|
|
176
|
+
}
|
|
177
|
+
async prune(harness) {
|
|
178
|
+
const entries = await this.list(harness);
|
|
179
|
+
for (const stale of entries.slice(MAX_BACKUPS_PER_HARNESS)) {
|
|
180
|
+
await promises.rm(join(this.harnessDir(harness), stale.id), { recursive: true, force: true });
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
44
185
|
const CONFIG_RELATIVE_PATH = ".veryhappy/worktree.json";
|
|
45
186
|
const CONFIG_MAX_BYTES = 64 * 1024;
|
|
46
187
|
const SCRIPT_MAX_BYTES = 32 * 1024;
|
|
@@ -1244,4 +1385,4 @@ function decideBackfill(messages, maxLines) {
|
|
|
1244
1385
|
return { replay: messages.slice(messages.length - cap), truncated: true };
|
|
1245
1386
|
}
|
|
1246
1387
|
|
|
1247
|
-
export {
|
|
1388
|
+
export { BackupStore as B, ModelConfigError as M, WORKTREE_CAPABILITY_VERSION as W, sanitizeTagList as a, sanitizeLiveSnapshot as b, serializeLiveSnapshot as c, configureWorktreeService as d, summarizeSpawnSessionForLog as e, parseMirrorSendParams as f, readConfigFile as g, sha256 as h, isClaudeSessionId as i, atomicWriteFile as j, extractCompleteLines as k, liveSnapshotChanged as l, decideBackfill as m, parseTerminalHookPayload as n, decideMirrorBinding as o, pickMirrorForTerminal as p, MIRROR_BACKFILL_LINES_DEFAULT as q, registerWorktreeHandlers as r, stableVersion as s, mirrorLineKey as t, mirrorLocalId as u, initializeOwnedWorktree as v, startAgentVersionChecks as w, currentWorktreeService as x };
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var node_child_process = require('node:child_process');
|
|
4
3
|
var node_crypto = require('node:crypto');
|
|
5
4
|
var node_fs = require('node:fs');
|
|
6
5
|
var path = require('node:path');
|
|
6
|
+
var node_child_process = require('node:child_process');
|
|
7
7
|
var promises = require('node:fs/promises');
|
|
8
|
-
var configuration = require('./configuration-
|
|
9
|
-
var index = require('./index-
|
|
10
|
-
var _package = require('./package-
|
|
8
|
+
var configuration = require('./configuration-CYO-kPOS.cjs');
|
|
9
|
+
var index = require('./index-Dv0Q48P3.cjs');
|
|
10
|
+
var _package = require('./package-KhLqBDX9.cjs');
|
|
11
11
|
|
|
12
12
|
function summarizeSpawnSessionForLog(value) {
|
|
13
13
|
const input = value && typeof value === "object" ? value : {};
|
|
@@ -43,6 +43,147 @@ function registerWorktreeHandlers(rpc, service) {
|
|
|
43
43
|
rpc.registerHandler("worktree-remove", async (params) => service.remove(obj(params).path, obj(params).discardChanges, obj(params).expectedFingerprint));
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
const MAX_CONFIG_BYTES = 1024 * 1024;
|
|
47
|
+
const MAX_BACKUPS_PER_HARNESS = 20;
|
|
48
|
+
class ModelConfigError extends Error {
|
|
49
|
+
constructor(code, message) {
|
|
50
|
+
super(message);
|
|
51
|
+
this.code = code;
|
|
52
|
+
this.name = "ModelConfigError";
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function sha256(text) {
|
|
56
|
+
return node_crypto.createHash("sha256").update(text).digest("hex");
|
|
57
|
+
}
|
|
58
|
+
async function readConfigFile(path) {
|
|
59
|
+
let stat;
|
|
60
|
+
try {
|
|
61
|
+
stat = await node_fs.promises.stat(path);
|
|
62
|
+
} catch (error) {
|
|
63
|
+
if (error.code === "ENOENT") {
|
|
64
|
+
return { path, exists: false, content: "", hash: sha256(""), mode: null };
|
|
65
|
+
}
|
|
66
|
+
throw new ModelConfigError("read-failed", `Cannot read ${path}: ${error.message}`);
|
|
67
|
+
}
|
|
68
|
+
if (!stat.isFile()) throw new ModelConfigError("not-a-file", `${path} is not a regular file`);
|
|
69
|
+
if (stat.size > MAX_CONFIG_BYTES) throw new ModelConfigError("file-too-large", `${path} is larger than ${MAX_CONFIG_BYTES} bytes`);
|
|
70
|
+
const content = await node_fs.promises.readFile(path, "utf8");
|
|
71
|
+
return { path, exists: true, content, hash: sha256(content), mode: stat.mode & 511 };
|
|
72
|
+
}
|
|
73
|
+
async function resolveWriteTarget(path$1) {
|
|
74
|
+
try {
|
|
75
|
+
return await node_fs.promises.realpath(path$1);
|
|
76
|
+
} catch (error) {
|
|
77
|
+
if (error.code === "ENOENT") {
|
|
78
|
+
try {
|
|
79
|
+
const link = await node_fs.promises.readlink(path$1);
|
|
80
|
+
return link.startsWith("/") ? link : path.join(path.dirname(path$1), link);
|
|
81
|
+
} catch {
|
|
82
|
+
return path$1;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async function atomicWriteFile(path$1, content, mode) {
|
|
89
|
+
const target = await resolveWriteTarget(path$1);
|
|
90
|
+
const dir = path.dirname(target);
|
|
91
|
+
await node_fs.promises.mkdir(dir, { recursive: true, mode: 448 });
|
|
92
|
+
const tmp = path.join(dir, `.${path.basename(target)}.vh-tmp-${process.pid}-${node_crypto.randomBytes(4).toString("hex")}`);
|
|
93
|
+
const handle = await node_fs.promises.open(tmp, node_fs.constants.O_WRONLY | node_fs.constants.O_CREAT | node_fs.constants.O_EXCL, mode ?? 384);
|
|
94
|
+
try {
|
|
95
|
+
await handle.writeFile(content, "utf8");
|
|
96
|
+
await handle.sync();
|
|
97
|
+
} catch (error) {
|
|
98
|
+
await handle.close().catch(() => {
|
|
99
|
+
});
|
|
100
|
+
await node_fs.promises.unlink(tmp).catch(() => {
|
|
101
|
+
});
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
await handle.close();
|
|
105
|
+
try {
|
|
106
|
+
if (mode !== null) await node_fs.promises.chmod(tmp, mode);
|
|
107
|
+
await node_fs.promises.rename(tmp, target);
|
|
108
|
+
} catch (error) {
|
|
109
|
+
await node_fs.promises.unlink(tmp).catch(() => {
|
|
110
|
+
});
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
const dirHandle = await node_fs.promises.open(dir, "r");
|
|
115
|
+
await dirHandle.sync().catch(() => {
|
|
116
|
+
});
|
|
117
|
+
await dirHandle.close();
|
|
118
|
+
} catch {
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const BACKUP_ID = /^\d{13}-[0-9a-f]{8}$/;
|
|
122
|
+
const HARNESS_DIR = /^[a-z][a-z0-9-]{0,31}$/;
|
|
123
|
+
class BackupStore {
|
|
124
|
+
constructor(root) {
|
|
125
|
+
this.root = root;
|
|
126
|
+
}
|
|
127
|
+
harnessDir(harness) {
|
|
128
|
+
if (!HARNESS_DIR.test(harness)) throw new ModelConfigError("invalid-harness", "Invalid harness");
|
|
129
|
+
return path.join(this.root, harness);
|
|
130
|
+
}
|
|
131
|
+
async create(harness, reason, files, now = Date.now()) {
|
|
132
|
+
const id = `${now}-${node_crypto.randomBytes(4).toString("hex")}`;
|
|
133
|
+
const dir = path.join(this.harnessDir(harness), id);
|
|
134
|
+
await node_fs.promises.mkdir(dir, { recursive: true, mode: 448 });
|
|
135
|
+
const manifest = { id, createdAt: now, reason, files: files.map((f, i) => ({ path: f.path, blob: f.content === null ? null : `f${i}`, mode: f.mode })) };
|
|
136
|
+
for (const [i, file] of files.entries()) {
|
|
137
|
+
if (file.content !== null) await node_fs.promises.writeFile(path.join(dir, `f${i}`), file.content, { encoding: "utf8", mode: 384 });
|
|
138
|
+
}
|
|
139
|
+
await node_fs.promises.writeFile(path.join(dir, "manifest.json"), JSON.stringify(manifest, null, 2), { encoding: "utf8", mode: 384 });
|
|
140
|
+
await this.prune(harness);
|
|
141
|
+
return { id, createdAt: now, reason, files: files.map((f) => f.path) };
|
|
142
|
+
}
|
|
143
|
+
async list(harness) {
|
|
144
|
+
let names;
|
|
145
|
+
try {
|
|
146
|
+
names = await node_fs.promises.readdir(this.harnessDir(harness));
|
|
147
|
+
} catch {
|
|
148
|
+
return [];
|
|
149
|
+
}
|
|
150
|
+
const entries = [];
|
|
151
|
+
for (const name of names.filter((n) => BACKUP_ID.test(n))) {
|
|
152
|
+
try {
|
|
153
|
+
const manifest = JSON.parse(await node_fs.promises.readFile(path.join(this.harnessDir(harness), name, "manifest.json"), "utf8"));
|
|
154
|
+
entries.push({ id: name, createdAt: Number(manifest.createdAt) || 0, reason: String(manifest.reason ?? ""), files: (manifest.files ?? []).map((f) => f.path) });
|
|
155
|
+
} catch {
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return entries.sort((a, b) => b.createdAt - a.createdAt);
|
|
159
|
+
}
|
|
160
|
+
async read(harness, id) {
|
|
161
|
+
if (!BACKUP_ID.test(id)) throw new ModelConfigError("invalid-backup", "Invalid backup id");
|
|
162
|
+
const dir = path.join(this.harnessDir(harness), id);
|
|
163
|
+
let manifest;
|
|
164
|
+
try {
|
|
165
|
+
manifest = JSON.parse(await node_fs.promises.readFile(path.join(dir, "manifest.json"), "utf8"));
|
|
166
|
+
} catch {
|
|
167
|
+
throw new ModelConfigError("backup-not-found", "Backup not found");
|
|
168
|
+
}
|
|
169
|
+
const out = [];
|
|
170
|
+
for (const file of manifest.files) {
|
|
171
|
+
out.push({
|
|
172
|
+
path: file.path,
|
|
173
|
+
content: file.blob === null ? null : await node_fs.promises.readFile(path.join(dir, file.blob), "utf8"),
|
|
174
|
+
mode: typeof file.mode === "number" ? file.mode : null
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
return out;
|
|
178
|
+
}
|
|
179
|
+
async prune(harness) {
|
|
180
|
+
const entries = await this.list(harness);
|
|
181
|
+
for (const stale of entries.slice(MAX_BACKUPS_PER_HARNESS)) {
|
|
182
|
+
await node_fs.promises.rm(path.join(this.harnessDir(harness), stale.id), { recursive: true, force: true });
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
46
187
|
const CONFIG_RELATIVE_PATH = ".veryhappy/worktree.json";
|
|
47
188
|
const CONFIG_MAX_BYTES = 64 * 1024;
|
|
48
189
|
const SCRIPT_MAX_BYTES = 32 * 1024;
|
|
@@ -1246,8 +1387,11 @@ function decideBackfill(messages, maxLines) {
|
|
|
1246
1387
|
return { replay: messages.slice(messages.length - cap), truncated: true };
|
|
1247
1388
|
}
|
|
1248
1389
|
|
|
1390
|
+
exports.BackupStore = BackupStore;
|
|
1249
1391
|
exports.MIRROR_BACKFILL_LINES_DEFAULT = MIRROR_BACKFILL_LINES_DEFAULT;
|
|
1392
|
+
exports.ModelConfigError = ModelConfigError;
|
|
1250
1393
|
exports.WORKTREE_CAPABILITY_VERSION = WORKTREE_CAPABILITY_VERSION;
|
|
1394
|
+
exports.atomicWriteFile = atomicWriteFile;
|
|
1251
1395
|
exports.configureWorktreeService = configureWorktreeService;
|
|
1252
1396
|
exports.currentWorktreeService = currentWorktreeService;
|
|
1253
1397
|
exports.decideBackfill = decideBackfill;
|
|
@@ -1261,10 +1405,12 @@ exports.mirrorLocalId = mirrorLocalId;
|
|
|
1261
1405
|
exports.parseMirrorSendParams = parseMirrorSendParams;
|
|
1262
1406
|
exports.parseTerminalHookPayload = parseTerminalHookPayload;
|
|
1263
1407
|
exports.pickMirrorForTerminal = pickMirrorForTerminal;
|
|
1408
|
+
exports.readConfigFile = readConfigFile;
|
|
1264
1409
|
exports.registerWorktreeHandlers = registerWorktreeHandlers;
|
|
1265
1410
|
exports.sanitizeLiveSnapshot = sanitizeLiveSnapshot;
|
|
1266
1411
|
exports.sanitizeTagList = sanitizeTagList;
|
|
1267
1412
|
exports.serializeLiveSnapshot = serializeLiveSnapshot;
|
|
1413
|
+
exports.sha256 = sha256;
|
|
1268
1414
|
exports.stableVersion = stableVersion;
|
|
1269
1415
|
exports.startAgentVersionChecks = startAgentVersionChecks;
|
|
1270
1416
|
exports.summarizeSpawnSessionForLog = summarizeSpawnSessionForLog;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
var name = "very-happy-cli";
|
|
2
|
-
var version = "0.2.
|
|
2
|
+
var version = "0.2.180";
|
|
3
3
|
var description = "Remote multi-agent workspace CLI with deep Claude integration, native terminal streaming, and self-hosting.";
|
|
4
4
|
var author = "Kirill Dubovitskiy";
|
|
5
5
|
var contributors = [
|
|
@@ -116,12 +116,12 @@ var dependencies = {
|
|
|
116
116
|
zod: "^4.0.0"
|
|
117
117
|
};
|
|
118
118
|
var optionalDependencies = {
|
|
119
|
-
"very-happy-tools-arm64-darwin": "0.2.
|
|
120
|
-
"very-happy-tools-x64-darwin": "0.2.
|
|
121
|
-
"very-happy-tools-arm64-linux": "0.2.
|
|
122
|
-
"very-happy-tools-x64-linux": "0.2.
|
|
123
|
-
"very-happy-tools-arm64-win32": "0.2.
|
|
124
|
-
"very-happy-tools-x64-win32": "0.2.
|
|
119
|
+
"very-happy-tools-arm64-darwin": "0.2.180",
|
|
120
|
+
"very-happy-tools-x64-darwin": "0.2.180",
|
|
121
|
+
"very-happy-tools-arm64-linux": "0.2.180",
|
|
122
|
+
"very-happy-tools-x64-linux": "0.2.180",
|
|
123
|
+
"very-happy-tools-arm64-win32": "0.2.180",
|
|
124
|
+
"very-happy-tools-x64-win32": "0.2.180"
|
|
125
125
|
};
|
|
126
126
|
var devDependencies = {
|
|
127
127
|
"@slopus/happy-wire": "workspace:*",
|
|
@@ -133,6 +133,7 @@ var devDependencies = {
|
|
|
133
133
|
"cross-env": "^10.1.0",
|
|
134
134
|
dotenv: "^16.6.1",
|
|
135
135
|
pkgroll: "^2.14.2",
|
|
136
|
+
"smol-toml": "1.9.0",
|
|
136
137
|
"ts-node": "^10",
|
|
137
138
|
tsx: "^4.20.6",
|
|
138
139
|
typescript: "5.9.3",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var name = "very-happy-cli";
|
|
4
|
-
var version = "0.2.
|
|
4
|
+
var version = "0.2.180";
|
|
5
5
|
var description = "Remote multi-agent workspace CLI with deep Claude integration, native terminal streaming, and self-hosting.";
|
|
6
6
|
var author = "Kirill Dubovitskiy";
|
|
7
7
|
var contributors = [
|
|
@@ -118,12 +118,12 @@ var dependencies = {
|
|
|
118
118
|
zod: "^4.0.0"
|
|
119
119
|
};
|
|
120
120
|
var optionalDependencies = {
|
|
121
|
-
"very-happy-tools-arm64-darwin": "0.2.
|
|
122
|
-
"very-happy-tools-x64-darwin": "0.2.
|
|
123
|
-
"very-happy-tools-arm64-linux": "0.2.
|
|
124
|
-
"very-happy-tools-x64-linux": "0.2.
|
|
125
|
-
"very-happy-tools-arm64-win32": "0.2.
|
|
126
|
-
"very-happy-tools-x64-win32": "0.2.
|
|
121
|
+
"very-happy-tools-arm64-darwin": "0.2.180",
|
|
122
|
+
"very-happy-tools-x64-darwin": "0.2.180",
|
|
123
|
+
"very-happy-tools-arm64-linux": "0.2.180",
|
|
124
|
+
"very-happy-tools-x64-linux": "0.2.180",
|
|
125
|
+
"very-happy-tools-arm64-win32": "0.2.180",
|
|
126
|
+
"very-happy-tools-x64-win32": "0.2.180"
|
|
127
127
|
};
|
|
128
128
|
var devDependencies = {
|
|
129
129
|
"@slopus/happy-wire": "workspace:*",
|
|
@@ -135,6 +135,7 @@ var devDependencies = {
|
|
|
135
135
|
"cross-env": "^10.1.0",
|
|
136
136
|
dotenv: "^16.6.1",
|
|
137
137
|
pkgroll: "^2.14.2",
|
|
138
|
+
"smol-toml": "1.9.0",
|
|
138
139
|
"ts-node": "^10",
|
|
139
140
|
tsx: "^4.20.6",
|
|
140
141
|
typescript: "5.9.3",
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { c as configuration } from './configuration-PxzEJumr.mjs';
|
|
4
|
+
import { b as readCredentialsForConfiguredRelay, r as readSettings } from './persistence-BFUOHW5h.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-7Ld1YMhh.mjs';
|
|
10
|
+
import 'node:fs/promises';
|
|
11
|
+
import 'zod';
|
|
12
|
+
import './authRelay-DhQhkBvX.mjs';
|
|
13
|
+
import 'node:crypto';
|
|
14
|
+
import 'tweetnacl';
|
|
15
|
+
import './logger-BUngm5Xg.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-Hov8p7CA.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 };
|