very-happy-cli 0.2.159 → 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-DUYFlyfN.cjs → AcpBackend-Bm2rdke8.cjs} +78 -76
- package/dist/{AcpBackend-VsfkZiVF.mjs → AcpBackend-mzv8Dhba.mjs} +4 -2
- package/dist/{AcpSessionManager-Bdv8LWXh.cjs → AcpSessionManager-BAY1Pggx.cjs} +9 -9
- package/dist/{AcpSessionManager-rYtVb0kN.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-CHh4lmjM.cjs → agentHome-CboCeKWq.cjs} +14 -28
- package/dist/{agentHome-CvsJyeQB.mjs → agentHome-Dj1C43aJ.mjs} +8 -22
- package/dist/api-CLMUr-SX.mjs +3339 -0
- package/dist/api-CgundNNX.cjs +3346 -0
- package/dist/{types-Dh-s4Lqs.mjs → apiMachine-B9dLW_p5.mjs} +9116 -16205
- package/dist/{types-BbvK1Tr_.cjs → apiMachine-Bn8482VM.cjs} +9104 -16247
- 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-DKmEls8Z.cjs → auto-BOX_fgmR.cjs} +70 -79
- package/dist/{auto-nb8GhRRy.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-ClLtM6F3.mjs → config-CTx_jb-C.mjs} +7 -40
- package/dist/{config-DLx-vW3I.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-BEOMECtE.cjs → index-B6pAdvJx.cjs} +121 -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-2mCaeKyf.mjs → index-DMZqWwsP.mjs} +68 -38
- 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-BPhJppvd.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-BOHrUaFM.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-Cou3WUf3.cjs → installTerminalHooks-BQZbvxsZ.cjs} +5 -40
- package/dist/{installTerminalHooks-WeznjkuC.mjs → installTerminalHooks-By7gBMEF.mjs} +3 -38
- package/dist/lib.cjs +28 -19
- package/dist/lib.d.cts +12 -2
- package/dist/lib.d.mts +12 -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-Dy3f_K0h.mjs → mcp-B1A4I3TK.mjs} +27 -33
- package/dist/{mcp-CPYbtsYG.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-kLZNpAAl.mjs → piRuntime-CSGkwCKQ.mjs} +2 -2
- package/dist/{piRuntime-NtF0YqjH.cjs → piRuntime-C_H7MJCM.cjs} +4 -4
- package/dist/{piTerminal-B0fEOV_2.mjs → piTerminal-C8a1OrNQ.mjs} +32 -35
- package/dist/{piTerminal-9J0GAKzb.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-DV6Ouadt.mjs → runGemini-BGeTz57m.mjs} +58 -31
- package/dist/{runGemini-F-mqx3_K.cjs → runGemini-DSr9LIxL.cjs} +202 -175
- package/dist/{runOpenClaw-Qqo9j63M.cjs → runOpenClaw-B1mTxN35.cjs} +64 -65
- package/dist/{runOpenClaw-D7MlPS5n.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-4qJTCAYW.cjs → send-B7J_eaG3.cjs} +16 -9
- package/dist/{send-CLhYXNgy.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-CzIH2rGp.mjs → sessions-BEG_HTSi.mjs} +17 -8
- package/dist/{sessions-Bh1pyddi.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-CPIWlPOM.mjs → spawn-B7yro0b2.mjs} +26 -38
- package/dist/{spawn-CmFOSVdW.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-CEahj4cm.mjs → teams-C32F1hqd.mjs} +9 -40
- package/dist/{teams-CB1R9-Z9.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-DqyRI4wP.cjs → todo-BvUOTa8G.cjs} +15 -12
- package/dist/{todo-Cknp5D4U.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-BRDN1NoZ.cjs +0 -2217
- package/dist/agentGuidance-KgvYuF3R.mjs +0 -2145
- package/dist/index-BF6WfgV5.mjs +0 -19624
- package/dist/index-C-JazrMB.mjs +0 -52
- package/dist/index-blDSadUR.cjs +0 -58
- package/dist/index-rH3DrQ5B.cjs +0 -19688
- package/dist/limits-BH5CV5vR.cjs +0 -2683
- package/dist/limits-CjRj8IX5.mjs +0 -2558
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var index = require('./index-DA7yINuk.cjs');
|
|
4
|
+
var promises = require('node:fs/promises');
|
|
5
|
+
var node_crypto = require('node:crypto');
|
|
6
|
+
var node_fs = require('node:fs');
|
|
7
|
+
var path = require('node:path');
|
|
8
|
+
var z = require('zod');
|
|
9
|
+
var client = require('./client-3Ac-O4pw.cjs');
|
|
10
|
+
var context = require('./context-DsDr6E2t.cjs');
|
|
11
|
+
var sessionOps = require('./sessionOps-Dn8z85h_.cjs');
|
|
12
|
+
var resources = require('./resources-JDPugcDq.cjs');
|
|
13
|
+
var tools = require('./tools-Be3AoAwu.cjs');
|
|
14
|
+
var tools$1 = require('./tools-DQj0AeLk.cjs');
|
|
15
|
+
var peerTools = require('./peerTools-BvKtHXj8.cjs');
|
|
16
|
+
var mcp_js = require('@modelcontextprotocol/sdk/server/mcp.js');
|
|
17
|
+
var node_http = require('node:http');
|
|
18
|
+
var streamableHttp_js = require('@modelcontextprotocol/sdk/server/streamableHttp.js');
|
|
19
|
+
var logger = require('./logger-CS0mw3fa.cjs');
|
|
20
|
+
var limits = require('./limits-C-a7gr04.cjs');
|
|
21
|
+
var assistantTools = require('./assistantTools-BTqPnlFl.cjs');
|
|
22
|
+
var agentGuidance = require('./agentGuidance-B5NATuFa.cjs');
|
|
23
|
+
var previewPath = require('./previewPath-B0rBdhy1.cjs');
|
|
24
|
+
var crypto = require('crypto');
|
|
25
|
+
|
|
26
|
+
const TEAMS_ADOPT_CAPABILITY = "teams-adopt-v1";
|
|
27
|
+
const TeamAdoptSchema = z.z.object({
|
|
28
|
+
requestId: z.z.string().min(1).max(128),
|
|
29
|
+
name: z.z.string().trim().min(1).max(128),
|
|
30
|
+
teamId: z.z.string().min(1).max(128).optional()
|
|
31
|
+
}).strict();
|
|
32
|
+
async function retainIntent(path$1, input) {
|
|
33
|
+
await promises.mkdir(path.dirname(path$1), { recursive: true, mode: 448 });
|
|
34
|
+
let file;
|
|
35
|
+
try {
|
|
36
|
+
file = await promises.open(path$1, node_fs.constants.O_WRONLY | node_fs.constants.O_CREAT | node_fs.constants.O_EXCL, 384);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
if (error.code !== "EEXIST") throw new Error("Cannot retain team connection request");
|
|
39
|
+
}
|
|
40
|
+
if (file) {
|
|
41
|
+
try {
|
|
42
|
+
await file.writeFile(JSON.stringify(input));
|
|
43
|
+
await file.sync();
|
|
44
|
+
} finally {
|
|
45
|
+
await file.close();
|
|
46
|
+
}
|
|
47
|
+
return { fresh: true };
|
|
48
|
+
}
|
|
49
|
+
const existing = await promises.open(path$1, node_fs.constants.O_RDONLY | (node_fs.constants.O_NOFOLLOW ?? 0));
|
|
50
|
+
try {
|
|
51
|
+
const stat = await existing.stat();
|
|
52
|
+
if (!stat.isFile() || process.platform !== "win32" && (stat.mode & 63) !== 0 || typeof process.getuid === "function" && stat.uid !== process.getuid()) throw new Error("Unsafe team connection receipt");
|
|
53
|
+
const stored = JSON.parse(await existing.readFile("utf8"));
|
|
54
|
+
const { resolvedTeamId, guidanceDelivered, ...request } = stored;
|
|
55
|
+
const previous = TeamAdoptSchema.parse(request);
|
|
56
|
+
if (JSON.stringify(previous) !== JSON.stringify(input)) throw new Error("Another team connection request already exists; retry the original request");
|
|
57
|
+
if (resolvedTeamId !== void 0 && (typeof resolvedTeamId !== "string" || !resolvedTeamId)) throw new Error("Invalid connection receipt");
|
|
58
|
+
if (guidanceDelivered !== void 0 && typeof guidanceDelivered !== "boolean") throw new Error("Invalid guidance receipt");
|
|
59
|
+
return { resolvedTeamId, guidanceDelivered };
|
|
60
|
+
} finally {
|
|
61
|
+
await existing.close();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async function retainTeam(path, input, resolvedTeamId, guidanceDelivered = false) {
|
|
65
|
+
const temporary = `${path}.${node_crypto.randomUUID()}.new`;
|
|
66
|
+
const file = await promises.open(temporary, "wx", 384);
|
|
67
|
+
try {
|
|
68
|
+
await file.writeFile(JSON.stringify({ ...input, resolvedTeamId, guidanceDelivered }));
|
|
69
|
+
await file.sync();
|
|
70
|
+
} finally {
|
|
71
|
+
await file.close();
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
await promises.rename(temporary, path);
|
|
75
|
+
} finally {
|
|
76
|
+
await promises.unlink(temporary).catch(() => {
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function createTeamAdoption(sessionId) {
|
|
81
|
+
const client$1 = client.createTeamsClient(sessionId);
|
|
82
|
+
let current;
|
|
83
|
+
return (raw) => {
|
|
84
|
+
const parsed = TeamAdoptSchema.safeParse(raw);
|
|
85
|
+
if (!parsed.success) return { error: "Invalid team connection request" };
|
|
86
|
+
if (process.env.VH_TEAM_SCOPE_FILE) return { error: "Assigned team members cannot create or join another team" };
|
|
87
|
+
let path;
|
|
88
|
+
try {
|
|
89
|
+
path = `${context.teamScopePath(sessionId)}.adopt.json`;
|
|
90
|
+
} catch {
|
|
91
|
+
return { error: "A managed session identity is required" };
|
|
92
|
+
}
|
|
93
|
+
const input = parsed.data;
|
|
94
|
+
const signature = JSON.stringify(input);
|
|
95
|
+
if (current) {
|
|
96
|
+
if (current.signature !== signature && current.safeToChange) current = void 0;
|
|
97
|
+
else if (current.signature !== signature) return { error: "Another team connection request already exists; retry the original request" };
|
|
98
|
+
}
|
|
99
|
+
if (current) {
|
|
100
|
+
const result = current.result;
|
|
101
|
+
if (result && "error" in result) current = void 0;
|
|
102
|
+
return result ?? { status: "pending", requestId: input.requestId };
|
|
103
|
+
}
|
|
104
|
+
const operation = { signature };
|
|
105
|
+
current = operation;
|
|
106
|
+
void (async () => {
|
|
107
|
+
let intent;
|
|
108
|
+
try {
|
|
109
|
+
intent = await retainIntent(path, input);
|
|
110
|
+
const connected = await client$1.initialize(input, { resumeAdoption: true, expectedTeamId: intent.resolvedTeamId, onTeamResolved: (teamId) => retainTeam(path, input, teamId, intent?.guidanceDelivered) });
|
|
111
|
+
const instructions = `${resources.TEAM_SKILL}
|
|
112
|
+
|
|
113
|
+
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.`;
|
|
114
|
+
if (!intent.guidanceDelivered) {
|
|
115
|
+
const key = await sessionOps.waitForSessionKey(sessionId, 1e4);
|
|
116
|
+
await sessionOps.sendUserMessage(sessionId, key, instructions, "teams", { localId: `teams-adopt-${input.requestId}`, sentFrom: "team" });
|
|
117
|
+
await retainTeam(path, input, connected.team.id, true);
|
|
118
|
+
}
|
|
119
|
+
operation.result = { status: "connected", teamId: connected.team.id, botId: connected.botId, instructions };
|
|
120
|
+
} catch (error) {
|
|
121
|
+
if (error instanceof client.TeamConnectionPreflightError && intent?.fresh && !intent.resolvedTeamId) {
|
|
122
|
+
await promises.unlink(path).catch(() => {
|
|
123
|
+
});
|
|
124
|
+
operation.safeToChange = true;
|
|
125
|
+
}
|
|
126
|
+
operation.result = { error: error instanceof Error ? error.message : "Team connection failed; retry the same request", ...operation.safeToChange ? { safeToChange: true } : {} };
|
|
127
|
+
}
|
|
128
|
+
})();
|
|
129
|
+
return { status: "pending", requestId: input.requestId };
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const SELF_REPORT_MIN_INTERVAL_MS = 30 * 1e3;
|
|
134
|
+
const SELF_REPORT_FRESH_MS = 15 * 60 * 1e3;
|
|
135
|
+
const PROGRESS_MAX_CHARS = 200;
|
|
136
|
+
function createSelfReportState() {
|
|
137
|
+
return { lastAcceptedAt: 0 };
|
|
138
|
+
}
|
|
139
|
+
function shouldAcceptSelfReport(state, now, attention) {
|
|
140
|
+
if (state.lastAcceptedAt === 0) return true;
|
|
141
|
+
if (attention !== void 0 && attention !== state.lastAttention) return true;
|
|
142
|
+
return now - state.lastAcceptedAt >= SELF_REPORT_MIN_INTERVAL_MS;
|
|
143
|
+
}
|
|
144
|
+
function isSelfReportFresh(state, now) {
|
|
145
|
+
if (state.lastAcceptedAt === 0) return false;
|
|
146
|
+
const age = now - state.lastAcceptedAt;
|
|
147
|
+
return age >= 0 && age < SELF_REPORT_FRESH_MS;
|
|
148
|
+
}
|
|
149
|
+
function normalizeProgress(value) {
|
|
150
|
+
if (typeof value !== "string") return null;
|
|
151
|
+
const flat = value.replace(/\s+/g, " ").trim();
|
|
152
|
+
if (!flat) return null;
|
|
153
|
+
return flat.length > PROGRESS_MAX_CHARS ? flat.slice(0, PROGRESS_MAX_CHARS) : flat;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function createMcpServer(handlers, options, sessionId, client) {
|
|
157
|
+
const mcp = new mcp_js.McpServer({
|
|
158
|
+
name: "Very Happy Tools",
|
|
159
|
+
version: "1.0.0"
|
|
160
|
+
});
|
|
161
|
+
tools.registerTeamsTools(mcp, sessionId);
|
|
162
|
+
tools$1.registerAutomationTools(mcp);
|
|
163
|
+
if (client) peerTools.registerSessionPeerTools(mcp, peerTools.createSessionPeerToolExecutor(client));
|
|
164
|
+
mcp.registerTool("change_title", {
|
|
165
|
+
description: "Change the title of the current chat session",
|
|
166
|
+
title: "Change Chat Title",
|
|
167
|
+
inputSchema: {
|
|
168
|
+
title: z.z.string().describe("The new title for the chat session")
|
|
169
|
+
}
|
|
170
|
+
}, async (args) => {
|
|
171
|
+
const response = await handlers.changeTitle(args.title);
|
|
172
|
+
logger.logger.debug("[happyMCP] Response:", response);
|
|
173
|
+
if (response.success) {
|
|
174
|
+
return {
|
|
175
|
+
content: [
|
|
176
|
+
{
|
|
177
|
+
type: "text",
|
|
178
|
+
text: `Successfully changed chat title to: "${args.title}"`
|
|
179
|
+
}
|
|
180
|
+
],
|
|
181
|
+
isError: false
|
|
182
|
+
};
|
|
183
|
+
} else {
|
|
184
|
+
return {
|
|
185
|
+
content: [
|
|
186
|
+
{
|
|
187
|
+
type: "text",
|
|
188
|
+
text: `Failed to change chat title: ${response.error || "Unknown error"}`
|
|
189
|
+
}
|
|
190
|
+
],
|
|
191
|
+
isError: true
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
mcp.registerTool(limits.CLIPBOARD_TOOL_NAME, {
|
|
196
|
+
description: limits.CLIPBOARD_TOOL_DESCRIPTION,
|
|
197
|
+
title: limits.CLIPBOARD_TOOL_TITLE,
|
|
198
|
+
inputSchema: {
|
|
199
|
+
text: z.z.string().describe("The text to copy to the user's clipboard")
|
|
200
|
+
}
|
|
201
|
+
}, async (args) => {
|
|
202
|
+
const response = await handlers.copyToClipboard(args.text);
|
|
203
|
+
logger.logger.debug("[happyMCP] copy_to_clipboard response:", response);
|
|
204
|
+
if (response.delivered) {
|
|
205
|
+
const note = response.truncated ? ` (truncated to ${limits.CLIPBOARD_MAX_BYTES / 1024}KB \u2014 original was ${response.totalBytes} bytes)` : "";
|
|
206
|
+
return {
|
|
207
|
+
content: [{
|
|
208
|
+
type: "text",
|
|
209
|
+
text: `Queued a clipboard request for the user's open Very Happy device(s)${note}. This does not confirm that a browser wrote the clipboard; the user may need to tap a confirmation button.`
|
|
210
|
+
}],
|
|
211
|
+
isError: false
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
content: [{
|
|
216
|
+
type: "text",
|
|
217
|
+
text: `Failed to push to clipboard: ${response.error || "not connected to the server"}`
|
|
218
|
+
}],
|
|
219
|
+
isError: true
|
|
220
|
+
};
|
|
221
|
+
});
|
|
222
|
+
mcp.registerTool(agentGuidance.PREVIEW_TOOL_NAME, {
|
|
223
|
+
description: agentGuidance.PREVIEW_TOOL_DESCRIPTION,
|
|
224
|
+
title: agentGuidance.PREVIEW_TOOL_TITLE,
|
|
225
|
+
inputSchema: {
|
|
226
|
+
path: z.z.string().describe("Absolute path (or ~/\u2026) of the file to show the user"),
|
|
227
|
+
mode: z.z.enum(["file", "diff"]).optional().describe("'file' (default) renders the file; 'diff' is reserved and currently falls back to 'file'")
|
|
228
|
+
}
|
|
229
|
+
}, async (args) => {
|
|
230
|
+
const response = await handlers.openPreview(args.path, args.mode ?? "file");
|
|
231
|
+
logger.logger.debug("[happyMCP] open_preview response:", response);
|
|
232
|
+
if (response.delivered) {
|
|
233
|
+
return {
|
|
234
|
+
content: [{
|
|
235
|
+
type: "text",
|
|
236
|
+
// 明说不保证用户看到了——否则 claude 会基于「已预览」做后续推断(spec 风险 8)
|
|
237
|
+
text: `Asked the user's open web client(s) to preview ${response.resolved ?? args.path}. This does not confirm they looked at it.`
|
|
238
|
+
}],
|
|
239
|
+
isError: false
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
return {
|
|
243
|
+
content: [{ type: "text", text: `Could not open preview: ${response.error || "unknown error"}` }],
|
|
244
|
+
isError: true
|
|
245
|
+
};
|
|
246
|
+
});
|
|
247
|
+
mcp.registerTool(agentGuidance.REPORT_PROGRESS_TOOL_NAME, {
|
|
248
|
+
description: agentGuidance.REPORT_PROGRESS_TOOL_DESCRIPTION,
|
|
249
|
+
title: agentGuidance.REPORT_PROGRESS_TOOL_TITLE,
|
|
250
|
+
inputSchema: {
|
|
251
|
+
progress: z.z.string().describe("One short line describing the current state of this task"),
|
|
252
|
+
attention: z.z.enum(["none", "review", "blocked"]).optional().describe("'blocked' = cannot proceed without the user; 'review' = wants their eyes; 'none' = ordinary progress")
|
|
253
|
+
}
|
|
254
|
+
}, async (args) => {
|
|
255
|
+
const response = await handlers.reportProgress(args.progress, args.attention ?? "none");
|
|
256
|
+
logger.logger.debug("[happyMCP] report_progress response:", response);
|
|
257
|
+
if (response.accepted) {
|
|
258
|
+
return { content: [{ type: "text", text: "Board updated." }], isError: false };
|
|
259
|
+
}
|
|
260
|
+
return {
|
|
261
|
+
content: [{ type: "text", text: response.error || "Report skipped (reported too recently); no need to retry." }],
|
|
262
|
+
isError: false
|
|
263
|
+
};
|
|
264
|
+
});
|
|
265
|
+
if (options?.assistant && !process.env.VH_TEAM_SCOPE_FILE) {
|
|
266
|
+
assistantTools.registerAssistantTools(mcp);
|
|
267
|
+
}
|
|
268
|
+
return mcp;
|
|
269
|
+
}
|
|
270
|
+
async function startHappyServer(client, options) {
|
|
271
|
+
logger.logger.debug(`[happyMCP] server:start sessionId=${client.sessionId} assistant=${!!options?.assistant}`);
|
|
272
|
+
const selfReportState = options?.selfReportState ?? createSelfReportState();
|
|
273
|
+
const handlers = {
|
|
274
|
+
openPreview: async (path, mode) => {
|
|
275
|
+
const verdict = previewPath.checkPreviewPath(path);
|
|
276
|
+
if (verdict.deniedReason) {
|
|
277
|
+
logger.logger.debug(`[happyMCP] open_preview denied: ${verdict.deniedReason}`);
|
|
278
|
+
return { delivered: false, error: verdict.deniedReason };
|
|
279
|
+
}
|
|
280
|
+
try {
|
|
281
|
+
const result = client.pushFilePreview(verdict.resolved, mode);
|
|
282
|
+
return { delivered: result.delivered, resolved: verdict.resolved, error: result.error };
|
|
283
|
+
} catch (error) {
|
|
284
|
+
return { delivered: false, error: String(error) };
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
reportProgress: async (progress, attention) => {
|
|
288
|
+
const text = normalizeProgress(progress);
|
|
289
|
+
if (!text) {
|
|
290
|
+
return { accepted: false, error: "progress must be a non-empty one-line string" };
|
|
291
|
+
}
|
|
292
|
+
const now = Date.now();
|
|
293
|
+
if (!shouldAcceptSelfReport(selfReportState, now, attention)) {
|
|
294
|
+
return { accepted: false };
|
|
295
|
+
}
|
|
296
|
+
selfReportState.lastAcceptedAt = now;
|
|
297
|
+
selfReportState.lastAttention = attention;
|
|
298
|
+
try {
|
|
299
|
+
client.updateMetadata((metadata) => ({
|
|
300
|
+
...metadata,
|
|
301
|
+
board: {
|
|
302
|
+
...metadata?.board,
|
|
303
|
+
attention,
|
|
304
|
+
progress: text,
|
|
305
|
+
analyzedAt: now,
|
|
306
|
+
// ⚠️ 这个字段**到不了 web**:web 的 MetadataSchema.board 是普通
|
|
307
|
+
// zod object(非 passthrough),safeParse 会把它剥掉;而 web 下
|
|
308
|
+
// 一次写 metadata 又会用剥净的对象回写,把它从服务端也删掉。
|
|
309
|
+
// 留着是为了 daemon 侧日志/未来把字段加进 web schema 时能对上,
|
|
310
|
+
// **别拿它做 UI**(review finding 5:原注释声称能区分自报与
|
|
311
|
+
// haiku 猜的,不成立)。
|
|
312
|
+
source: "self-report"
|
|
313
|
+
}
|
|
314
|
+
}));
|
|
315
|
+
return { accepted: true };
|
|
316
|
+
} catch (error) {
|
|
317
|
+
return { accepted: false, error: String(error) };
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
changeTitle: async (title) => {
|
|
321
|
+
logger.logger.debug("[happyMCP] Changing title to:", title);
|
|
322
|
+
try {
|
|
323
|
+
client.sendClaudeSessionMessage({
|
|
324
|
+
type: "summary",
|
|
325
|
+
summary: title,
|
|
326
|
+
leafUuid: node_crypto.randomUUID()
|
|
327
|
+
});
|
|
328
|
+
return { success: true };
|
|
329
|
+
} catch (error) {
|
|
330
|
+
return { success: false, error: String(error) };
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
copyToClipboard: async (text) => {
|
|
334
|
+
logger.logger.debug(`[happyMCP] Pushing ${text.length} chars to clipboard`);
|
|
335
|
+
try {
|
|
336
|
+
return client.pushClipboard(text);
|
|
337
|
+
} catch (error) {
|
|
338
|
+
return { delivered: false, truncated: false, totalBytes: 0, error: String(error) };
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
const contextPath = "/runtime-context/" + node_crypto.randomUUID();
|
|
343
|
+
const server = node_http.createServer(async (req, res) => {
|
|
344
|
+
if (req.url?.startsWith("/runtime-context/")) {
|
|
345
|
+
if (!options?.onContextUsage || req.url !== contextPath || req.method !== "POST" || req.headers.origin) {
|
|
346
|
+
res.writeHead(403).end();
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
try {
|
|
350
|
+
let body = "";
|
|
351
|
+
for await (const chunk of req) {
|
|
352
|
+
body += chunk.toString();
|
|
353
|
+
if (Buffer.byteLength(body) > 2048) {
|
|
354
|
+
res.writeHead(413).end();
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
const usage = index.ContextUsageSchema.parse({ ...JSON.parse(body), updatedAt: Date.now() });
|
|
359
|
+
options.onContextUsage(usage);
|
|
360
|
+
res.writeHead(204).end();
|
|
361
|
+
} catch {
|
|
362
|
+
if (!res.headersSent) res.writeHead(400).end();
|
|
363
|
+
}
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
const mcp = createMcpServer(handlers, options, client.sessionId, client);
|
|
367
|
+
try {
|
|
368
|
+
const transport = new streamableHttp_js.StreamableHTTPServerTransport({
|
|
369
|
+
sessionIdGenerator: void 0
|
|
370
|
+
});
|
|
371
|
+
await mcp.connect(transport);
|
|
372
|
+
await transport.handleRequest(req, res);
|
|
373
|
+
res.on("close", () => {
|
|
374
|
+
transport.close();
|
|
375
|
+
mcp.close();
|
|
376
|
+
});
|
|
377
|
+
} catch (error) {
|
|
378
|
+
logger.logger.debug("Error handling request:", error);
|
|
379
|
+
if (!res.headersSent) {
|
|
380
|
+
res.writeHead(500).end();
|
|
381
|
+
}
|
|
382
|
+
mcp.close();
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
const baseUrl = await new Promise((resolve) => {
|
|
386
|
+
server.listen(0, "127.0.0.1", () => {
|
|
387
|
+
const addr = server.address();
|
|
388
|
+
resolve(new URL(`http://127.0.0.1:${addr.port}`));
|
|
389
|
+
});
|
|
390
|
+
});
|
|
391
|
+
const adoptionEnabled = !process.env.VH_TEAM_SCOPE_FILE;
|
|
392
|
+
if (adoptionEnabled) {
|
|
393
|
+
client.rpcHandlerManager.registerHandler("teams-adopt", createTeamAdoption(client.sessionId));
|
|
394
|
+
client.updateMetadata((metadata) => ({ ...metadata, capabilities: [.../* @__PURE__ */ new Set([...metadata.capabilities ?? [], TEAMS_ADOPT_CAPABILITY])] }));
|
|
395
|
+
}
|
|
396
|
+
logger.logger.debug(`[happyMCP] server:ready sessionId=${client.sessionId} url=${baseUrl.toString()}`);
|
|
397
|
+
return {
|
|
398
|
+
url: baseUrl.toString(),
|
|
399
|
+
contextUsageUrl: options?.onContextUsage ? new URL(contextPath, baseUrl).toString() : void 0,
|
|
400
|
+
toolNames: [
|
|
401
|
+
"change_title",
|
|
402
|
+
limits.CLIPBOARD_TOOL_NAME,
|
|
403
|
+
agentGuidance.PREVIEW_TOOL_NAME,
|
|
404
|
+
agentGuidance.REPORT_PROGRESS_TOOL_NAME,
|
|
405
|
+
...tools.TEAM_TOOL_NAMES,
|
|
406
|
+
...tools$1.AUTOMATION_TOOL_NAMES,
|
|
407
|
+
...peerTools.SESSION_PEER_TOOL_NAMES,
|
|
408
|
+
...options?.assistant && !process.env.VH_TEAM_SCOPE_FILE ? assistantTools.ASSISTANT_TOOL_NAMES : []
|
|
409
|
+
],
|
|
410
|
+
stop: () => {
|
|
411
|
+
logger.logger.debug(`[happyMCP] server:stop sessionId=${client.sessionId}`);
|
|
412
|
+
if (adoptionEnabled) client.rpcHandlerManager.unregisterHandler("teams-adopt");
|
|
413
|
+
server.close();
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function deterministicStringify(obj, options = {}) {
|
|
419
|
+
const {
|
|
420
|
+
undefinedBehavior = "omit",
|
|
421
|
+
sortArrays = false,
|
|
422
|
+
replacer,
|
|
423
|
+
includeSymbols = false
|
|
424
|
+
} = options;
|
|
425
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
426
|
+
function processValue(value, key) {
|
|
427
|
+
if (replacer && key !== void 0) {
|
|
428
|
+
value = replacer(key, value);
|
|
429
|
+
}
|
|
430
|
+
if (value === null) return null;
|
|
431
|
+
if (value === void 0) {
|
|
432
|
+
switch (undefinedBehavior) {
|
|
433
|
+
case "omit":
|
|
434
|
+
return void 0;
|
|
435
|
+
case "null":
|
|
436
|
+
return null;
|
|
437
|
+
case "throw":
|
|
438
|
+
throw new Error(`Undefined value at key: ${key}`);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
if (typeof value === "boolean" || typeof value === "number" || typeof value === "string") {
|
|
442
|
+
return value;
|
|
443
|
+
}
|
|
444
|
+
if (value instanceof Date) {
|
|
445
|
+
return value.toISOString();
|
|
446
|
+
}
|
|
447
|
+
if (value instanceof RegExp) {
|
|
448
|
+
return value.toString();
|
|
449
|
+
}
|
|
450
|
+
if (typeof value === "function") {
|
|
451
|
+
return void 0;
|
|
452
|
+
}
|
|
453
|
+
if (typeof value === "symbol") {
|
|
454
|
+
return includeSymbols ? value.toString() : void 0;
|
|
455
|
+
}
|
|
456
|
+
if (typeof value === "bigint") {
|
|
457
|
+
return value.toString() + "n";
|
|
458
|
+
}
|
|
459
|
+
if (seen.has(value)) {
|
|
460
|
+
throw new Error("Circular reference detected");
|
|
461
|
+
}
|
|
462
|
+
seen.add(value);
|
|
463
|
+
if (Array.isArray(value)) {
|
|
464
|
+
const processed2 = value.map((item, index) => processValue(item, String(index))).filter((item) => item !== void 0);
|
|
465
|
+
if (sortArrays) {
|
|
466
|
+
processed2.sort((a, b) => {
|
|
467
|
+
const aStr = JSON.stringify(processValue(a));
|
|
468
|
+
const bStr = JSON.stringify(processValue(b));
|
|
469
|
+
return aStr.localeCompare(bStr);
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
seen.delete(value);
|
|
473
|
+
return processed2;
|
|
474
|
+
}
|
|
475
|
+
if (value.constructor === Object || value.constructor === void 0) {
|
|
476
|
+
const processed2 = {};
|
|
477
|
+
const keys = Object.keys(value).sort();
|
|
478
|
+
for (const k of keys) {
|
|
479
|
+
const processedValue = processValue(value[k], k);
|
|
480
|
+
if (processedValue !== void 0) {
|
|
481
|
+
processed2[k] = processedValue;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
seen.delete(value);
|
|
485
|
+
return processed2;
|
|
486
|
+
}
|
|
487
|
+
try {
|
|
488
|
+
const plain = { ...value };
|
|
489
|
+
seen.delete(value);
|
|
490
|
+
return processValue(plain, key);
|
|
491
|
+
} catch {
|
|
492
|
+
seen.delete(value);
|
|
493
|
+
return String(value);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
const processed = processValue(obj);
|
|
497
|
+
return JSON.stringify(processed);
|
|
498
|
+
}
|
|
499
|
+
function hashObject(obj, options, encoding = "hex") {
|
|
500
|
+
const jsonString = deterministicStringify(obj, options);
|
|
501
|
+
return crypto.createHash("sha256").update(jsonString).digest(encoding);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
exports.createSelfReportState = createSelfReportState;
|
|
505
|
+
exports.hashObject = hashObject;
|
|
506
|
+
exports.isSelfReportFresh = isSelfReportFresh;
|
|
507
|
+
exports.startHappyServer = startHappyServer;
|