very-happy-cli 0.2.177 → 0.2.179
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{AcpBackend-B0K0WrtW.mjs → AcpBackend-CHp3y7cb.mjs} +135 -16
- package/dist/{AcpBackend-B-ny68XM.cjs → AcpBackend-DFipFF7-.cjs} +135 -16
- package/dist/{AcpSessionManager-CjdJLofq.cjs → AcpSessionManager-0zpvRJXc.cjs} +38 -4
- package/dist/{AcpSessionManager-DykjzBM4.mjs → AcpSessionManager-d2-rKWWa.mjs} +38 -4
- package/dist/{BasePermissionHandler-DR6nxuEn.cjs → BasePermissionHandler-CH3zuEkA.cjs} +5 -2
- package/dist/{BasePermissionHandler-hdY7kTqX.mjs → BasePermissionHandler-DdZBYIR4.mjs} +5 -2
- package/dist/acpSessionResume-DTGmAPLt.mjs +67 -0
- package/dist/acpSessionResume-oiCBnAVA.cjs +74 -0
- package/dist/{agentHome-BdTXEUPe.cjs → agentHome-BWcz8mz0.cjs} +5 -5
- package/dist/{agentHome-GRN2VfHv.mjs → agentHome-CghLvL_1.mjs} +5 -5
- package/dist/{api-BWX10o97.cjs → api-Cmjfr8Z7.cjs} +29 -261
- package/dist/{api-CKBViqI3.mjs → api-CzwFpJQc.mjs} +22 -254
- package/dist/{apiMachine-DttO4UFj.mjs → apiMachine-DJkTEiqy.mjs} +53 -16
- package/dist/{apiMachine-BYYFGgFs.cjs → apiMachine-G6OogT08.cjs} +53 -16
- package/dist/{attachmentContent-cPVF463_.mjs → attachmentContent-B2os4HbA.mjs} +2 -2
- package/dist/{attachmentContent-kJKXpkMX.cjs → attachmentContent-Bo0UAsSu.cjs} +4 -4
- package/dist/{auth-BmESeKuM.mjs → auth-BS6PaOOG.mjs} +6 -6
- package/dist/{auth-CTECt2Oz.cjs → auth-D6bBUwZa.cjs} +6 -6
- package/dist/{auth-CKdXb9zp.mjs → auth-DMX0xPNK.mjs} +9 -9
- package/dist/{auth-DNxVmVbn.cjs → auth-HEhRaNgL.cjs} +9 -9
- package/dist/{authRelay-DSAvg1uv.mjs → authRelay-DhQhkBvX.mjs} +1 -1
- package/dist/{authRelay-BdYkC1Po.cjs → authRelay-Dy1qU9td.cjs} +1 -0
- package/dist/{auto-D1ypjjfx.cjs → auto-C6I55iOh.cjs} +19 -18
- package/dist/{auto-Ch3203qd.mjs → auto-Cl1SEDcD.mjs} +19 -18
- package/dist/{bootstrap-6OI698q9.cjs → bootstrap-exVucYav.cjs} +2 -2
- package/dist/{bootstrap-C0s2bPFQ.mjs → bootstrap-iuyufnp3.mjs} +2 -2
- package/dist/{browser-DG6Uof5O.cjs → browser-BohJK12g.cjs} +1 -1
- package/dist/{browser-BlLWZUMx.mjs → browser-CSYum7xH.mjs} +1 -1
- package/dist/{claudeLocal-CcWcKnoo.mjs → claudeLocal-Dq_R3Ax_.mjs} +6 -5
- package/dist/{claudeLocal-CemsIArT.cjs → claudeLocal-re4yjSTx.cjs} +6 -5
- package/dist/{claudeLocalLauncher-A4VuevIi.cjs → claudeLocalLauncher-B4hJHpCA.cjs} +11 -10
- package/dist/{claudeLocalLauncher-7p6y88nj.mjs → claudeLocalLauncher-CN67lN7-.mjs} +11 -10
- package/dist/{claudeSessionFork-BtROOjqf.mjs → claudeSessionFork-BihfD0Ik.mjs} +1 -1
- package/dist/{claudeSessionFork-CbDfm8Fz.cjs → claudeSessionFork-DiSMYerV.cjs} +1 -1
- package/dist/{client-DyvBTYee.cjs → client-BKcK1Bi-.cjs} +3 -3
- package/dist/client-BhoEBnuN.mjs +71 -0
- package/dist/{client-COmgDDy0.cjs → client-CuVdN6PP.cjs} +2 -2
- package/dist/{client-BPMWutfs.mjs → client-DuTDwWSQ.mjs} +3 -3
- package/dist/client-ZjOsn6nZ.cjs +76 -0
- package/dist/{client-DG5ndWLw.mjs → client-wo9nbxuf.mjs} +2 -2
- package/dist/codex/happyMcpStdioBridge.cjs +25 -16
- package/dist/codex/happyMcpStdioBridge.mjs +25 -16
- package/dist/{codexAppServerClient-D-Z8qSfI.mjs → codexAppServerClient-BK3zra_1.mjs} +3 -3
- package/dist/{codexAppServerClient-R24WZZfg.cjs → codexAppServerClient-Dt5zxrun.cjs} +3 -3
- package/dist/{codexCommand-CVTkZJ1o.mjs → codexCommand-B6pY7CMh.mjs} +66 -61
- package/dist/{codexCommand-6hW19gsq.cjs → codexCommand-CAZ1SLjg.cjs} +89 -84
- package/dist/{codexTermination-CCIfwzcx.mjs → codexTermination-Cd1Eon_4.mjs} +1 -1
- package/dist/{codexTermination-BBU7e92y.cjs → codexTermination-DmGbHxcD.cjs} +1 -1
- package/dist/{config-CvsNChKX.mjs → config-2oMG_fEI.mjs} +3 -3
- package/dist/{config-DhdrvOLV.cjs → config-B0uK6K7n.cjs} +3 -3
- package/dist/{configuration-DZPy0T9Z.cjs → configuration-CMHZnp6G.cjs} +1 -1
- package/dist/{configuration-D55F0t16.mjs → configuration-WMi4idBB.mjs} +1 -1
- package/dist/{connect-CwCXMRmD.mjs → connect-BLVHhHzA.mjs} +15 -15
- package/dist/{connect-Wz-XZYXW.cjs → connect-uaglGrde.cjs} +15 -15
- package/dist/{context-BKbrZ55r.cjs → context-DXzU5bFM.cjs} +1 -1
- package/dist/{context-CCRpVXFo.mjs → context-DploEcoN.mjs} +1 -1
- package/dist/{controlClient-C4xB5J6O.mjs → controlClient-BWUJrj3t.mjs} +3 -3
- package/dist/{controlClient-SX8gSza2.cjs → controlClient-C-5qCt8W.cjs} +3 -3
- package/dist/{createSessionMetadata-Bi-m0Y_O.mjs → createSessionMetadata-3uXrJgOW.mjs} +2 -2
- package/dist/{createSessionMetadata-BCFmYlBo.cjs → createSessionMetadata-BkIzHALd.cjs} +2 -2
- package/dist/{defaultPermissionMode-wBcbBezm.mjs → defaultPermissionMode-BzxLh20a.mjs} +2 -2
- package/dist/{defaultPermissionMode-DMBEnXll.cjs → defaultPermissionMode-pS3vmiSg.cjs} +2 -2
- package/dist/{deterministicJson-ChGfQEF6.cjs → deterministicJson-B8z2GPi9.cjs} +220 -14
- package/dist/{deterministicJson-BkQETt8_.mjs → deterministicJson-D_whDMFd.mjs} +217 -12
- package/dist/{doctor-BsN3JZJn.cjs → doctor-Br1Kcy2J.cjs} +8 -8
- package/dist/{doctor-B9c2C9dF.mjs → doctor-CmtSsR2-.mjs} +8 -8
- package/dist/{downloadTarget-Dj3WoVJa.cjs → downloadTarget-BQJK_6oH.cjs} +6 -6
- package/dist/{downloadTarget-ByXzbDK4.mjs → downloadTarget-BoNwTIH_.mjs} +6 -6
- package/dist/{ensureDaemonRunning-7Wb8M7Lv.cjs → ensureDaemonRunning-BRUmsq6J.cjs} +5 -5
- package/dist/{ensureDaemonRunning--HYzs5Ce.mjs → ensureDaemonRunning-Czo9IHJQ.mjs} +5 -5
- package/dist/{handleResumeCommand-DHddBkNJ.mjs → handleResumeCommand-C8thKjqf.mjs} +22 -6
- package/dist/{handleResumeCommand-OmuUGYjQ.cjs → handleResumeCommand-tKD_Hpxc.cjs} +22 -6
- package/dist/{index-CrR4JISa.cjs → index-B0UjHlAe.cjs} +5 -5
- package/dist/{index-BzJNDsJq.mjs → index-BTxHphpV.mjs} +254 -49
- package/dist/index-BiyC7cZ3.mjs +18 -0
- package/dist/{index-De8L5lFK.cjs → index-C6O2vVjm.cjs} +156 -34
- package/dist/index-CUuc6iCn.cjs +24 -0
- package/dist/{index-Dhl6_bw7.mjs → index-CdQI0C9p.mjs} +5 -5
- package/dist/{index-D9NoYc5I.cjs → index-D09T1m8Y.cjs} +3 -3
- package/dist/{index-CEm0MYiS.mjs → index-D3bidoG8.mjs} +3 -3
- package/dist/{index-BRJzH4sc.cjs → index-DMqDMT1Q.cjs} +257 -52
- package/dist/{index-DMy3OCBe.mjs → index-DPOa4NhL.mjs} +154 -35
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/dist/{install-BdvKiOQw.mjs → install-BX3lv3NO.mjs} +1 -1
- package/dist/{install-Cf6AFSWC.cjs → install-BXvf2E3o.cjs} +1 -1
- package/dist/{install-1qn-D9FS.cjs → install-CYRZxS87.cjs} +3 -3
- package/dist/{install-BDIUtPXi.mjs → install-hnve_9vq.mjs} +3 -3
- package/dist/lib.cjs +14 -14
- package/dist/lib.d.cts +65 -1
- package/dist/lib.d.mts +65 -1
- package/dist/lib.mjs +14 -14
- package/dist/{lidState-BqVsw7H1.mjs → lidState-Bb8fgXg3.mjs} +2 -2
- package/dist/{lidState-DxbK0qfu.cjs → lidState-Dv2wwFTj.cjs} +2 -2
- package/dist/{localHappyAgentAuth-D5tANdRD.cjs → localHappyAgentAuth-DjYvkXvV.cjs} +2 -2
- package/dist/{localHappyAgentAuth-Ce8kO2yc.mjs → localHappyAgentAuth-NEU7fax7.mjs} +2 -2
- package/dist/{logger-13cBr_ew.mjs → logger-BtVhHnD8.mjs} +2 -2
- package/dist/{logger-LvwVeATU.cjs → logger-C1GWx3gi.cjs} +2 -2
- package/dist/{machineMetadata-29h7vgf4.cjs → machineMetadata-CLHS9sv_.cjs} +3 -3
- package/dist/{machineMetadata-dMida2qq.mjs → machineMetadata-D-g--oU_.mjs} +3 -3
- package/dist/{main-x4nAhdH5.mjs → main-B2LWV8DI.mjs} +59 -46
- package/dist/{main-DpM5jaFH.cjs → main-CWhSsbtU.cjs} +59 -46
- package/dist/{mcp-DQv3caXs.cjs → mcp-CARUsXHV.cjs} +15 -15
- package/dist/{mcp-DMiFGYMT.mjs → mcp-ext92q3Y.mjs} +15 -15
- package/dist/{mirrorProtocol-Bz8tEabR.mjs → mirrorProtocol-BwYibqry.mjs} +3 -3
- package/dist/{mirrorProtocol-BfrERW7Z.cjs → mirrorProtocol-DEy2g1CB.cjs} +3 -3
- package/dist/{package-CjlsAaRe.mjs → package-BPPebGQF.mjs} +7 -7
- package/dist/{package-Ch9WGDV_.cjs → package-SgqTYsjn.cjs} +7 -7
- package/dist/panels-BZ0_Tt7B.mjs +137 -0
- package/dist/panels-D1c7q2dD.cjs +142 -0
- package/dist/{peerTools-CxmrKnfV.mjs → peerTools-CWKzcQ7u.mjs} +60 -10
- package/dist/{peerTools-DtGKWli5.cjs → peerTools-DRQETXaz.cjs} +60 -9
- package/dist/{persistence-DXbKOHxl.cjs → persistence-BegE7NPa.cjs} +14 -3
- package/dist/{persistence-C_tYtOqK.mjs → persistence-Cr-wutZ4.mjs} +14 -4
- package/dist/{piRunnerArgs-BVRZe2AR.cjs → piRunnerArgs-Cs-378Vz.cjs} +8 -2
- package/dist/{piRunnerArgs-BpHc-JZl.mjs → piRunnerArgs-DwvM_yWA.mjs} +7 -1
- package/dist/{piRuntime-D7eio8Ix.cjs → piRuntime-BG-1td_n.cjs} +2 -2
- package/dist/{piRuntime-DOdGF395.mjs → piRuntime-Bue5mnlc.mjs} +2 -2
- package/dist/{piTerminal-dpxz4Q8D.mjs → piTerminal-B5x9X5yV.mjs} +18 -18
- package/dist/{piTerminal-y_PRo2NY.cjs → piTerminal-G4z-xVyy.cjs} +18 -18
- package/dist/processTreeSnapshot-CuLJDNC-.mjs +101 -0
- package/dist/processTreeSnapshot-mDbnuojn.cjs +105 -0
- package/dist/prompt-BOouDaTM.mjs +99 -0
- package/dist/prompt-lgF9IE82.cjs +105 -0
- package/dist/{attachmentLimits-Di1Z93lN.mjs → pushNotifications-BdFjDjQe.mjs} +303 -3
- package/dist/{attachmentLimits-DtFqqiwR.cjs → pushNotifications-DaLQUyi0.cjs} +304 -2
- package/dist/{index-DFPT4HOO.cjs → query-Ctfg-5gy.cjs} +25 -5
- package/dist/{index-CEjJnq05.mjs → query-DYP_W1wp.mjs} +26 -3
- package/dist/{rateLimitWindows-DYHDGuzQ.mjs → rateLimitWindows-CuEqk_0g.mjs} +1 -1
- package/dist/{rateLimitWindows-DFnMU2Vt.cjs → rateLimitWindows-Dj_8voBK.cjs} +1 -1
- package/dist/{registerCommonHandlers-D8OMpBbQ.mjs → registerCommonHandlers-BAlP7SGc.mjs} +2 -2
- package/dist/{registerCommonHandlers-60VuTkdg.cjs → registerCommonHandlers-Cj084Sg7.cjs} +2 -2
- package/dist/{registerKillSessionHandler-Drhf7-Vz.mjs → registerKillSessionHandler-PD0jWtQo.mjs} +6 -6
- package/dist/{registerKillSessionHandler-pqChBKwO.cjs → registerKillSessionHandler-qMju0ZfF.cjs} +6 -6
- package/dist/{remoteSessionClient-B7NvjHD3.cjs → remoteSessionClient-B7i7MkYV.cjs} +5 -5
- package/dist/{remoteSessionClient-D01Hso2-.mjs → remoteSessionClient-Bn2qu5C5.mjs} +5 -5
- package/dist/{reportProgressTool-Du_zAK4h.cjs → reportProgressTool-CM1JFAHg.cjs} +84 -2
- package/dist/{reportProgressTool-B203EZCR.mjs → reportProgressTool-gHItlSzz.mjs} +82 -3
- package/dist/{resources-JDPugcDq.cjs → resources-CvIlkzpP.cjs} +30 -0
- package/dist/{resources-BdFBQi8r.mjs → resources-y9jfyO-_.mjs} +30 -0
- package/dist/{run-DX4Zs3Ug.mjs → run-BM4TxiyN.mjs} +249 -45
- package/dist/{run-DZ5jU53c.cjs → run-CNXwIe0A.cjs} +263 -59
- package/dist/{runClaude-ClRhHpwR.cjs → runClaude-CWhj2V4Q.cjs} +37 -41
- package/dist/{runClaude-CgPHXP0L.mjs → runClaude-C_3I8hvR.mjs} +37 -41
- package/dist/{runClaudeDeps-D2v_WDSL.cjs → runClaudeDeps-B81cOKnH.cjs} +295 -157
- package/dist/{runClaudeDeps-Dz2iydq4.mjs → runClaudeDeps-QGrOeDe2.mjs} +295 -160
- package/dist/{runGemini-DBXxpoY8.mjs → runGemini-BEdWEZLR.mjs} +61 -55
- package/dist/{runGemini-BtZqGFkp.cjs → runGemini-CgRLYbt5.cjs} +61 -55
- package/dist/{runOpenClaw-D8q8G57u.cjs → runOpenClaw-C1NVmzOL.cjs} +19 -19
- package/dist/{runOpenClaw-BOHpzCEU.mjs → runOpenClaw-DdQZAYj1.mjs} +19 -19
- package/dist/{sandbox-C452Vrsc.mjs → sandbox-DjQUdCMG.mjs} +5 -5
- package/dist/{sandbox-Cu9mMzjx.cjs → sandbox-nocIjliq.cjs} +5 -5
- package/dist/selfCheck-CjCF4C3v.mjs +85 -0
- package/dist/{selfCheck-gKa3uVr1.cjs → selfCheck-DCt4Uzbq.cjs} +36 -35
- package/dist/{send-B8HARi7x.mjs → send-Ct7X4pPU.mjs} +9 -9
- package/dist/{send-2Vb5eppI.cjs → send-Dydf_hwZ.cjs} +9 -9
- package/dist/{server-Db9Wuam3.cjs → server-CosABFbd.cjs} +7 -7
- package/dist/{server-BBWCIZyS.mjs → server-DTQGZMxh.mjs} +5 -5
- package/dist/{sessionLock-6qL_N6Rn.cjs → sessionLock-DokGab2R.cjs} +16 -3
- package/dist/{sessionLock-ZfvFVdUi.mjs → sessionLock-WYIyaVO4.mjs} +16 -4
- package/dist/{sessionOps-CdgbEJgf.mjs → sessionOps-BIGgRube.mjs} +11 -6
- package/dist/{sessionOps-Dmt7WUUs.cjs → sessionOps-S-qPBLFf.cjs} +11 -6
- package/dist/{sessionScanner-CQL_WSaC.cjs → sessionScanner-CIMM2hvZ.cjs} +3 -3
- package/dist/{sessionScanner-CNVaSNOn.mjs → sessionScanner-o5hnMi5e.mjs} +3 -3
- package/dist/{sessions-DTomHfFg.mjs → sessions-BJHEZpi2.mjs} +40 -18
- package/dist/{sessions-BJblG_Hx.cjs → sessions-JchI1w3z.cjs} +40 -17
- package/dist/{setupOfflineReconnection-DVA0VpQL.cjs → setupOfflineReconnection-CNiAt5ZP.cjs} +2 -2
- package/dist/{setupOfflineReconnection-C5trsV-j.mjs → setupOfflineReconnection-DMiBO2y9.mjs} +2 -2
- package/dist/{spawn-DRyNAqD8.cjs → spawn-6PD7nnoC.cjs} +49 -18
- package/dist/{spawn-CQJFgoOq.mjs → spawn-DgvUNYEo.mjs} +49 -18
- package/dist/{spawnAgents-CCjJifAW.cjs → spawnAgents-DsXgegHM.cjs} +37 -1
- package/dist/spawnAgents-P006Hqio.mjs +79 -0
- package/dist/{spawnHappyCLI-B_0RWxD4.mjs → spawnHappyCLI-CCOrEtf9.mjs} +1 -1
- package/dist/{spawnHappyCLI-ChniczJ5.cjs → spawnHappyCLI-Dywezwk6.cjs} +1 -1
- package/dist/{specialCommands-DkdFJi4N.mjs → specialCommands-DPcd9edP.mjs} +3 -3
- package/dist/{specialCommands-DbntVs0d.cjs → specialCommands-QxPpkGKf.cjs} +3 -3
- package/dist/{startFileWatcher-UQyTSRAP.mjs → startFileWatcher-DghDOCO4.mjs} +1 -1
- package/dist/{startFileWatcher-C292fhra.cjs → startFileWatcher-RECH5qY8.cjs} +1 -1
- package/dist/{streamRelay-_qCd873P.mjs → streamRelay-DMV_TXfS.mjs} +1 -1
- package/dist/{streamRelay-Cx01enfe.cjs → streamRelay-DlUWKUpo.cjs} +1 -1
- package/dist/{sync-C3p7-KLn.mjs → sync-CSe0Rf45.mjs} +1 -1
- package/dist/{sync-C7sxoUYG.cjs → sync-D23jbqVa.cjs} +1 -1
- package/dist/{systemPrompt-DtibzbRU.cjs → systemPrompt-BOy4kU4P.cjs} +4 -3
- package/dist/{systemPrompt-CdHOlyVW.mjs → systemPrompt-CFNKnh65.mjs} +4 -3
- package/dist/{teams-ujXr3AFn.mjs → teams-DyY669f0.mjs} +9 -9
- package/dist/{teams-D7O7TpVU.cjs → teams-Ov2BDT-A.cjs} +9 -9
- package/dist/{time-yEL6wHUF.mjs → time-65DcU6Jx.mjs} +1 -1
- package/dist/{time-Dg5tVB8S.cjs → time-CrwIMHta.cjs} +1 -1
- package/dist/{titleGenerator-BMEaDTwU.cjs → titleGenerator-CS_rh2_J.cjs} +9 -8
- package/dist/{titleGenerator-Dr-BtjzO.mjs → titleGenerator-CiAMxf7s.mjs} +9 -8
- package/dist/{todo-CvJe4M2C.mjs → todo-BDONw0sK.mjs} +7 -7
- package/dist/{todo-CUcFamGs.cjs → todo-KY-okGii.cjs} +7 -7
- package/dist/{tools-BrM3bZW5.mjs → tools-D8-PnZEG.mjs} +1 -1
- package/dist/{tools-DDKTB5aQ.cjs → tools-_w52DZG6.cjs} +1 -1
- package/dist/{uninstall-7oLuhYIu.cjs → uninstall-8vnLN-IE.cjs} +3 -3
- package/dist/{uninstall-CEcMMQGz.mjs → uninstall-_fjGRP9b.mjs} +3 -3
- package/dist/webPanels-B2_C2-3g.mjs +49 -0
- package/dist/webPanels-FCgFKvVe.cjs +53 -0
- package/package.json +7 -7
- package/dist/selfCheck-BAvqBwBR.mjs +0 -84
- package/dist/sessionModeFile-CWVq8AT9.mjs +0 -32
- package/dist/sessionModeFile-CsLtn_PL.cjs +0 -36
- package/dist/spawnAgents-BjtmjBvP.mjs +0 -45
|
@@ -1,28 +1,126 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var logger = require('./logger-C1GWx3gi.cjs');
|
|
4
|
+
var prompt = require('./prompt-lgF9IE82.cjs');
|
|
5
|
+
var client = require('./client-ZjOsn6nZ.cjs');
|
|
6
|
+
var reportProgressTool = require('./reportProgressTool-CM1JFAHg.cjs');
|
|
7
|
+
var index = require('./index-C6O2vVjm.cjs');
|
|
4
8
|
var promises = require('node:fs/promises');
|
|
5
9
|
var node_crypto = require('node:crypto');
|
|
6
10
|
var node_fs = require('node:fs');
|
|
7
11
|
var path = require('node:path');
|
|
8
12
|
var z = require('zod');
|
|
9
|
-
var client = require('./client-
|
|
10
|
-
var context = require('./context-
|
|
11
|
-
var sessionOps = require('./sessionOps-
|
|
12
|
-
var resources = require('./resources-
|
|
13
|
-
var tools = require('./tools-
|
|
14
|
-
var
|
|
15
|
-
var peerTools = require('./peerTools-DtGKWli5.cjs');
|
|
13
|
+
var client$1 = require('./client-BKcK1Bi-.cjs');
|
|
14
|
+
var context = require('./context-DXzU5bFM.cjs');
|
|
15
|
+
var sessionOps = require('./sessionOps-S-qPBLFf.cjs');
|
|
16
|
+
var resources = require('./resources-CvIlkzpP.cjs');
|
|
17
|
+
var tools = require('./tools-_w52DZG6.cjs');
|
|
18
|
+
var peerTools = require('./peerTools-DRQETXaz.cjs');
|
|
16
19
|
var mcp_js = require('@modelcontextprotocol/sdk/server/mcp.js');
|
|
17
20
|
var node_http = require('node:http');
|
|
18
21
|
var streamableHttp_js = require('@modelcontextprotocol/sdk/server/streamableHttp.js');
|
|
19
|
-
var logger = require('./logger-LvwVeATU.cjs');
|
|
20
22
|
var limits = require('./limits-C-a7gr04.cjs');
|
|
21
|
-
var downloadTarget = require('./downloadTarget-
|
|
23
|
+
var downloadTarget = require('./downloadTarget-BQJK_6oH.cjs');
|
|
22
24
|
var agentGuidance = require('./agentGuidance-BtBx2xxE.cjs');
|
|
25
|
+
var webPanels = require('./webPanels-FCgFKvVe.cjs');
|
|
26
|
+
var persistence = require('./persistence-BegE7NPa.cjs');
|
|
27
|
+
var pushNotifications = require('./pushNotifications-DaLQUyi0.cjs');
|
|
23
28
|
var previewPath = require('./previewPath-B0rBdhy1.cjs');
|
|
24
29
|
var crypto = require('crypto');
|
|
25
30
|
|
|
31
|
+
function createProjectInjector(deps) {
|
|
32
|
+
const timeoutMs = deps.timeoutMs ?? 1500;
|
|
33
|
+
const now = deps.now ?? Date.now;
|
|
34
|
+
const presenceEvery = deps.presenceMinIntervalMs ?? 3e4;
|
|
35
|
+
const state = { projectId: null, prefixSent: false, cursor: 0, injectedVersion: null };
|
|
36
|
+
const titles = /* @__PURE__ */ new Map();
|
|
37
|
+
let lastPresenceAt = 0;
|
|
38
|
+
let lastPresenceVersion = null;
|
|
39
|
+
const label = (id) => titles.get(id) ?? id.slice(0, 8);
|
|
40
|
+
function withTimeout(p) {
|
|
41
|
+
return Promise.race([p, new Promise((_, reject) => setTimeout(() => reject(new Error("project injection timeout")), timeoutMs).unref?.())]);
|
|
42
|
+
}
|
|
43
|
+
function reportPresence(force) {
|
|
44
|
+
const sid = deps.sessionId();
|
|
45
|
+
const meta = deps.metadata?.() ?? null;
|
|
46
|
+
const machineId = typeof meta?.machineId === "string" ? meta.machineId : null;
|
|
47
|
+
if (!sid || !machineId || !state.projectId) return;
|
|
48
|
+
const t = now();
|
|
49
|
+
if (!force && state.injectedVersion === lastPresenceVersion && t - lastPresenceAt < presenceEvery) return;
|
|
50
|
+
lastPresenceAt = t;
|
|
51
|
+
lastPresenceVersion = state.injectedVersion;
|
|
52
|
+
const entry = {
|
|
53
|
+
sessionId: sid,
|
|
54
|
+
agent: deps.agent,
|
|
55
|
+
state: "running",
|
|
56
|
+
injectedInstructionsVersion: state.injectedVersion,
|
|
57
|
+
...typeof meta?.summary?.text === "string" ? { title: String(meta.summary.text).slice(0, 200) } : {},
|
|
58
|
+
...typeof meta?.board?.progress === "string" ? { doing: String(meta.board.progress).slice(0, 200) } : {},
|
|
59
|
+
...typeof meta?.worktree?.branch === "string" ? { branch: String(meta.worktree.branch).slice(0, 200) } : {},
|
|
60
|
+
...typeof meta?.host === "string" ? { machine: String(meta.host).slice(0, 200) } : {},
|
|
61
|
+
...Array.isArray(meta?.capabilities) ? { capabilities: meta.capabilities.filter((c) => typeof c === "string").slice(0, 32) } : {}
|
|
62
|
+
};
|
|
63
|
+
void deps.client.presence(machineId, [entry]).catch((error) => logger.logger.debug(`[projects] presence write skipped: ${String(error)}`));
|
|
64
|
+
}
|
|
65
|
+
function markDelivered(sid, ids) {
|
|
66
|
+
if (ids.length) void deps.client.delivered(sid, ids).catch((error) => logger.logger.debug(`[projects] delivered ack skipped: ${String(error)}`));
|
|
67
|
+
}
|
|
68
|
+
async function firstTurn(sid, message) {
|
|
69
|
+
const ctx = await withTimeout(deps.client.context(sid, {}, timeoutMs));
|
|
70
|
+
for (const s of ctx.sessions) if (s.title) titles.set(s.sessionId, s.title);
|
|
71
|
+
const built = prompt.buildFirstTurnPrefix(ctx, { label });
|
|
72
|
+
if (!built || !ctx.project) {
|
|
73
|
+
state.projectId = null;
|
|
74
|
+
return message;
|
|
75
|
+
}
|
|
76
|
+
state.projectId = ctx.project.id;
|
|
77
|
+
state.prefixSent = true;
|
|
78
|
+
state.cursor = ctx.asOf;
|
|
79
|
+
state.injectedVersion = built.instructionsVersion;
|
|
80
|
+
markDelivered(sid, ctx.unread.map((u) => u.id));
|
|
81
|
+
reportPresence(true);
|
|
82
|
+
return prompt.prependToMessage(message, built.prefix);
|
|
83
|
+
}
|
|
84
|
+
async function laterTurn(sid, message) {
|
|
85
|
+
const d = await withTimeout(deps.client.digest(sid, state.cursor, timeoutMs));
|
|
86
|
+
if (!d.projectId) {
|
|
87
|
+
state.projectId = null;
|
|
88
|
+
state.prefixSent = false;
|
|
89
|
+
state.injectedVersion = null;
|
|
90
|
+
return message;
|
|
91
|
+
}
|
|
92
|
+
if (d.projectId !== state.projectId) {
|
|
93
|
+
state.prefixSent = false;
|
|
94
|
+
return firstTurn(sid, message);
|
|
95
|
+
}
|
|
96
|
+
state.cursor = d.asOf;
|
|
97
|
+
if (d.instructions) state.injectedVersion = d.instructions.version;
|
|
98
|
+
markDelivered(sid, d.messages.map((m) => m.id));
|
|
99
|
+
reportPresence(!!d.instructions);
|
|
100
|
+
return prompt.prependToMessage(message, prompt.buildDigestLine(d, { label }));
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
state: () => ({ ...state }),
|
|
104
|
+
/** A fresh agent with no memory of earlier turns (ACP backend restart, new Claude conversation) needs P again. */
|
|
105
|
+
reset() {
|
|
106
|
+
state.prefixSent = false;
|
|
107
|
+
state.cursor = 0;
|
|
108
|
+
},
|
|
109
|
+
async decorate(message) {
|
|
110
|
+
if (typeof message !== "string") return message;
|
|
111
|
+
const sid = deps.sessionId();
|
|
112
|
+
if (!sid || deps.client.isDisabled()) return message;
|
|
113
|
+
try {
|
|
114
|
+
const out = state.prefixSent ? await laterTurn(sid, message) : await firstTurn(sid, message);
|
|
115
|
+
return out;
|
|
116
|
+
} catch (error) {
|
|
117
|
+
if (!(error instanceof client.ProjectsUnsupportedError)) logger.logger.debug(`[projects] injection skipped: ${String(error)}`);
|
|
118
|
+
return message;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
26
124
|
const TEAMS_ADOPT_CAPABILITY = "teams-adopt-v1";
|
|
27
125
|
const TeamAdoptSchema = z.z.object({
|
|
28
126
|
requestId: z.z.string().min(1).max(128),
|
|
@@ -78,7 +176,7 @@ async function retainTeam(path, input, resolvedTeamId, guidanceDelivered = false
|
|
|
78
176
|
}
|
|
79
177
|
}
|
|
80
178
|
function createTeamAdoption(sessionId) {
|
|
81
|
-
const client
|
|
179
|
+
const client = client$1.createTeamsClient(sessionId);
|
|
82
180
|
let current;
|
|
83
181
|
return (raw) => {
|
|
84
182
|
const parsed = TeamAdoptSchema.safeParse(raw);
|
|
@@ -107,7 +205,7 @@ function createTeamAdoption(sessionId) {
|
|
|
107
205
|
let intent;
|
|
108
206
|
try {
|
|
109
207
|
intent = await retainIntent(path, input);
|
|
110
|
-
const connected = await client
|
|
208
|
+
const connected = await client.initialize(input, { resumeAdoption: true, expectedTeamId: intent.resolvedTeamId, onTeamResolved: (teamId) => retainTeam(path, input, teamId, intent?.guidanceDelivered) });
|
|
111
209
|
const instructions = `${resources.TEAM_SKILL}
|
|
112
210
|
|
|
113
211
|
This session is now connected as the team lead. Call team_inspect to read the authoritative state before continuing the user's goal. Do not call team_create or team_join again.`;
|
|
@@ -118,7 +216,7 @@ This session is now connected as the team lead. Call team_inspect to read the au
|
|
|
118
216
|
}
|
|
119
217
|
operation.result = { status: "connected", teamId: connected.team.id, botId: connected.botId, instructions };
|
|
120
218
|
} catch (error) {
|
|
121
|
-
if (error instanceof client.TeamConnectionPreflightError && intent?.fresh && !intent.resolvedTeamId) {
|
|
219
|
+
if (error instanceof client$1.TeamConnectionPreflightError && intent?.fresh && !intent.resolvedTeamId) {
|
|
122
220
|
await promises.unlink(path).catch(() => {
|
|
123
221
|
});
|
|
124
222
|
operation.safeToChange = true;
|
|
@@ -130,6 +228,41 @@ This session is now connected as the team lead. Call team_inspect to read the au
|
|
|
130
228
|
};
|
|
131
229
|
}
|
|
132
230
|
|
|
231
|
+
const REQUEST_HUMAN_TOOL_NAME = "request_human";
|
|
232
|
+
const REQUEST_HUMAN_REASON_MAX = 200;
|
|
233
|
+
const REQUEST_HUMAN_DEDUPE_MS = 6e4;
|
|
234
|
+
const REQUEST_HUMAN_TOOL_DESCRIPTION = "Ask the user to step in when you cannot continue on your own: a captcha, 2FA code, QR scan, OAuth consent page, or a decision only they can make. Sends a push notification and marks the task board as blocked. Give a short reason (no secrets; the server can read it). If this machine declares a web panel showing what you are working in (e.g. a remote desktop or browser dashboard), pass its id as `panel` so the notification opens it. Afterwards, poll for your own completion condition (the page changed, the element disappeared) instead of waiting for a reply.";
|
|
235
|
+
function createRequestHuman(deps) {
|
|
236
|
+
const now = deps.now ?? Date.now;
|
|
237
|
+
let last = null;
|
|
238
|
+
return async (rawReason, panel) => {
|
|
239
|
+
const reason = rawReason.replace(/\s+/g, " ").trim().slice(0, REQUEST_HUMAN_REASON_MAX);
|
|
240
|
+
if (!reason) return { notified: false, error: "reason must be a non-empty string" };
|
|
241
|
+
await deps.reportBlocked(reason);
|
|
242
|
+
const at = now();
|
|
243
|
+
if (last && last.reason === reason && at - last.at < REQUEST_HUMAN_DEDUPE_MS) {
|
|
244
|
+
return { notified: true, deduped: true };
|
|
245
|
+
}
|
|
246
|
+
let url = `/session/${encodeURIComponent(deps.sessionId)}`;
|
|
247
|
+
let unknownPanel;
|
|
248
|
+
if (panel) {
|
|
249
|
+
const machineId = deps.machineId();
|
|
250
|
+
const { panels } = webPanels.normalizeWebPanels(await deps.readPanels().catch(() => void 0));
|
|
251
|
+
if (machineId && panels.some((p) => p.id === panel)) url = webPanels.webPanelPath(machineId, panel);
|
|
252
|
+
else unknownPanel = panel;
|
|
253
|
+
}
|
|
254
|
+
const sent = await deps.sendAttention({ sessionId: deps.sessionId, reason, url });
|
|
255
|
+
if (sent.sent) last = { reason, at };
|
|
256
|
+
return { notified: sent.sent, url, ...unknownPanel ? { unknownPanel } : {}, ...sent.error ? { error: sent.error } : {} };
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
function requestHumanResultText(r) {
|
|
260
|
+
if (r.deduped) return "Already asked for this in the last minute; the board still shows it. Keep polling your completion condition.";
|
|
261
|
+
if (!r.notified) return `Could not notify the user: ${r.error ?? "unknown error"}. The task board is marked blocked.`;
|
|
262
|
+
const panelNote = r.unknownPanel ? ` (panel "${r.unknownPanel}" is not declared on this machine, so the notification opens the session instead)` : "";
|
|
263
|
+
return `Notified the user${panelNote}. This does not mean they have seen it. Poll your own completion condition (URL changed, element gone) instead of waiting for a reply.`;
|
|
264
|
+
}
|
|
265
|
+
|
|
133
266
|
function createMcpServer(handlers, options, sessionId, client) {
|
|
134
267
|
const mcp = new mcp_js.McpServer({
|
|
135
268
|
name: "Very Happy Tools",
|
|
@@ -138,6 +271,7 @@ function createMcpServer(handlers, options, sessionId, client) {
|
|
|
138
271
|
tools.registerTeamsTools(mcp, sessionId);
|
|
139
272
|
reportProgressTool.registerAutomationTools(mcp);
|
|
140
273
|
if (client) peerTools.registerSessionPeerTools(mcp, peerTools.createSessionPeerToolExecutor(client));
|
|
274
|
+
if (client) reportProgressTool.registerProjectTools(mcp, reportProgressTool.createProjectToolExecutor(() => client.sessionId));
|
|
141
275
|
mcp.registerTool("change_title", {
|
|
142
276
|
description: "Change the title of the current chat session",
|
|
143
277
|
title: "Change Chat Title",
|
|
@@ -224,6 +358,18 @@ function createMcpServer(handlers, options, sessionId, client) {
|
|
|
224
358
|
isError: true
|
|
225
359
|
};
|
|
226
360
|
});
|
|
361
|
+
mcp.registerTool(REQUEST_HUMAN_TOOL_NAME, {
|
|
362
|
+
description: REQUEST_HUMAN_TOOL_DESCRIPTION,
|
|
363
|
+
title: "Ask the user to step in",
|
|
364
|
+
inputSchema: {
|
|
365
|
+
reason: z.z.string().describe("What you need from the user, one short line (no secrets)"),
|
|
366
|
+
panel: z.z.string().optional().describe("Id of this machine's web panel that shows what you are working in (from ~/.happy/settings.json webPanels)")
|
|
367
|
+
}
|
|
368
|
+
}, async (args) => {
|
|
369
|
+
const response = await handlers.requestHuman(String(args.reason ?? ""), args.panel);
|
|
370
|
+
logger.logger.debug("[happyMCP] request_human response:", response);
|
|
371
|
+
return { content: [{ type: "text", text: requestHumanResultText(response) }], isError: response.error === "reason must be a non-empty string" };
|
|
372
|
+
});
|
|
227
373
|
reportProgressTool.registerReportProgressTool(mcp, async (args) => {
|
|
228
374
|
const response = await handlers.reportProgress(String(args.progress ?? ""), reportProgressTool.normalizeAttention(args.attention), reportProgressTool.normalizePhase(args.phase));
|
|
229
375
|
logger.logger.debug("[happyMCP] report_progress response:", response);
|
|
@@ -321,10 +467,66 @@ async function startHappyServer(client, options) {
|
|
|
321
467
|
} catch (error) {
|
|
322
468
|
return { delivered: false, truncated: false, totalBytes: 0, error: String(error) };
|
|
323
469
|
}
|
|
324
|
-
}
|
|
470
|
+
},
|
|
471
|
+
requestHuman: createRequestHuman({
|
|
472
|
+
sessionId: client.sessionId,
|
|
473
|
+
machineId: () => client.getMetadata()?.machineId,
|
|
474
|
+
readPanels: async () => (await persistence.readSettings()).webPanels,
|
|
475
|
+
// Same board write (and attention-change throttle bypass) as report_progress.
|
|
476
|
+
reportBlocked: (reason) => handlers.reportProgress(reason, "blocked"),
|
|
477
|
+
sendAttention: (input) => options?.push ? options.push.sendAttention({ ...input, sessionTitle: pushNotifications.getSessionNotificationBody(client.getMetadata()) }) : Promise.resolve({ sent: false, error: "push is not available in this runner" })
|
|
478
|
+
})
|
|
325
479
|
};
|
|
326
480
|
const contextPath = "/runtime-context/" + node_crypto.randomUUID();
|
|
481
|
+
const steerPath = "/runtime-steer/" + node_crypto.randomUUID();
|
|
327
482
|
const server = node_http.createServer(async (req, res) => {
|
|
483
|
+
if (req.url?.startsWith("/runtime-steer/")) {
|
|
484
|
+
const steer = options?.piSteer;
|
|
485
|
+
if (!steer || req.headers.origin) {
|
|
486
|
+
res.writeHead(403).end();
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
if (req.method === "GET" && req.url === steerPath) {
|
|
490
|
+
const gone = new AbortController();
|
|
491
|
+
res.on("close", () => gone.abort());
|
|
492
|
+
const item = await steer.take(25e3, gone.signal);
|
|
493
|
+
if (res.writableEnded || gone.signal.aborted) {
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
if (!item) {
|
|
497
|
+
res.writeHead(204).end();
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify(item));
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
if (req.method === "POST" && (req.url === steerPath + "/hello" || req.url === steerPath + "/ack")) {
|
|
504
|
+
let body = "";
|
|
505
|
+
for await (const chunk of req) {
|
|
506
|
+
body += chunk.toString();
|
|
507
|
+
if (Buffer.byteLength(body) > 1024) {
|
|
508
|
+
res.writeHead(413).end();
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
if (req.url.endsWith("/hello")) {
|
|
513
|
+
steer.hello();
|
|
514
|
+
res.writeHead(204).end();
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
try {
|
|
518
|
+
const ack = JSON.parse(body);
|
|
519
|
+
if (typeof ack.id !== "number") throw new Error("id");
|
|
520
|
+
steer.ack(ack.id, ack.delivered === true);
|
|
521
|
+
res.writeHead(204).end();
|
|
522
|
+
} catch {
|
|
523
|
+
res.writeHead(400).end();
|
|
524
|
+
}
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
res.writeHead(403).end();
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
328
530
|
if (req.url?.startsWith("/runtime-context/")) {
|
|
329
531
|
if (!options?.onContextUsage || req.url !== contextPath || req.method !== "POST" || req.headers.origin) {
|
|
330
532
|
res.writeHead(403).end();
|
|
@@ -381,14 +583,17 @@ async function startHappyServer(client, options) {
|
|
|
381
583
|
return {
|
|
382
584
|
url: baseUrl.toString(),
|
|
383
585
|
contextUsageUrl: options?.onContextUsage ? new URL(contextPath, baseUrl).toString() : void 0,
|
|
586
|
+
steerUrl: options?.piSteer ? new URL(steerPath, baseUrl).toString() : void 0,
|
|
384
587
|
toolNames: [
|
|
385
588
|
"change_title",
|
|
386
589
|
limits.CLIPBOARD_TOOL_NAME,
|
|
387
590
|
agentGuidance.PREVIEW_TOOL_NAME,
|
|
388
591
|
agentGuidance.REPORT_PROGRESS_TOOL_NAME,
|
|
592
|
+
REQUEST_HUMAN_TOOL_NAME,
|
|
389
593
|
...tools.TEAM_TOOL_NAMES,
|
|
390
594
|
...reportProgressTool.AUTOMATION_TOOL_NAMES,
|
|
391
595
|
...peerTools.SESSION_PEER_TOOL_NAMES,
|
|
596
|
+
...reportProgressTool.PROJECT_TOOL_NAMES,
|
|
392
597
|
...options?.assistant && !process.env.VH_TEAM_SCOPE_FILE ? downloadTarget.ASSISTANT_TOOL_NAMES : []
|
|
393
598
|
],
|
|
394
599
|
stop: () => {
|
|
@@ -485,5 +690,6 @@ function hashObject(obj, options, encoding = "hex") {
|
|
|
485
690
|
return crypto.createHash("sha256").update(jsonString).digest(encoding);
|
|
486
691
|
}
|
|
487
692
|
|
|
693
|
+
exports.createProjectInjector = createProjectInjector;
|
|
488
694
|
exports.hashObject = hashObject;
|
|
489
695
|
exports.startHappyServer = startHappyServer;
|
|
@@ -1,26 +1,124 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { l as logger } from './logger-BtVhHnD8.mjs';
|
|
2
|
+
import { p as prependToMessage, b as buildDigestLine, a as buildFirstTurnPrefix } from './prompt-BOouDaTM.mjs';
|
|
3
|
+
import { P as ProjectsUnsupportedError } from './client-BhoEBnuN.mjs';
|
|
4
|
+
import { c as createSelfReportState, A as AUTOMATION_TOOL_NAMES, P as PROJECT_TOOL_NAMES, r as registerAutomationTools, a as registerProjectTools, d as createProjectToolExecutor, b as registerReportProgressTool, n as normalizeAttention, e as normalizePhase, f as normalizeProgress, s as shouldAcceptSelfReport } from './reportProgressTool-gHItlSzz.mjs';
|
|
5
|
+
import { C as ContextUsageSchema } from './index-DPOa4NhL.mjs';
|
|
2
6
|
import { unlink, mkdir, open, rename } from 'node:fs/promises';
|
|
3
7
|
import { randomUUID } from 'node:crypto';
|
|
4
8
|
import { constants } from 'node:fs';
|
|
5
9
|
import { dirname } from 'node:path';
|
|
6
10
|
import { z } from 'zod';
|
|
7
|
-
import { T as TeamConnectionPreflightError, c as createTeamsClient } from './client-
|
|
8
|
-
import { t as teamScopePath } from './context-
|
|
9
|
-
import { g as waitForSessionKey, e as sendUserMessage } from './sessionOps-
|
|
10
|
-
import { T as TEAM_SKILL } from './resources-
|
|
11
|
-
import { T as TEAM_TOOL_NAMES, r as registerTeamsTools } from './tools-
|
|
12
|
-
import {
|
|
13
|
-
import { S as SESSION_PEER_TOOL_NAMES, r as registerSessionPeerTools, a as createSessionPeerToolExecutor } from './peerTools-CxmrKnfV.mjs';
|
|
11
|
+
import { T as TeamConnectionPreflightError, c as createTeamsClient } from './client-DuTDwWSQ.mjs';
|
|
12
|
+
import { t as teamScopePath } from './context-DploEcoN.mjs';
|
|
13
|
+
import { g as waitForSessionKey, e as sendUserMessage } from './sessionOps-BIGgRube.mjs';
|
|
14
|
+
import { T as TEAM_SKILL } from './resources-y9jfyO-_.mjs';
|
|
15
|
+
import { T as TEAM_TOOL_NAMES, r as registerTeamsTools } from './tools-D8-PnZEG.mjs';
|
|
16
|
+
import { S as SESSION_PEER_TOOL_NAMES, r as registerSessionPeerTools, a as createSessionPeerToolExecutor } from './peerTools-CWKzcQ7u.mjs';
|
|
14
17
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
15
18
|
import { createServer } from 'node:http';
|
|
16
19
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
17
|
-
import { l as logger } from './logger-13cBr_ew.mjs';
|
|
18
20
|
import { C as CLIPBOARD_TOOL_NAME, a as CLIPBOARD_TOOL_TITLE, b as CLIPBOARD_TOOL_DESCRIPTION, c as CLIPBOARD_MAX_BYTES } from './limits-DIo7rEBR.mjs';
|
|
19
|
-
import { A as ASSISTANT_TOOL_NAMES, a as registerAssistantTools, c as checkDownloadTarget } from './downloadTarget-
|
|
21
|
+
import { A as ASSISTANT_TOOL_NAMES, a as registerAssistantTools, c as checkDownloadTarget } from './downloadTarget-BoNwTIH_.mjs';
|
|
20
22
|
import { P as PREVIEW_TOOL_NAME, R as REPORT_PROGRESS_TOOL_NAME, a as PREVIEW_TOOL_TITLE, b as PREVIEW_TOOL_DESCRIPTION, c as PREVIEW_DOWNLOAD_PARAM_DESCRIPTION } from './agentGuidance-BDYt2Qy2.mjs';
|
|
23
|
+
import { n as normalizeWebPanels, w as webPanelPath } from './webPanels-B2_C2-3g.mjs';
|
|
24
|
+
import { r as readSettings } from './persistence-Cr-wutZ4.mjs';
|
|
25
|
+
import { g as getSessionNotificationBody } from './pushNotifications-BdFjDjQe.mjs';
|
|
21
26
|
import { c as checkPreviewPath } from './previewPath-CXN4Vag0.mjs';
|
|
22
27
|
import { createHash } from 'crypto';
|
|
23
28
|
|
|
29
|
+
function createProjectInjector(deps) {
|
|
30
|
+
const timeoutMs = deps.timeoutMs ?? 1500;
|
|
31
|
+
const now = deps.now ?? Date.now;
|
|
32
|
+
const presenceEvery = deps.presenceMinIntervalMs ?? 3e4;
|
|
33
|
+
const state = { projectId: null, prefixSent: false, cursor: 0, injectedVersion: null };
|
|
34
|
+
const titles = /* @__PURE__ */ new Map();
|
|
35
|
+
let lastPresenceAt = 0;
|
|
36
|
+
let lastPresenceVersion = null;
|
|
37
|
+
const label = (id) => titles.get(id) ?? id.slice(0, 8);
|
|
38
|
+
function withTimeout(p) {
|
|
39
|
+
return Promise.race([p, new Promise((_, reject) => setTimeout(() => reject(new Error("project injection timeout")), timeoutMs).unref?.())]);
|
|
40
|
+
}
|
|
41
|
+
function reportPresence(force) {
|
|
42
|
+
const sid = deps.sessionId();
|
|
43
|
+
const meta = deps.metadata?.() ?? null;
|
|
44
|
+
const machineId = typeof meta?.machineId === "string" ? meta.machineId : null;
|
|
45
|
+
if (!sid || !machineId || !state.projectId) return;
|
|
46
|
+
const t = now();
|
|
47
|
+
if (!force && state.injectedVersion === lastPresenceVersion && t - lastPresenceAt < presenceEvery) return;
|
|
48
|
+
lastPresenceAt = t;
|
|
49
|
+
lastPresenceVersion = state.injectedVersion;
|
|
50
|
+
const entry = {
|
|
51
|
+
sessionId: sid,
|
|
52
|
+
agent: deps.agent,
|
|
53
|
+
state: "running",
|
|
54
|
+
injectedInstructionsVersion: state.injectedVersion,
|
|
55
|
+
...typeof meta?.summary?.text === "string" ? { title: String(meta.summary.text).slice(0, 200) } : {},
|
|
56
|
+
...typeof meta?.board?.progress === "string" ? { doing: String(meta.board.progress).slice(0, 200) } : {},
|
|
57
|
+
...typeof meta?.worktree?.branch === "string" ? { branch: String(meta.worktree.branch).slice(0, 200) } : {},
|
|
58
|
+
...typeof meta?.host === "string" ? { machine: String(meta.host).slice(0, 200) } : {},
|
|
59
|
+
...Array.isArray(meta?.capabilities) ? { capabilities: meta.capabilities.filter((c) => typeof c === "string").slice(0, 32) } : {}
|
|
60
|
+
};
|
|
61
|
+
void deps.client.presence(machineId, [entry]).catch((error) => logger.debug(`[projects] presence write skipped: ${String(error)}`));
|
|
62
|
+
}
|
|
63
|
+
function markDelivered(sid, ids) {
|
|
64
|
+
if (ids.length) void deps.client.delivered(sid, ids).catch((error) => logger.debug(`[projects] delivered ack skipped: ${String(error)}`));
|
|
65
|
+
}
|
|
66
|
+
async function firstTurn(sid, message) {
|
|
67
|
+
const ctx = await withTimeout(deps.client.context(sid, {}, timeoutMs));
|
|
68
|
+
for (const s of ctx.sessions) if (s.title) titles.set(s.sessionId, s.title);
|
|
69
|
+
const built = buildFirstTurnPrefix(ctx, { label });
|
|
70
|
+
if (!built || !ctx.project) {
|
|
71
|
+
state.projectId = null;
|
|
72
|
+
return message;
|
|
73
|
+
}
|
|
74
|
+
state.projectId = ctx.project.id;
|
|
75
|
+
state.prefixSent = true;
|
|
76
|
+
state.cursor = ctx.asOf;
|
|
77
|
+
state.injectedVersion = built.instructionsVersion;
|
|
78
|
+
markDelivered(sid, ctx.unread.map((u) => u.id));
|
|
79
|
+
reportPresence(true);
|
|
80
|
+
return prependToMessage(message, built.prefix);
|
|
81
|
+
}
|
|
82
|
+
async function laterTurn(sid, message) {
|
|
83
|
+
const d = await withTimeout(deps.client.digest(sid, state.cursor, timeoutMs));
|
|
84
|
+
if (!d.projectId) {
|
|
85
|
+
state.projectId = null;
|
|
86
|
+
state.prefixSent = false;
|
|
87
|
+
state.injectedVersion = null;
|
|
88
|
+
return message;
|
|
89
|
+
}
|
|
90
|
+
if (d.projectId !== state.projectId) {
|
|
91
|
+
state.prefixSent = false;
|
|
92
|
+
return firstTurn(sid, message);
|
|
93
|
+
}
|
|
94
|
+
state.cursor = d.asOf;
|
|
95
|
+
if (d.instructions) state.injectedVersion = d.instructions.version;
|
|
96
|
+
markDelivered(sid, d.messages.map((m) => m.id));
|
|
97
|
+
reportPresence(!!d.instructions);
|
|
98
|
+
return prependToMessage(message, buildDigestLine(d, { label }));
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
state: () => ({ ...state }),
|
|
102
|
+
/** A fresh agent with no memory of earlier turns (ACP backend restart, new Claude conversation) needs P again. */
|
|
103
|
+
reset() {
|
|
104
|
+
state.prefixSent = false;
|
|
105
|
+
state.cursor = 0;
|
|
106
|
+
},
|
|
107
|
+
async decorate(message) {
|
|
108
|
+
if (typeof message !== "string") return message;
|
|
109
|
+
const sid = deps.sessionId();
|
|
110
|
+
if (!sid || deps.client.isDisabled()) return message;
|
|
111
|
+
try {
|
|
112
|
+
const out = state.prefixSent ? await laterTurn(sid, message) : await firstTurn(sid, message);
|
|
113
|
+
return out;
|
|
114
|
+
} catch (error) {
|
|
115
|
+
if (!(error instanceof ProjectsUnsupportedError)) logger.debug(`[projects] injection skipped: ${String(error)}`);
|
|
116
|
+
return message;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
24
122
|
const TEAMS_ADOPT_CAPABILITY = "teams-adopt-v1";
|
|
25
123
|
const TeamAdoptSchema = z.object({
|
|
26
124
|
requestId: z.string().min(1).max(128),
|
|
@@ -128,6 +226,41 @@ This session is now connected as the team lead. Call team_inspect to read the au
|
|
|
128
226
|
};
|
|
129
227
|
}
|
|
130
228
|
|
|
229
|
+
const REQUEST_HUMAN_TOOL_NAME = "request_human";
|
|
230
|
+
const REQUEST_HUMAN_REASON_MAX = 200;
|
|
231
|
+
const REQUEST_HUMAN_DEDUPE_MS = 6e4;
|
|
232
|
+
const REQUEST_HUMAN_TOOL_DESCRIPTION = "Ask the user to step in when you cannot continue on your own: a captcha, 2FA code, QR scan, OAuth consent page, or a decision only they can make. Sends a push notification and marks the task board as blocked. Give a short reason (no secrets; the server can read it). If this machine declares a web panel showing what you are working in (e.g. a remote desktop or browser dashboard), pass its id as `panel` so the notification opens it. Afterwards, poll for your own completion condition (the page changed, the element disappeared) instead of waiting for a reply.";
|
|
233
|
+
function createRequestHuman(deps) {
|
|
234
|
+
const now = deps.now ?? Date.now;
|
|
235
|
+
let last = null;
|
|
236
|
+
return async (rawReason, panel) => {
|
|
237
|
+
const reason = rawReason.replace(/\s+/g, " ").trim().slice(0, REQUEST_HUMAN_REASON_MAX);
|
|
238
|
+
if (!reason) return { notified: false, error: "reason must be a non-empty string" };
|
|
239
|
+
await deps.reportBlocked(reason);
|
|
240
|
+
const at = now();
|
|
241
|
+
if (last && last.reason === reason && at - last.at < REQUEST_HUMAN_DEDUPE_MS) {
|
|
242
|
+
return { notified: true, deduped: true };
|
|
243
|
+
}
|
|
244
|
+
let url = `/session/${encodeURIComponent(deps.sessionId)}`;
|
|
245
|
+
let unknownPanel;
|
|
246
|
+
if (panel) {
|
|
247
|
+
const machineId = deps.machineId();
|
|
248
|
+
const { panels } = normalizeWebPanels(await deps.readPanels().catch(() => void 0));
|
|
249
|
+
if (machineId && panels.some((p) => p.id === panel)) url = webPanelPath(machineId, panel);
|
|
250
|
+
else unknownPanel = panel;
|
|
251
|
+
}
|
|
252
|
+
const sent = await deps.sendAttention({ sessionId: deps.sessionId, reason, url });
|
|
253
|
+
if (sent.sent) last = { reason, at };
|
|
254
|
+
return { notified: sent.sent, url, ...unknownPanel ? { unknownPanel } : {}, ...sent.error ? { error: sent.error } : {} };
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
function requestHumanResultText(r) {
|
|
258
|
+
if (r.deduped) return "Already asked for this in the last minute; the board still shows it. Keep polling your completion condition.";
|
|
259
|
+
if (!r.notified) return `Could not notify the user: ${r.error ?? "unknown error"}. The task board is marked blocked.`;
|
|
260
|
+
const panelNote = r.unknownPanel ? ` (panel "${r.unknownPanel}" is not declared on this machine, so the notification opens the session instead)` : "";
|
|
261
|
+
return `Notified the user${panelNote}. This does not mean they have seen it. Poll your own completion condition (URL changed, element gone) instead of waiting for a reply.`;
|
|
262
|
+
}
|
|
263
|
+
|
|
131
264
|
function createMcpServer(handlers, options, sessionId, client) {
|
|
132
265
|
const mcp = new McpServer({
|
|
133
266
|
name: "Very Happy Tools",
|
|
@@ -136,6 +269,7 @@ function createMcpServer(handlers, options, sessionId, client) {
|
|
|
136
269
|
registerTeamsTools(mcp, sessionId);
|
|
137
270
|
registerAutomationTools(mcp);
|
|
138
271
|
if (client) registerSessionPeerTools(mcp, createSessionPeerToolExecutor(client));
|
|
272
|
+
if (client) registerProjectTools(mcp, createProjectToolExecutor(() => client.sessionId));
|
|
139
273
|
mcp.registerTool("change_title", {
|
|
140
274
|
description: "Change the title of the current chat session",
|
|
141
275
|
title: "Change Chat Title",
|
|
@@ -222,6 +356,18 @@ function createMcpServer(handlers, options, sessionId, client) {
|
|
|
222
356
|
isError: true
|
|
223
357
|
};
|
|
224
358
|
});
|
|
359
|
+
mcp.registerTool(REQUEST_HUMAN_TOOL_NAME, {
|
|
360
|
+
description: REQUEST_HUMAN_TOOL_DESCRIPTION,
|
|
361
|
+
title: "Ask the user to step in",
|
|
362
|
+
inputSchema: {
|
|
363
|
+
reason: z.string().describe("What you need from the user, one short line (no secrets)"),
|
|
364
|
+
panel: z.string().optional().describe("Id of this machine's web panel that shows what you are working in (from ~/.happy/settings.json webPanels)")
|
|
365
|
+
}
|
|
366
|
+
}, async (args) => {
|
|
367
|
+
const response = await handlers.requestHuman(String(args.reason ?? ""), args.panel);
|
|
368
|
+
logger.debug("[happyMCP] request_human response:", response);
|
|
369
|
+
return { content: [{ type: "text", text: requestHumanResultText(response) }], isError: response.error === "reason must be a non-empty string" };
|
|
370
|
+
});
|
|
225
371
|
registerReportProgressTool(mcp, async (args) => {
|
|
226
372
|
const response = await handlers.reportProgress(String(args.progress ?? ""), normalizeAttention(args.attention), normalizePhase(args.phase));
|
|
227
373
|
logger.debug("[happyMCP] report_progress response:", response);
|
|
@@ -319,10 +465,66 @@ async function startHappyServer(client, options) {
|
|
|
319
465
|
} catch (error) {
|
|
320
466
|
return { delivered: false, truncated: false, totalBytes: 0, error: String(error) };
|
|
321
467
|
}
|
|
322
|
-
}
|
|
468
|
+
},
|
|
469
|
+
requestHuman: createRequestHuman({
|
|
470
|
+
sessionId: client.sessionId,
|
|
471
|
+
machineId: () => client.getMetadata()?.machineId,
|
|
472
|
+
readPanels: async () => (await readSettings()).webPanels,
|
|
473
|
+
// Same board write (and attention-change throttle bypass) as report_progress.
|
|
474
|
+
reportBlocked: (reason) => handlers.reportProgress(reason, "blocked"),
|
|
475
|
+
sendAttention: (input) => options?.push ? options.push.sendAttention({ ...input, sessionTitle: getSessionNotificationBody(client.getMetadata()) }) : Promise.resolve({ sent: false, error: "push is not available in this runner" })
|
|
476
|
+
})
|
|
323
477
|
};
|
|
324
478
|
const contextPath = "/runtime-context/" + randomUUID();
|
|
479
|
+
const steerPath = "/runtime-steer/" + randomUUID();
|
|
325
480
|
const server = createServer(async (req, res) => {
|
|
481
|
+
if (req.url?.startsWith("/runtime-steer/")) {
|
|
482
|
+
const steer = options?.piSteer;
|
|
483
|
+
if (!steer || req.headers.origin) {
|
|
484
|
+
res.writeHead(403).end();
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
if (req.method === "GET" && req.url === steerPath) {
|
|
488
|
+
const gone = new AbortController();
|
|
489
|
+
res.on("close", () => gone.abort());
|
|
490
|
+
const item = await steer.take(25e3, gone.signal);
|
|
491
|
+
if (res.writableEnded || gone.signal.aborted) {
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
if (!item) {
|
|
495
|
+
res.writeHead(204).end();
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify(item));
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
if (req.method === "POST" && (req.url === steerPath + "/hello" || req.url === steerPath + "/ack")) {
|
|
502
|
+
let body = "";
|
|
503
|
+
for await (const chunk of req) {
|
|
504
|
+
body += chunk.toString();
|
|
505
|
+
if (Buffer.byteLength(body) > 1024) {
|
|
506
|
+
res.writeHead(413).end();
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
if (req.url.endsWith("/hello")) {
|
|
511
|
+
steer.hello();
|
|
512
|
+
res.writeHead(204).end();
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
try {
|
|
516
|
+
const ack = JSON.parse(body);
|
|
517
|
+
if (typeof ack.id !== "number") throw new Error("id");
|
|
518
|
+
steer.ack(ack.id, ack.delivered === true);
|
|
519
|
+
res.writeHead(204).end();
|
|
520
|
+
} catch {
|
|
521
|
+
res.writeHead(400).end();
|
|
522
|
+
}
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
res.writeHead(403).end();
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
326
528
|
if (req.url?.startsWith("/runtime-context/")) {
|
|
327
529
|
if (!options?.onContextUsage || req.url !== contextPath || req.method !== "POST" || req.headers.origin) {
|
|
328
530
|
res.writeHead(403).end();
|
|
@@ -379,14 +581,17 @@ async function startHappyServer(client, options) {
|
|
|
379
581
|
return {
|
|
380
582
|
url: baseUrl.toString(),
|
|
381
583
|
contextUsageUrl: options?.onContextUsage ? new URL(contextPath, baseUrl).toString() : void 0,
|
|
584
|
+
steerUrl: options?.piSteer ? new URL(steerPath, baseUrl).toString() : void 0,
|
|
382
585
|
toolNames: [
|
|
383
586
|
"change_title",
|
|
384
587
|
CLIPBOARD_TOOL_NAME,
|
|
385
588
|
PREVIEW_TOOL_NAME,
|
|
386
589
|
REPORT_PROGRESS_TOOL_NAME,
|
|
590
|
+
REQUEST_HUMAN_TOOL_NAME,
|
|
387
591
|
...TEAM_TOOL_NAMES,
|
|
388
592
|
...AUTOMATION_TOOL_NAMES,
|
|
389
593
|
...SESSION_PEER_TOOL_NAMES,
|
|
594
|
+
...PROJECT_TOOL_NAMES,
|
|
390
595
|
...options?.assistant && !process.env.VH_TEAM_SCOPE_FILE ? ASSISTANT_TOOL_NAMES : []
|
|
391
596
|
],
|
|
392
597
|
stop: () => {
|
|
@@ -483,4 +688,4 @@ function hashObject(obj, options, encoding = "hex") {
|
|
|
483
688
|
return createHash("sha256").update(jsonString).digest(encoding);
|
|
484
689
|
}
|
|
485
690
|
|
|
486
|
-
export { hashObject as h, startHappyServer as s };
|
|
691
|
+
export { createProjectInjector as c, hashObject as h, startHappyServer as s };
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chalk = require('chalk');
|
|
4
|
-
var configuration = require('./configuration-
|
|
5
|
-
var persistence = require('./persistence-
|
|
6
|
-
var controlClient = require('./controlClient-
|
|
4
|
+
var configuration = require('./configuration-CMHZnp6G.cjs');
|
|
5
|
+
var persistence = require('./persistence-BegE7NPa.cjs');
|
|
6
|
+
var controlClient = require('./controlClient-C-5qCt8W.cjs');
|
|
7
7
|
var doctor$1 = require('./doctor-u46qYYKX.cjs');
|
|
8
8
|
var node_fs = require('node:fs');
|
|
9
9
|
var path = require('node:path');
|
|
10
10
|
var projectPath = require('./projectPath-ChLhdOyt.cjs');
|
|
11
|
-
var _package = require('./package-
|
|
11
|
+
var _package = require('./package-SgqTYsjn.cjs');
|
|
12
12
|
var doctorReadiness = require('./doctorReadiness-BCZGcN0a.cjs');
|
|
13
|
-
var authRelay = require('./authRelay-
|
|
13
|
+
var authRelay = require('./authRelay-Dy1qU9td.cjs');
|
|
14
14
|
var cliUpdate = require('./cliUpdate-DsKXPFYp.cjs');
|
|
15
15
|
var node_child_process = require('node:child_process');
|
|
16
|
-
var piRunnerArgs = require('./piRunnerArgs-
|
|
16
|
+
var piRunnerArgs = require('./piRunnerArgs-Cs-378Vz.cjs');
|
|
17
17
|
|
|
18
18
|
function shareSafeProcessLine(process2) {
|
|
19
19
|
return `PID ${process2.pid}: command arguments hidden for privacy`;
|
|
@@ -313,8 +313,8 @@ ${typeLabels[type] || type}:`));
|
|
|
313
313
|
}
|
|
314
314
|
console.log(chalk.gray(" An external claude command is only needed for native terminal/mirror use."));
|
|
315
315
|
try {
|
|
316
|
-
const { resolveAgentHomesForCli } = await Promise.resolve().then(function () { return require('./agentHome-
|
|
317
|
-
const { describeAgentHome } = await Promise.resolve().then(function () { return require('./index-
|
|
316
|
+
const { resolveAgentHomesForCli } = await Promise.resolve().then(function () { return require('./agentHome-BWcz8mz0.cjs'); });
|
|
317
|
+
const { describeAgentHome } = await Promise.resolve().then(function () { return require('./index-B0UjHlAe.cjs'); });
|
|
318
318
|
const homes = await resolveAgentHomesForCli();
|
|
319
319
|
console.log(chalk.green(`\u2713 Claude config dir: ${describeAgentHome(homes.claudeConfigDir)}`));
|
|
320
320
|
console.log(chalk.green(`\u2713 Codex home: ${describeAgentHome(homes.codexHome)}`));
|