very-happy-cli 0.2.158 → 0.2.160
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{AcpBackend-DIDRig5G.cjs → AcpBackend-Bm2rdke8.cjs} +78 -76
- package/dist/{AcpBackend-vDVLHuYJ.mjs → AcpBackend-mzv8Dhba.mjs} +4 -2
- package/dist/{AcpSessionManager-C44U99CC.cjs → AcpSessionManager-BAY1Pggx.cjs} +9 -9
- package/dist/{AcpSessionManager-CmRjfhn3.mjs → AcpSessionManager-CoMWFVw3.mjs} +1 -1
- package/dist/BasePermissionHandler-CFHAxumV.cjs +157 -0
- package/dist/BasePermissionHandler-m3WVholL.mjs +155 -0
- package/dist/BaseReasoningProcessor-BFa9_rZA.cjs +200 -0
- package/dist/BaseReasoningProcessor-CYrKBXGm.mjs +198 -0
- package/dist/RemoteModeDisplay-D-HewyXg.mjs +150 -0
- package/dist/RemoteModeDisplay-NC1gPHtj.cjs +153 -0
- package/dist/agentAttachments-Dbw8iMCZ.cjs +20 -0
- package/dist/agentAttachments-M_B5qEF2.mjs +18 -0
- package/dist/agentGuidance-B5NATuFa.cjs +28 -0
- package/dist/agentGuidance-CQuNlNx8.mjs +20 -0
- package/dist/{agentHome-Dw8Jx_CJ.cjs → agentHome-CboCeKWq.cjs} +14 -28
- package/dist/{agentHome-CyLmGH5L.mjs → agentHome-Dj1C43aJ.mjs} +8 -22
- package/dist/api-CLMUr-SX.mjs +3339 -0
- package/dist/api-CgundNNX.cjs +3346 -0
- package/dist/{types-DIBF4U0Y.mjs → apiMachine-B9dLW_p5.mjs} +9116 -16015
- package/dist/{types-DnrPeN80.cjs → apiMachine-Bn8482VM.cjs} +9104 -16057
- package/dist/assistantTools-BTqPnlFl.cjs +380 -0
- package/dist/assistantTools-D6tuc6o4.mjs +376 -0
- package/dist/attachmentContent-DpiTJZb4.cjs +88 -0
- package/dist/attachmentContent-_kxRznNf.mjs +82 -0
- package/dist/attachmentLimits-CzVrqgLR.cjs +354 -0
- package/dist/attachmentLimits-yba1uHFO.mjs +348 -0
- package/dist/auth-BDOVh5h5.cjs +220 -0
- package/dist/auth-Cwutmdsa.mjs +225 -0
- package/dist/auth-PYHZQNPp.mjs +218 -0
- package/dist/auth-ba4WMYrN.cjs +227 -0
- package/dist/authRelay-BdYkC1Po.cjs +156 -0
- package/dist/authRelay-DSAvg1uv.mjs +143 -0
- package/dist/{auto-DZbNcTXx.cjs → auto-BOX_fgmR.cjs} +70 -79
- package/dist/{auto-BlMZPwOk.mjs → auto-BXu14yP_.mjs} +27 -36
- package/dist/backgroundTaskActivity-8PdPxrvy.mjs +149 -0
- package/dist/backgroundTaskActivity-CBvUdj39.cjs +157 -0
- package/dist/bootstrap-B5G1TijC.cjs +116 -0
- package/dist/bootstrap-hxXPCFMx.mjs +112 -0
- package/dist/browser-Y6Bl8L_O.cjs +22 -0
- package/dist/browser-jh2P0UVZ.mjs +20 -0
- package/dist/claudeCliPath-BqkaH2oR.mjs +8 -0
- package/dist/claudeCliPath-U4HHmV4r.cjs +10 -0
- package/dist/claudeLocal-BaY4fZKi.mjs +339 -0
- package/dist/claudeLocal-CRGG4Pea.cjs +343 -0
- package/dist/claudeLocalLauncher-D4T7MTqd.mjs +152 -0
- package/dist/claudeLocalLauncher-DyEbVzUN.cjs +154 -0
- package/dist/cliUpdate-DsKXPFYp.cjs +120 -0
- package/dist/cliUpdate-Y34VGe9Y.mjs +112 -0
- package/dist/client-3Ac-O4pw.cjs +104 -0
- package/dist/client-BPNbmtvO.cjs +119 -0
- package/dist/client-CeGKqqcJ.mjs +100 -0
- package/dist/client-ClR0K8zX.mjs +112 -0
- package/dist/codex/happyMcpStdioBridge.cjs +33 -14
- package/dist/codex/happyMcpStdioBridge.mjs +26 -7
- package/dist/codexAppServerClient-I3teiV-N.mjs +1088 -0
- package/dist/codexAppServerClient-q2FjnRcK.cjs +1090 -0
- package/dist/codexCommand-4zcccIoq.cjs +2088 -0
- package/dist/codexCommand-Cc9gcbdX.mjs +2086 -0
- package/dist/codexThreadFork-BH9IZPqD.cjs +350 -0
- package/dist/codexThreadFork-slzAseLx.mjs +338 -0
- package/dist/{config-BtPArqRH.mjs → config-CTx_jb-C.mjs} +7 -40
- package/dist/{config-DG84bjwF.cjs → config-Ci9Kpgwa.cjs} +26 -59
- package/dist/configuration-BSYpcPwE.cjs +181 -0
- package/dist/configuration-RfeNjFmd.mjs +170 -0
- package/dist/connect-BpOdzNbE.mjs +682 -0
- package/dist/connect-C2CiOUFs.cjs +684 -0
- package/dist/constants-BC4St0xd.mjs +11 -0
- package/dist/constants-VJ0N6WuG.cjs +17 -0
- package/dist/contentLogMetadata-BlWI0egu.mjs +51 -0
- package/dist/contentLogMetadata-ZSFk_NjQ.cjs +54 -0
- package/dist/context-DsDr6E2t.cjs +69 -0
- package/dist/context-H0Bcb9S_.mjs +65 -0
- package/dist/controlClient-BGbDcgWS.mjs +260 -0
- package/dist/controlClient-Bcwv3D21.cjs +279 -0
- package/dist/createSessionMetadata-BJxEnM-o.cjs +58 -0
- package/dist/createSessionMetadata-CVVkGjxV.mjs +54 -0
- package/dist/defaultPermissionMode-BnxJPVHT.mjs +4 -0
- package/dist/defaultPermissionMode-CxmTXUQR.cjs +7 -0
- package/dist/detectCLI-CSGMlV51.mjs +58 -0
- package/dist/detectCLI-DR9ZaN6B.cjs +61 -0
- package/dist/deterministicJson-C5CYTVpm.cjs +507 -0
- package/dist/deterministicJson-CzkFJWw1.mjs +502 -0
- package/dist/doctor-BPkYWSuq.mjs +75 -0
- package/dist/doctor-D2YJ-Yn2.cjs +395 -0
- package/dist/doctor-DOvByjbk.mjs +391 -0
- package/dist/doctor-u46qYYKX.cjs +79 -0
- package/dist/doctorReadiness-BCZGcN0a.cjs +151 -0
- package/dist/doctorReadiness-C208SMN9.mjs +142 -0
- package/dist/editPaths-BVfS_FFL.mjs +68 -0
- package/dist/editPaths-Bqp4OFPw.cjs +73 -0
- package/dist/ensureDaemonRunning-BCwNrMyv.cjs +64 -0
- package/dist/ensureDaemonRunning-Dqa2pOjY.mjs +61 -0
- package/dist/handleResumeCommand-BvXYf5El.mjs +240 -0
- package/dist/handleResumeCommand-C2cKchpX.cjs +245 -0
- package/dist/ids-B6ZC0HGt.cjs +13 -0
- package/dist/ids-DU6sLx4C.mjs +10 -0
- package/dist/index-B6UGRQ7h.mjs +102 -0
- package/dist/{index-DPCsWlWK.cjs → index-B6pAdvJx.cjs} +131 -91
- package/dist/index-Bu5Zi_a9.cjs +182 -0
- package/dist/index-D3kI0hDR.cjs +107 -0
- package/dist/index-DA7yINuk.cjs +994 -0
- package/dist/index-DDeHXrIX.cjs +71 -0
- package/dist/index-DKLU_fD0.mjs +158 -0
- package/dist/{index-ZChGsuB7.mjs → index-DMZqWwsP.mjs} +79 -39
- package/dist/index-DVkMGPyS.mjs +68 -0
- package/dist/index-qdS1friN.mjs +949 -0
- package/dist/index.cjs +5 -46
- package/dist/index.mjs +5 -46
- package/dist/{install-DarS_Wco.mjs → install-BO_W7VhL.mjs} +37 -37
- package/dist/install-BgoC2e_2.cjs +88 -0
- package/dist/install-CFY3tYtJ.mjs +86 -0
- package/dist/{install-wKQGgXvN.cjs → install-Cs5qAPrB.cjs} +38 -38
- package/dist/{installPiTools-DuZ6jZvX.cjs → installPiTools-BKnXjrVu.cjs} +2 -3
- package/dist/{installPiTools-Cj7yU9Fc.mjs → installPiTools-B_CdM5_2.mjs} +1 -2
- package/dist/{installTerminalHooks-DcQfee_O.cjs → installTerminalHooks-BQZbvxsZ.cjs} +5 -40
- package/dist/{installTerminalHooks-CpNbRFPz.mjs → installTerminalHooks-By7gBMEF.mjs} +3 -38
- package/dist/lib.cjs +28 -19
- package/dist/lib.d.cts +126 -2
- package/dist/lib.d.mts +126 -2
- package/dist/lib.mjs +23 -14
- package/dist/lidState-BeDfxxEX.cjs +305 -0
- package/dist/lidState-CeEt442o.mjs +297 -0
- package/dist/limits-C-a7gr04.cjs +43 -0
- package/dist/limits-DIo7rEBR.mjs +36 -0
- package/dist/localHappyAgentAuth-C-HQyiv6.mjs +82 -0
- package/dist/localHappyAgentAuth-D6rFhaoc.cjs +86 -0
- package/dist/logger-6HYUEXNk.mjs +271 -0
- package/dist/logger-CS0mw3fa.cjs +275 -0
- package/dist/loginShellEnv-BkuYtExZ.cjs +182 -0
- package/dist/loginShellEnv-Dw8M7tkI.mjs +167 -0
- package/dist/machineMetadata-DyDbODYd.cjs +41 -0
- package/dist/machineMetadata-oOzBfDfs.mjs +38 -0
- package/dist/main-BkxJP6JQ.cjs +941 -0
- package/dist/main-BwNIAI1A.mjs +939 -0
- package/dist/manager-BQ4flvQZ.mjs +101 -0
- package/dist/manager-Cly8xVIR.cjs +105 -0
- package/dist/{mcp-BN6bKIGb.mjs → mcp-B1A4I3TK.mjs} +27 -33
- package/dist/{mcp-DGdeUUDJ.cjs → mcp-Hszd7qpS.cjs} +42 -48
- package/dist/messageBuffer-BWlGgR3A.mjs +71 -0
- package/dist/messageBuffer-fJMH6uY8.cjs +73 -0
- package/dist/mirrorProtocol-BNLtoWjO.mjs +170 -0
- package/dist/mirrorProtocol-BUtmg1ws.cjs +186 -0
- package/dist/oneShotPrompts-CL0dip9C.cjs +16 -0
- package/dist/oneShotPrompts-DT4p6RNd.mjs +12 -0
- package/dist/package-BhaKlnxz.mjs +171 -0
- package/dist/package-BwMrPwqH.cjs +173 -0
- package/dist/path-B7zW-WwE.cjs +18 -0
- package/dist/path-D2wdaNSk.mjs +15 -0
- package/dist/peerTools-BTqw97Gb.mjs +272 -0
- package/dist/peerTools-BvKtHXj8.cjs +283 -0
- package/dist/permissionMode-Cr5JCbB7.mjs +80 -0
- package/dist/permissionMode-CrV-XuMs.cjs +87 -0
- package/dist/persistence-HGW_ZVs9.mjs +372 -0
- package/dist/persistence-yKTH3-5X.cjs +414 -0
- package/dist/piExtension.mjs +2 -1
- package/dist/piRunnerArgs-BNloJCCg.cjs +66 -0
- package/dist/piRunnerArgs-BuX1UFWy.mjs +59 -0
- package/dist/{piRuntime-bkw2NAZU.mjs → piRuntime-CSGkwCKQ.mjs} +2 -2
- package/dist/{piRuntime-3qtbKujX.cjs → piRuntime-C_H7MJCM.cjs} +4 -4
- package/dist/{piTerminal-DilKwM7B.mjs → piTerminal-C8a1OrNQ.mjs} +32 -35
- package/dist/{piTerminal-BYxp3LMr.cjs → piTerminal-DNCZ6yTM.cjs} +32 -35
- package/dist/previewPath-B0rBdhy1.cjs +83 -0
- package/dist/previewPath-CXN4Vag0.mjs +81 -0
- package/dist/projectPath-BTBIMB57.mjs +10 -0
- package/dist/projectPath-ChLhdOyt.cjs +13 -0
- package/dist/registerCommonHandlers-Ccvsz7Ou.mjs +536 -0
- package/dist/registerCommonHandlers-DskirN-_.cjs +538 -0
- package/dist/registerKillSessionHandler-DZeLXWcB.cjs +361 -0
- package/dist/registerKillSessionHandler-GYvHdipX.mjs +358 -0
- package/dist/remoteSessionClient-B0LraSB9.cjs +634 -0
- package/dist/remoteSessionClient-CYnXRynE.mjs +612 -0
- package/dist/resources-BdFBQi8r.mjs +117 -0
- package/dist/resources-JDPugcDq.cjs +120 -0
- package/dist/run-CJzxoHVh.cjs +5762 -0
- package/dist/run-D3ifupU3.mjs +5739 -0
- package/dist/runClaude-Ba01qT-u.mjs +848 -0
- package/dist/runClaude-Da3RirzE.cjs +850 -0
- package/dist/runClaudeDeps-DOt79DjU.mjs +3624 -0
- package/dist/runClaudeDeps-DOzEBMls.cjs +3649 -0
- package/dist/{runGemini-Cjii069p.mjs → runGemini-BGeTz57m.mjs} +58 -31
- package/dist/{runGemini-28O2sqyI.cjs → runGemini-DSr9LIxL.cjs} +202 -175
- package/dist/{runOpenClaw-CiMZad-H.cjs → runOpenClaw-B1mTxN35.cjs} +64 -65
- package/dist/{runOpenClaw-jaLr7KF1.mjs → runOpenClaw-CogSedIc.mjs} +31 -32
- package/dist/sandbox-CG7IyDTU.cjs +187 -0
- package/dist/sandbox-DTe6d54R.mjs +180 -0
- package/dist/selfCheck-C9mVrQwf.mjs +84 -0
- package/dist/selfCheck-Dc-mNSLb.cjs +87 -0
- package/dist/{send-D5ejHPXG.cjs → send-B7J_eaG3.cjs} +16 -9
- package/dist/{send-C9mOtChi.mjs → send-CBXJKc6O.mjs} +12 -5
- package/dist/server-CZTP_iOn.cjs +407 -0
- package/dist/server-DcVBv04l.mjs +404 -0
- package/dist/sessionLock-Bys1PNSo.cjs +205 -0
- package/dist/sessionLock-D-EG2CfG.mjs +197 -0
- package/dist/sessionModeFile-DMl3dw3r.mjs +32 -0
- package/dist/sessionModeFile-RSm0NQkH.cjs +36 -0
- package/dist/sessionOps-Dn8z85h_.cjs +783 -0
- package/dist/sessionOps-SuHW8Dfe.mjs +760 -0
- package/dist/sessionScanner-BOrGjMXL.cjs +209 -0
- package/dist/sessionScanner-CX3onqXh.mjs +206 -0
- package/dist/{sessions-W6771g3X.mjs → sessions-BEG_HTSi.mjs} +17 -8
- package/dist/{sessions-BNMPQoLE.cjs → sessions-D74aJbhL.cjs} +37 -28
- package/dist/setupOfflineReconnection-ByElY60m.cjs +74 -0
- package/dist/setupOfflineReconnection-DpvWTt69.mjs +72 -0
- package/dist/smallFastModel-BLNgMrwR.mjs +18 -0
- package/dist/smallFastModel-D_uxGMo3.cjs +21 -0
- package/dist/{spawn-D0QVhzRb.mjs → spawn-B7yro0b2.mjs} +26 -38
- package/dist/{spawn-Ddtom1cb.cjs → spawn-DgR0RKRs.cjs} +52 -64
- package/dist/spawnAgents-BGQiEF-w.cjs +52 -0
- package/dist/spawnAgents-DZzZ9jMI.mjs +45 -0
- package/dist/spawnHappyCLI-B2H5s4B_.mjs +64 -0
- package/dist/spawnHappyCLI-DBhwZT7O.cjs +66 -0
- package/dist/specialCommands-BSqhYg5X.mjs +52 -0
- package/dist/specialCommands-DSsTeRej.cjs +54 -0
- package/dist/startFileWatcher-B4VsLgjD.cjs +71 -0
- package/dist/startFileWatcher-DErVWZE4.mjs +69 -0
- package/dist/startupPlan-BLMbfQIH.cjs +12 -0
- package/dist/startupPlan-DFMyNgAs.mjs +10 -0
- package/dist/streamRelay-BiKw59Cc.cjs +233 -0
- package/dist/streamRelay-FPVbHpbM.mjs +231 -0
- package/dist/sync-C8gyQFMc.mjs +69 -0
- package/dist/sync-DccIKZ5_.cjs +71 -0
- package/dist/systemPrompt-BwTPWfMu.cjs +97 -0
- package/dist/systemPrompt-DX521JJz.mjs +94 -0
- package/dist/{teams-CqSwtw2O.mjs → teams-C32F1hqd.mjs} +9 -40
- package/dist/{teams-BZ1tayg_.cjs → teams-Dl8g8kTI.cjs} +14 -45
- package/dist/template-BaHAmH2K.cjs +129 -0
- package/dist/template-CiOPa2rd.mjs +121 -0
- package/dist/{terminalTitleSuggest-DKgX3osW.mjs → terminalTitleSuggest-CeKsX_V6.mjs} +1 -9
- package/dist/{terminalTitleSuggest-Dji8I0Jy.cjs → terminalTitleSuggest-DhvRFX3H.cjs} +0 -10
- package/dist/terminals-B_bfC9c2.cjs +250 -0
- package/dist/terminals-Dlg0x3nY.mjs +235 -0
- package/dist/time-D0XyHOid.mjs +38 -0
- package/dist/time-DCuTyook.cjs +42 -0
- package/dist/titleGenerator-CQ8CoGhg.mjs +166 -0
- package/dist/titleGenerator-ChzMJsyg.cjs +172 -0
- package/dist/tmuxSocket-B8Yx20sT.mjs +19 -0
- package/dist/tmuxSocket-D-Xt6Vn-.cjs +24 -0
- package/dist/{todo-BYMg0fR0.cjs → todo-BvUOTa8G.cjs} +15 -12
- package/dist/{todo-BbusB1zM.mjs → todo-CZ6cFrrn.mjs} +11 -8
- package/dist/tools-BZtHF_qQ.mjs +177 -0
- package/dist/tools-Be3AoAwu.cjs +63 -0
- package/dist/tools-DQj0AeLk.cjs +180 -0
- package/dist/tools-DkluDcG4.mjs +60 -0
- package/dist/trimIdent-4gvk9Wk6.cjs +22 -0
- package/dist/trimIdent-BAjmv_TG.mjs +20 -0
- package/dist/types-CRS-srZK.cjs +66 -0
- package/dist/types-CkqAACXx.mjs +64 -0
- package/dist/uninstall-BkLzaJ6I.mjs +47 -0
- package/dist/uninstall-x-TUtf5H.cjs +49 -0
- package/package.json +7 -7
- package/dist/agentGuidance-CrR9l62U.mjs +0 -2145
- package/dist/agentGuidance-DwOWbX55.cjs +0 -2217
- package/dist/index-BG932eCh.cjs +0 -19655
- package/dist/index-CVCt3kSt.mjs +0 -19591
- package/dist/index-D5ScEErM.cjs +0 -58
- package/dist/index-DgO0FHOx.mjs +0 -52
- package/dist/limits-D2uN090G.mjs +0 -2528
- package/dist/limits-kqFqhfsh.cjs +0 -2652
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var logger = require('./logger-CS0mw3fa.cjs');
|
|
4
|
+
require('axios');
|
|
5
|
+
require('node:events');
|
|
6
|
+
require('socket.io-client');
|
|
7
|
+
require('./attachmentLimits-CzVrqgLR.cjs');
|
|
8
|
+
require('node:crypto');
|
|
9
|
+
require('tweetnacl');
|
|
10
|
+
require('./configuration-BSYpcPwE.cjs');
|
|
11
|
+
require('./index-DA7yINuk.cjs');
|
|
12
|
+
require('./registerCommonHandlers-DskirN-_.cjs');
|
|
13
|
+
require('os');
|
|
14
|
+
require('child_process');
|
|
15
|
+
require('@paralleldrive/cuid2');
|
|
16
|
+
require('./persistence-yKTH3-5X.cjs');
|
|
17
|
+
require('chalk');
|
|
18
|
+
require('./types-CRS-srZK.cjs');
|
|
19
|
+
|
|
20
|
+
class MessageQueue2 {
|
|
21
|
+
queue = [];
|
|
22
|
+
// Made public for testing
|
|
23
|
+
waiter = null;
|
|
24
|
+
closed = false;
|
|
25
|
+
onMessageHandler = null;
|
|
26
|
+
/**
|
|
27
|
+
* B-332: fired for every item the queue itself destroys before it was ever
|
|
28
|
+
* handed to the runner. The runner wires this to a queue-cancel tombstone
|
|
29
|
+
* so the web stops painting a silently-lost message as "queued".
|
|
30
|
+
*/
|
|
31
|
+
onDiscardHandler = null;
|
|
32
|
+
/**
|
|
33
|
+
* B-509: fired when a consumer starts waiting on an EMPTY queue — the
|
|
34
|
+
* runner has finished its turn and has nothing to run. The server-side
|
|
35
|
+
* prompt queue drain uses it as its "idle" edge (utils/promptQueueDrain.ts).
|
|
36
|
+
*/
|
|
37
|
+
onWaitHandler = null;
|
|
38
|
+
modeHasher;
|
|
39
|
+
constructor(modeHasher, onMessageHandler = null, onDiscardHandler = null) {
|
|
40
|
+
this.modeHasher = modeHasher;
|
|
41
|
+
this.onMessageHandler = onMessageHandler;
|
|
42
|
+
this.onDiscardHandler = onDiscardHandler;
|
|
43
|
+
logger.logger.debug(`[MessageQueue2] Initialized`);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Set a handler that will be called when a message arrives
|
|
47
|
+
*/
|
|
48
|
+
setOnMessage(handler) {
|
|
49
|
+
this.onMessageHandler = handler;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Set a handler that will be called when messages are discarded without ever
|
|
53
|
+
* being processed (B-332).
|
|
54
|
+
*/
|
|
55
|
+
setOnDiscard(handler) {
|
|
56
|
+
this.onDiscardHandler = handler;
|
|
57
|
+
}
|
|
58
|
+
/** B-509: observe the consumer blocking on an empty queue. */
|
|
59
|
+
setOnWait(handler) {
|
|
60
|
+
this.onWaitHandler = handler;
|
|
61
|
+
}
|
|
62
|
+
/** B-509: true while a consumer is blocked waiting for the next message. */
|
|
63
|
+
isWaiting() {
|
|
64
|
+
return this.waiter !== null;
|
|
65
|
+
}
|
|
66
|
+
/** Report the current items as destroyed for `reason` (caller clears next). */
|
|
67
|
+
notifyDiscard(reason) {
|
|
68
|
+
if (this.queue.length === 0) return;
|
|
69
|
+
const entries = this.queue.map((item) => ({ sourceId: item.sourceId, reason }));
|
|
70
|
+
this.onDiscardHandler?.(entries);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Push a message to the queue with a mode and an optional list of
|
|
74
|
+
* attachments that travel with this message.
|
|
75
|
+
*/
|
|
76
|
+
push(message, mode, attachments, sourceId) {
|
|
77
|
+
if (this.closed) {
|
|
78
|
+
throw new Error("Cannot push to closed queue");
|
|
79
|
+
}
|
|
80
|
+
const modeHash = this.modeHasher(mode);
|
|
81
|
+
logger.logger.debug(`[MessageQueue2] push() called with mode hash: ${modeHash}`);
|
|
82
|
+
this.queue.push({
|
|
83
|
+
message,
|
|
84
|
+
mode,
|
|
85
|
+
modeHash,
|
|
86
|
+
isolate: false,
|
|
87
|
+
attachments,
|
|
88
|
+
sourceId
|
|
89
|
+
});
|
|
90
|
+
if (this.onMessageHandler) {
|
|
91
|
+
this.onMessageHandler(message, mode);
|
|
92
|
+
}
|
|
93
|
+
if (this.waiter) {
|
|
94
|
+
logger.logger.debug(`[MessageQueue2] Notifying waiter`);
|
|
95
|
+
const waiter = this.waiter;
|
|
96
|
+
this.waiter = null;
|
|
97
|
+
waiter(true);
|
|
98
|
+
}
|
|
99
|
+
logger.logger.debug(`[MessageQueue2] push() completed. Queue size: ${this.queue.length}`);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Push a message immediately without batching delay.
|
|
103
|
+
* Does not clear the queue or enforce isolation.
|
|
104
|
+
*/
|
|
105
|
+
pushImmediate(message, mode) {
|
|
106
|
+
if (this.closed) {
|
|
107
|
+
throw new Error("Cannot push to closed queue");
|
|
108
|
+
}
|
|
109
|
+
const modeHash = this.modeHasher(mode);
|
|
110
|
+
logger.logger.debug(`[MessageQueue2] pushImmediate() called with mode hash: ${modeHash}`);
|
|
111
|
+
this.queue.push({
|
|
112
|
+
message,
|
|
113
|
+
mode,
|
|
114
|
+
modeHash,
|
|
115
|
+
isolate: false
|
|
116
|
+
});
|
|
117
|
+
if (this.onMessageHandler) {
|
|
118
|
+
this.onMessageHandler(message, mode);
|
|
119
|
+
}
|
|
120
|
+
if (this.waiter) {
|
|
121
|
+
logger.logger.debug(`[MessageQueue2] Notifying waiter for immediate message`);
|
|
122
|
+
const waiter = this.waiter;
|
|
123
|
+
this.waiter = null;
|
|
124
|
+
waiter(true);
|
|
125
|
+
}
|
|
126
|
+
logger.logger.debug(`[MessageQueue2] pushImmediate() completed. Queue size: ${this.queue.length}`);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Push a message that must be processed in complete isolation.
|
|
130
|
+
* Clears any pending messages and ensures this message is never batched with others.
|
|
131
|
+
* Used for special commands that require dedicated processing.
|
|
132
|
+
*/
|
|
133
|
+
pushIsolateAndClear(message, mode, attachments, sourceId) {
|
|
134
|
+
if (this.closed) {
|
|
135
|
+
throw new Error("Cannot push to closed queue");
|
|
136
|
+
}
|
|
137
|
+
const modeHash = this.modeHasher(mode);
|
|
138
|
+
logger.logger.debug(`[MessageQueue2] pushIsolateAndClear() called with mode hash: ${modeHash} - clearing ${this.queue.length} pending messages`);
|
|
139
|
+
this.notifyDiscard("cleared");
|
|
140
|
+
this.queue = [];
|
|
141
|
+
this.queue.push({
|
|
142
|
+
message,
|
|
143
|
+
mode,
|
|
144
|
+
modeHash,
|
|
145
|
+
isolate: true,
|
|
146
|
+
attachments,
|
|
147
|
+
sourceId
|
|
148
|
+
});
|
|
149
|
+
if (this.onMessageHandler) {
|
|
150
|
+
this.onMessageHandler(message, mode);
|
|
151
|
+
}
|
|
152
|
+
if (this.waiter) {
|
|
153
|
+
logger.logger.debug(`[MessageQueue2] Notifying waiter for isolated message`);
|
|
154
|
+
const waiter = this.waiter;
|
|
155
|
+
this.waiter = null;
|
|
156
|
+
waiter(true);
|
|
157
|
+
}
|
|
158
|
+
logger.logger.debug(`[MessageQueue2] pushIsolateAndClear() completed. Queue size: ${this.queue.length}`);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Push a message to the beginning of the queue with a mode.
|
|
162
|
+
*/
|
|
163
|
+
unshift(message, mode) {
|
|
164
|
+
if (this.closed) {
|
|
165
|
+
throw new Error("Cannot unshift to closed queue");
|
|
166
|
+
}
|
|
167
|
+
const modeHash = this.modeHasher(mode);
|
|
168
|
+
logger.logger.debug(`[MessageQueue2] unshift() called with mode hash: ${modeHash}`);
|
|
169
|
+
this.queue.unshift({
|
|
170
|
+
message,
|
|
171
|
+
mode,
|
|
172
|
+
modeHash,
|
|
173
|
+
isolate: false
|
|
174
|
+
});
|
|
175
|
+
if (this.onMessageHandler) {
|
|
176
|
+
this.onMessageHandler(message, mode);
|
|
177
|
+
}
|
|
178
|
+
if (this.waiter) {
|
|
179
|
+
logger.logger.debug(`[MessageQueue2] Notifying waiter`);
|
|
180
|
+
const waiter = this.waiter;
|
|
181
|
+
this.waiter = null;
|
|
182
|
+
waiter(true);
|
|
183
|
+
}
|
|
184
|
+
logger.logger.debug(`[MessageQueue2] unshift() completed. Queue size: ${this.queue.length}`);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Reset the queue - clears all messages and resets to empty state
|
|
188
|
+
*/
|
|
189
|
+
reset() {
|
|
190
|
+
logger.logger.debug(`[MessageQueue2] reset() called. Clearing ${this.queue.length} messages`);
|
|
191
|
+
this.notifyDiscard("aborted");
|
|
192
|
+
this.queue = [];
|
|
193
|
+
this.closed = false;
|
|
194
|
+
this.waiter = null;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Close the queue - no more messages can be pushed
|
|
198
|
+
*/
|
|
199
|
+
close() {
|
|
200
|
+
logger.logger.debug(`[MessageQueue2] close() called`);
|
|
201
|
+
this.closed = true;
|
|
202
|
+
if (this.waiter) {
|
|
203
|
+
const waiter = this.waiter;
|
|
204
|
+
this.waiter = null;
|
|
205
|
+
waiter(false);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Check if the queue is closed
|
|
210
|
+
*/
|
|
211
|
+
isClosed() {
|
|
212
|
+
return this.closed;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Get the current queue size
|
|
216
|
+
*/
|
|
217
|
+
size() {
|
|
218
|
+
return this.queue.length;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Remove one message that has not yet been collected by the agent loop.
|
|
222
|
+
* Source id is authoritative. Exact-text fallback only covers items that
|
|
223
|
+
* entered this live process before transport ids were introduced.
|
|
224
|
+
*/
|
|
225
|
+
cancelPending(sourceId, exactText) {
|
|
226
|
+
let index = sourceId ? this.queue.findIndex((item) => item.sourceId === sourceId) : -1;
|
|
227
|
+
if (index < 0 && exactText !== void 0) {
|
|
228
|
+
index = this.queue.findIndex((item) => item.sourceId === void 0 && item.message === exactText);
|
|
229
|
+
}
|
|
230
|
+
if (index < 0) return false;
|
|
231
|
+
this.queue.splice(index, 1);
|
|
232
|
+
logger.logger.debug(`[MessageQueue2] Cancelled pending item. Queue size: ${this.queue.length}`);
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Wait for messages and return all messages with the same mode as a single string
|
|
237
|
+
* Returns { message: string, mode: T } or null if aborted/closed
|
|
238
|
+
*/
|
|
239
|
+
async waitForMessagesAndGetAsString(abortSignal) {
|
|
240
|
+
if (this.queue.length > 0) {
|
|
241
|
+
return this.collectBatch();
|
|
242
|
+
}
|
|
243
|
+
if (this.closed || abortSignal?.aborted) {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
const hasMessages = await this.waitForMessages(abortSignal);
|
|
247
|
+
if (!hasMessages) {
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
return this.collectBatch();
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Collect a batch of messages with the same mode, respecting isolation requirements
|
|
254
|
+
*/
|
|
255
|
+
collectBatch() {
|
|
256
|
+
if (this.queue.length === 0) {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
const firstItem = this.queue[0];
|
|
260
|
+
const sameModeMessages = [];
|
|
261
|
+
const collectedAttachments = [];
|
|
262
|
+
let mode = firstItem.mode;
|
|
263
|
+
let isolate = firstItem.isolate ?? false;
|
|
264
|
+
const targetModeHash = firstItem.modeHash;
|
|
265
|
+
if (firstItem.isolate) {
|
|
266
|
+
const item = this.queue.shift();
|
|
267
|
+
sameModeMessages.push(item.message);
|
|
268
|
+
if (item.attachments) collectedAttachments.push(...item.attachments);
|
|
269
|
+
logger.logger.debug(`[MessageQueue2] Collected isolated message with mode hash: ${targetModeHash}`);
|
|
270
|
+
} else {
|
|
271
|
+
while (this.queue.length > 0 && this.queue[0].modeHash === targetModeHash && !this.queue[0].isolate) {
|
|
272
|
+
const item = this.queue.shift();
|
|
273
|
+
sameModeMessages.push(item.message);
|
|
274
|
+
mode = item.mode;
|
|
275
|
+
if (item.attachments) collectedAttachments.push(...item.attachments);
|
|
276
|
+
}
|
|
277
|
+
logger.logger.debug(`[MessageQueue2] Collected batch of ${sameModeMessages.length} messages with mode hash: ${targetModeHash}`);
|
|
278
|
+
}
|
|
279
|
+
const combinedMessage = sameModeMessages.join("\n");
|
|
280
|
+
return {
|
|
281
|
+
message: combinedMessage,
|
|
282
|
+
mode,
|
|
283
|
+
hash: targetModeHash,
|
|
284
|
+
isolate,
|
|
285
|
+
attachments: collectedAttachments.length > 0 ? collectedAttachments : void 0
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Wait for messages to arrive
|
|
290
|
+
*/
|
|
291
|
+
waitForMessages(abortSignal) {
|
|
292
|
+
return new Promise((resolve) => {
|
|
293
|
+
let abortHandler = null;
|
|
294
|
+
if (abortSignal) {
|
|
295
|
+
abortHandler = () => {
|
|
296
|
+
logger.logger.debug("[MessageQueue2] Wait aborted");
|
|
297
|
+
if (this.waiter === waiterFunc) {
|
|
298
|
+
this.waiter = null;
|
|
299
|
+
}
|
|
300
|
+
resolve(false);
|
|
301
|
+
};
|
|
302
|
+
abortSignal.addEventListener("abort", abortHandler);
|
|
303
|
+
}
|
|
304
|
+
const waiterFunc = (hasMessages) => {
|
|
305
|
+
if (abortHandler && abortSignal) {
|
|
306
|
+
abortSignal.removeEventListener("abort", abortHandler);
|
|
307
|
+
}
|
|
308
|
+
resolve(hasMessages);
|
|
309
|
+
};
|
|
310
|
+
if (this.queue.length > 0) {
|
|
311
|
+
if (abortHandler && abortSignal) {
|
|
312
|
+
abortSignal.removeEventListener("abort", abortHandler);
|
|
313
|
+
}
|
|
314
|
+
resolve(true);
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
if (this.closed || abortSignal?.aborted) {
|
|
318
|
+
if (abortHandler && abortSignal) {
|
|
319
|
+
abortSignal.removeEventListener("abort", abortHandler);
|
|
320
|
+
}
|
|
321
|
+
resolve(false);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
this.waiter = waiterFunc;
|
|
325
|
+
logger.logger.debug("[MessageQueue2] Waiting for messages...");
|
|
326
|
+
this.onWaitHandler?.();
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function registerKillSessionHandler(rpcHandlerManager, killThisHappy, archiveEvents, options) {
|
|
332
|
+
let terminationStarted = false;
|
|
333
|
+
const terminateOnce = () => {
|
|
334
|
+
if (terminationStarted) return;
|
|
335
|
+
terminationStarted = true;
|
|
336
|
+
void killThisHappy();
|
|
337
|
+
};
|
|
338
|
+
archiveEvents.on("archived", terminateOnce);
|
|
339
|
+
if (options?.processSignals) {
|
|
340
|
+
process.on("SIGTERM", terminateOnce);
|
|
341
|
+
process.on("SIGINT", terminateOnce);
|
|
342
|
+
}
|
|
343
|
+
rpcHandlerManager.registerHandler("killSession", async () => {
|
|
344
|
+
logger.logger.debug("Kill session request received");
|
|
345
|
+
terminateOnce();
|
|
346
|
+
return {
|
|
347
|
+
success: true,
|
|
348
|
+
message: "Killing happy-cli process"
|
|
349
|
+
};
|
|
350
|
+
});
|
|
351
|
+
return () => {
|
|
352
|
+
archiveEvents.off?.("archived", terminateOnce);
|
|
353
|
+
if (options?.processSignals) {
|
|
354
|
+
process.off("SIGTERM", terminateOnce);
|
|
355
|
+
process.off("SIGINT", terminateOnce);
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
exports.MessageQueue2 = MessageQueue2;
|
|
361
|
+
exports.registerKillSessionHandler = registerKillSessionHandler;
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import { l as logger } from './logger-6HYUEXNk.mjs';
|
|
2
|
+
import 'axios';
|
|
3
|
+
import 'node:events';
|
|
4
|
+
import 'socket.io-client';
|
|
5
|
+
import './attachmentLimits-yba1uHFO.mjs';
|
|
6
|
+
import 'node:crypto';
|
|
7
|
+
import 'tweetnacl';
|
|
8
|
+
import './configuration-RfeNjFmd.mjs';
|
|
9
|
+
import './index-qdS1friN.mjs';
|
|
10
|
+
import './registerCommonHandlers-Ccvsz7Ou.mjs';
|
|
11
|
+
import 'os';
|
|
12
|
+
import 'child_process';
|
|
13
|
+
import '@paralleldrive/cuid2';
|
|
14
|
+
import './persistence-HGW_ZVs9.mjs';
|
|
15
|
+
import 'chalk';
|
|
16
|
+
import './types-CkqAACXx.mjs';
|
|
17
|
+
|
|
18
|
+
class MessageQueue2 {
|
|
19
|
+
queue = [];
|
|
20
|
+
// Made public for testing
|
|
21
|
+
waiter = null;
|
|
22
|
+
closed = false;
|
|
23
|
+
onMessageHandler = null;
|
|
24
|
+
/**
|
|
25
|
+
* B-332: fired for every item the queue itself destroys before it was ever
|
|
26
|
+
* handed to the runner. The runner wires this to a queue-cancel tombstone
|
|
27
|
+
* so the web stops painting a silently-lost message as "queued".
|
|
28
|
+
*/
|
|
29
|
+
onDiscardHandler = null;
|
|
30
|
+
/**
|
|
31
|
+
* B-509: fired when a consumer starts waiting on an EMPTY queue — the
|
|
32
|
+
* runner has finished its turn and has nothing to run. The server-side
|
|
33
|
+
* prompt queue drain uses it as its "idle" edge (utils/promptQueueDrain.ts).
|
|
34
|
+
*/
|
|
35
|
+
onWaitHandler = null;
|
|
36
|
+
modeHasher;
|
|
37
|
+
constructor(modeHasher, onMessageHandler = null, onDiscardHandler = null) {
|
|
38
|
+
this.modeHasher = modeHasher;
|
|
39
|
+
this.onMessageHandler = onMessageHandler;
|
|
40
|
+
this.onDiscardHandler = onDiscardHandler;
|
|
41
|
+
logger.debug(`[MessageQueue2] Initialized`);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Set a handler that will be called when a message arrives
|
|
45
|
+
*/
|
|
46
|
+
setOnMessage(handler) {
|
|
47
|
+
this.onMessageHandler = handler;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Set a handler that will be called when messages are discarded without ever
|
|
51
|
+
* being processed (B-332).
|
|
52
|
+
*/
|
|
53
|
+
setOnDiscard(handler) {
|
|
54
|
+
this.onDiscardHandler = handler;
|
|
55
|
+
}
|
|
56
|
+
/** B-509: observe the consumer blocking on an empty queue. */
|
|
57
|
+
setOnWait(handler) {
|
|
58
|
+
this.onWaitHandler = handler;
|
|
59
|
+
}
|
|
60
|
+
/** B-509: true while a consumer is blocked waiting for the next message. */
|
|
61
|
+
isWaiting() {
|
|
62
|
+
return this.waiter !== null;
|
|
63
|
+
}
|
|
64
|
+
/** Report the current items as destroyed for `reason` (caller clears next). */
|
|
65
|
+
notifyDiscard(reason) {
|
|
66
|
+
if (this.queue.length === 0) return;
|
|
67
|
+
const entries = this.queue.map((item) => ({ sourceId: item.sourceId, reason }));
|
|
68
|
+
this.onDiscardHandler?.(entries);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Push a message to the queue with a mode and an optional list of
|
|
72
|
+
* attachments that travel with this message.
|
|
73
|
+
*/
|
|
74
|
+
push(message, mode, attachments, sourceId) {
|
|
75
|
+
if (this.closed) {
|
|
76
|
+
throw new Error("Cannot push to closed queue");
|
|
77
|
+
}
|
|
78
|
+
const modeHash = this.modeHasher(mode);
|
|
79
|
+
logger.debug(`[MessageQueue2] push() called with mode hash: ${modeHash}`);
|
|
80
|
+
this.queue.push({
|
|
81
|
+
message,
|
|
82
|
+
mode,
|
|
83
|
+
modeHash,
|
|
84
|
+
isolate: false,
|
|
85
|
+
attachments,
|
|
86
|
+
sourceId
|
|
87
|
+
});
|
|
88
|
+
if (this.onMessageHandler) {
|
|
89
|
+
this.onMessageHandler(message, mode);
|
|
90
|
+
}
|
|
91
|
+
if (this.waiter) {
|
|
92
|
+
logger.debug(`[MessageQueue2] Notifying waiter`);
|
|
93
|
+
const waiter = this.waiter;
|
|
94
|
+
this.waiter = null;
|
|
95
|
+
waiter(true);
|
|
96
|
+
}
|
|
97
|
+
logger.debug(`[MessageQueue2] push() completed. Queue size: ${this.queue.length}`);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Push a message immediately without batching delay.
|
|
101
|
+
* Does not clear the queue or enforce isolation.
|
|
102
|
+
*/
|
|
103
|
+
pushImmediate(message, mode) {
|
|
104
|
+
if (this.closed) {
|
|
105
|
+
throw new Error("Cannot push to closed queue");
|
|
106
|
+
}
|
|
107
|
+
const modeHash = this.modeHasher(mode);
|
|
108
|
+
logger.debug(`[MessageQueue2] pushImmediate() called with mode hash: ${modeHash}`);
|
|
109
|
+
this.queue.push({
|
|
110
|
+
message,
|
|
111
|
+
mode,
|
|
112
|
+
modeHash,
|
|
113
|
+
isolate: false
|
|
114
|
+
});
|
|
115
|
+
if (this.onMessageHandler) {
|
|
116
|
+
this.onMessageHandler(message, mode);
|
|
117
|
+
}
|
|
118
|
+
if (this.waiter) {
|
|
119
|
+
logger.debug(`[MessageQueue2] Notifying waiter for immediate message`);
|
|
120
|
+
const waiter = this.waiter;
|
|
121
|
+
this.waiter = null;
|
|
122
|
+
waiter(true);
|
|
123
|
+
}
|
|
124
|
+
logger.debug(`[MessageQueue2] pushImmediate() completed. Queue size: ${this.queue.length}`);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Push a message that must be processed in complete isolation.
|
|
128
|
+
* Clears any pending messages and ensures this message is never batched with others.
|
|
129
|
+
* Used for special commands that require dedicated processing.
|
|
130
|
+
*/
|
|
131
|
+
pushIsolateAndClear(message, mode, attachments, sourceId) {
|
|
132
|
+
if (this.closed) {
|
|
133
|
+
throw new Error("Cannot push to closed queue");
|
|
134
|
+
}
|
|
135
|
+
const modeHash = this.modeHasher(mode);
|
|
136
|
+
logger.debug(`[MessageQueue2] pushIsolateAndClear() called with mode hash: ${modeHash} - clearing ${this.queue.length} pending messages`);
|
|
137
|
+
this.notifyDiscard("cleared");
|
|
138
|
+
this.queue = [];
|
|
139
|
+
this.queue.push({
|
|
140
|
+
message,
|
|
141
|
+
mode,
|
|
142
|
+
modeHash,
|
|
143
|
+
isolate: true,
|
|
144
|
+
attachments,
|
|
145
|
+
sourceId
|
|
146
|
+
});
|
|
147
|
+
if (this.onMessageHandler) {
|
|
148
|
+
this.onMessageHandler(message, mode);
|
|
149
|
+
}
|
|
150
|
+
if (this.waiter) {
|
|
151
|
+
logger.debug(`[MessageQueue2] Notifying waiter for isolated message`);
|
|
152
|
+
const waiter = this.waiter;
|
|
153
|
+
this.waiter = null;
|
|
154
|
+
waiter(true);
|
|
155
|
+
}
|
|
156
|
+
logger.debug(`[MessageQueue2] pushIsolateAndClear() completed. Queue size: ${this.queue.length}`);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Push a message to the beginning of the queue with a mode.
|
|
160
|
+
*/
|
|
161
|
+
unshift(message, mode) {
|
|
162
|
+
if (this.closed) {
|
|
163
|
+
throw new Error("Cannot unshift to closed queue");
|
|
164
|
+
}
|
|
165
|
+
const modeHash = this.modeHasher(mode);
|
|
166
|
+
logger.debug(`[MessageQueue2] unshift() called with mode hash: ${modeHash}`);
|
|
167
|
+
this.queue.unshift({
|
|
168
|
+
message,
|
|
169
|
+
mode,
|
|
170
|
+
modeHash,
|
|
171
|
+
isolate: false
|
|
172
|
+
});
|
|
173
|
+
if (this.onMessageHandler) {
|
|
174
|
+
this.onMessageHandler(message, mode);
|
|
175
|
+
}
|
|
176
|
+
if (this.waiter) {
|
|
177
|
+
logger.debug(`[MessageQueue2] Notifying waiter`);
|
|
178
|
+
const waiter = this.waiter;
|
|
179
|
+
this.waiter = null;
|
|
180
|
+
waiter(true);
|
|
181
|
+
}
|
|
182
|
+
logger.debug(`[MessageQueue2] unshift() completed. Queue size: ${this.queue.length}`);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Reset the queue - clears all messages and resets to empty state
|
|
186
|
+
*/
|
|
187
|
+
reset() {
|
|
188
|
+
logger.debug(`[MessageQueue2] reset() called. Clearing ${this.queue.length} messages`);
|
|
189
|
+
this.notifyDiscard("aborted");
|
|
190
|
+
this.queue = [];
|
|
191
|
+
this.closed = false;
|
|
192
|
+
this.waiter = null;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Close the queue - no more messages can be pushed
|
|
196
|
+
*/
|
|
197
|
+
close() {
|
|
198
|
+
logger.debug(`[MessageQueue2] close() called`);
|
|
199
|
+
this.closed = true;
|
|
200
|
+
if (this.waiter) {
|
|
201
|
+
const waiter = this.waiter;
|
|
202
|
+
this.waiter = null;
|
|
203
|
+
waiter(false);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Check if the queue is closed
|
|
208
|
+
*/
|
|
209
|
+
isClosed() {
|
|
210
|
+
return this.closed;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Get the current queue size
|
|
214
|
+
*/
|
|
215
|
+
size() {
|
|
216
|
+
return this.queue.length;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Remove one message that has not yet been collected by the agent loop.
|
|
220
|
+
* Source id is authoritative. Exact-text fallback only covers items that
|
|
221
|
+
* entered this live process before transport ids were introduced.
|
|
222
|
+
*/
|
|
223
|
+
cancelPending(sourceId, exactText) {
|
|
224
|
+
let index = sourceId ? this.queue.findIndex((item) => item.sourceId === sourceId) : -1;
|
|
225
|
+
if (index < 0 && exactText !== void 0) {
|
|
226
|
+
index = this.queue.findIndex((item) => item.sourceId === void 0 && item.message === exactText);
|
|
227
|
+
}
|
|
228
|
+
if (index < 0) return false;
|
|
229
|
+
this.queue.splice(index, 1);
|
|
230
|
+
logger.debug(`[MessageQueue2] Cancelled pending item. Queue size: ${this.queue.length}`);
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Wait for messages and return all messages with the same mode as a single string
|
|
235
|
+
* Returns { message: string, mode: T } or null if aborted/closed
|
|
236
|
+
*/
|
|
237
|
+
async waitForMessagesAndGetAsString(abortSignal) {
|
|
238
|
+
if (this.queue.length > 0) {
|
|
239
|
+
return this.collectBatch();
|
|
240
|
+
}
|
|
241
|
+
if (this.closed || abortSignal?.aborted) {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
const hasMessages = await this.waitForMessages(abortSignal);
|
|
245
|
+
if (!hasMessages) {
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
return this.collectBatch();
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Collect a batch of messages with the same mode, respecting isolation requirements
|
|
252
|
+
*/
|
|
253
|
+
collectBatch() {
|
|
254
|
+
if (this.queue.length === 0) {
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
const firstItem = this.queue[0];
|
|
258
|
+
const sameModeMessages = [];
|
|
259
|
+
const collectedAttachments = [];
|
|
260
|
+
let mode = firstItem.mode;
|
|
261
|
+
let isolate = firstItem.isolate ?? false;
|
|
262
|
+
const targetModeHash = firstItem.modeHash;
|
|
263
|
+
if (firstItem.isolate) {
|
|
264
|
+
const item = this.queue.shift();
|
|
265
|
+
sameModeMessages.push(item.message);
|
|
266
|
+
if (item.attachments) collectedAttachments.push(...item.attachments);
|
|
267
|
+
logger.debug(`[MessageQueue2] Collected isolated message with mode hash: ${targetModeHash}`);
|
|
268
|
+
} else {
|
|
269
|
+
while (this.queue.length > 0 && this.queue[0].modeHash === targetModeHash && !this.queue[0].isolate) {
|
|
270
|
+
const item = this.queue.shift();
|
|
271
|
+
sameModeMessages.push(item.message);
|
|
272
|
+
mode = item.mode;
|
|
273
|
+
if (item.attachments) collectedAttachments.push(...item.attachments);
|
|
274
|
+
}
|
|
275
|
+
logger.debug(`[MessageQueue2] Collected batch of ${sameModeMessages.length} messages with mode hash: ${targetModeHash}`);
|
|
276
|
+
}
|
|
277
|
+
const combinedMessage = sameModeMessages.join("\n");
|
|
278
|
+
return {
|
|
279
|
+
message: combinedMessage,
|
|
280
|
+
mode,
|
|
281
|
+
hash: targetModeHash,
|
|
282
|
+
isolate,
|
|
283
|
+
attachments: collectedAttachments.length > 0 ? collectedAttachments : void 0
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Wait for messages to arrive
|
|
288
|
+
*/
|
|
289
|
+
waitForMessages(abortSignal) {
|
|
290
|
+
return new Promise((resolve) => {
|
|
291
|
+
let abortHandler = null;
|
|
292
|
+
if (abortSignal) {
|
|
293
|
+
abortHandler = () => {
|
|
294
|
+
logger.debug("[MessageQueue2] Wait aborted");
|
|
295
|
+
if (this.waiter === waiterFunc) {
|
|
296
|
+
this.waiter = null;
|
|
297
|
+
}
|
|
298
|
+
resolve(false);
|
|
299
|
+
};
|
|
300
|
+
abortSignal.addEventListener("abort", abortHandler);
|
|
301
|
+
}
|
|
302
|
+
const waiterFunc = (hasMessages) => {
|
|
303
|
+
if (abortHandler && abortSignal) {
|
|
304
|
+
abortSignal.removeEventListener("abort", abortHandler);
|
|
305
|
+
}
|
|
306
|
+
resolve(hasMessages);
|
|
307
|
+
};
|
|
308
|
+
if (this.queue.length > 0) {
|
|
309
|
+
if (abortHandler && abortSignal) {
|
|
310
|
+
abortSignal.removeEventListener("abort", abortHandler);
|
|
311
|
+
}
|
|
312
|
+
resolve(true);
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
if (this.closed || abortSignal?.aborted) {
|
|
316
|
+
if (abortHandler && abortSignal) {
|
|
317
|
+
abortSignal.removeEventListener("abort", abortHandler);
|
|
318
|
+
}
|
|
319
|
+
resolve(false);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
this.waiter = waiterFunc;
|
|
323
|
+
logger.debug("[MessageQueue2] Waiting for messages...");
|
|
324
|
+
this.onWaitHandler?.();
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function registerKillSessionHandler(rpcHandlerManager, killThisHappy, archiveEvents, options) {
|
|
330
|
+
let terminationStarted = false;
|
|
331
|
+
const terminateOnce = () => {
|
|
332
|
+
if (terminationStarted) return;
|
|
333
|
+
terminationStarted = true;
|
|
334
|
+
void killThisHappy();
|
|
335
|
+
};
|
|
336
|
+
archiveEvents.on("archived", terminateOnce);
|
|
337
|
+
if (options?.processSignals) {
|
|
338
|
+
process.on("SIGTERM", terminateOnce);
|
|
339
|
+
process.on("SIGINT", terminateOnce);
|
|
340
|
+
}
|
|
341
|
+
rpcHandlerManager.registerHandler("killSession", async () => {
|
|
342
|
+
logger.debug("Kill session request received");
|
|
343
|
+
terminateOnce();
|
|
344
|
+
return {
|
|
345
|
+
success: true,
|
|
346
|
+
message: "Killing happy-cli process"
|
|
347
|
+
};
|
|
348
|
+
});
|
|
349
|
+
return () => {
|
|
350
|
+
archiveEvents.off?.("archived", terminateOnce);
|
|
351
|
+
if (options?.processSignals) {
|
|
352
|
+
process.off("SIGTERM", terminateOnce);
|
|
353
|
+
process.off("SIGINT", terminateOnce);
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export { MessageQueue2 as M, registerKillSessionHandler as r };
|