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,536 @@
|
|
|
1
|
+
import { l as logger } from './logger-6HYUEXNk.mjs';
|
|
2
|
+
import { spawn as spawn$1, exec } from 'child_process';
|
|
3
|
+
import { promisify } from 'util';
|
|
4
|
+
import { mkdir, writeFile, appendFile, stat, rename, unlink, readdir, readFile } from 'fs/promises';
|
|
5
|
+
import { randomUUID, createHash } from 'crypto';
|
|
6
|
+
import { resolve, join, sep } from 'path';
|
|
7
|
+
import { spawn } from 'cross-spawn';
|
|
8
|
+
import { p as projectPath } from './projectPath-BTBIMB57.mjs';
|
|
9
|
+
import { platform } from 'os';
|
|
10
|
+
import { c as configuration } from './configuration-RfeNjFmd.mjs';
|
|
11
|
+
|
|
12
|
+
function run$1(args, options) {
|
|
13
|
+
const RUNNER_PATH = resolve(join(projectPath(), "scripts", "ripgrep_launcher.cjs"));
|
|
14
|
+
return new Promise((resolve2, reject) => {
|
|
15
|
+
const child = spawn("node", [RUNNER_PATH, JSON.stringify(args)], {
|
|
16
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
17
|
+
cwd: options?.cwd,
|
|
18
|
+
windowsHide: true
|
|
19
|
+
});
|
|
20
|
+
let stdout = "";
|
|
21
|
+
let stderr = "";
|
|
22
|
+
child.stdout.on("data", (data) => {
|
|
23
|
+
stdout += data.toString();
|
|
24
|
+
});
|
|
25
|
+
child.stderr.on("data", (data) => {
|
|
26
|
+
stderr += data.toString();
|
|
27
|
+
});
|
|
28
|
+
child.on("close", (code) => {
|
|
29
|
+
resolve2({
|
|
30
|
+
exitCode: code || 0,
|
|
31
|
+
stdout,
|
|
32
|
+
stderr
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
child.on("error", (err) => {
|
|
36
|
+
reject(err);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function getBinaryPath() {
|
|
42
|
+
const platformName = platform();
|
|
43
|
+
const binaryName = platformName === "win32" ? "difft.exe" : "difft";
|
|
44
|
+
return resolve(join(projectPath(), "tools", "unpacked", binaryName));
|
|
45
|
+
}
|
|
46
|
+
function run(args, options) {
|
|
47
|
+
const binaryPath = getBinaryPath();
|
|
48
|
+
return new Promise((resolve2, reject) => {
|
|
49
|
+
const child = spawn$1(binaryPath, args, {
|
|
50
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
51
|
+
cwd: options?.cwd,
|
|
52
|
+
windowsHide: true,
|
|
53
|
+
env: {
|
|
54
|
+
...process.env,
|
|
55
|
+
// Force color output when needed
|
|
56
|
+
FORCE_COLOR: "1"
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
let stdout = "";
|
|
60
|
+
let stderr = "";
|
|
61
|
+
child.stdout.on("data", (data) => {
|
|
62
|
+
stdout += data.toString();
|
|
63
|
+
});
|
|
64
|
+
child.stderr.on("data", (data) => {
|
|
65
|
+
stderr += data.toString();
|
|
66
|
+
});
|
|
67
|
+
child.on("close", (code) => {
|
|
68
|
+
resolve2({
|
|
69
|
+
exitCode: code || 0,
|
|
70
|
+
stdout,
|
|
71
|
+
stderr
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
child.on("error", (err) => {
|
|
75
|
+
reject(err);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function validatePath(targetPath, workingDirectory) {
|
|
81
|
+
const resolvedTarget = resolve(workingDirectory, targetPath);
|
|
82
|
+
const resolvedWorkingDir = resolve(workingDirectory);
|
|
83
|
+
if (!resolvedTarget.startsWith(resolvedWorkingDir + sep) && resolvedTarget !== resolvedWorkingDir) {
|
|
84
|
+
return {
|
|
85
|
+
valid: false,
|
|
86
|
+
resolvedPath: resolvedTarget,
|
|
87
|
+
error: `Access denied: Path '${targetPath}' is outside the working directory`
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
return { valid: true, resolvedPath: resolvedTarget };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const MAX_USER_UPLOAD_BYTES = 8 * 1024 * 1024;
|
|
94
|
+
const MAX_USER_UPLOAD_CHUNK_BYTES = 96 * 1024;
|
|
95
|
+
const MAX_ACTIVE_UPLOADS = 8;
|
|
96
|
+
const UPLOAD_TTL_MS = 10 * 60 * 1e3;
|
|
97
|
+
function safeSegment(value, fallback, maxLength) {
|
|
98
|
+
const sanitized = (value || fallback).replace(/[^\w.\-]+/g, "_").slice(0, maxLength) || fallback;
|
|
99
|
+
return sanitized === "." || sanitized === ".." ? fallback : sanitized;
|
|
100
|
+
}
|
|
101
|
+
function safeFileName(value) {
|
|
102
|
+
const basename = (value || "file").split(/[/\\]/).pop() || "file";
|
|
103
|
+
return safeSegment(basename, "file", 200);
|
|
104
|
+
}
|
|
105
|
+
function uniqueFileName(name, token) {
|
|
106
|
+
const dot = name.lastIndexOf(".");
|
|
107
|
+
return dot > 0 ? `${name.slice(0, dot)}-${token}${name.slice(dot)}` : `${name}-${token}`;
|
|
108
|
+
}
|
|
109
|
+
function decodeUploadBase64(content, maxBytes) {
|
|
110
|
+
const maxEncodedLength = Math.ceil(maxBytes / 3) * 4;
|
|
111
|
+
if (content.length > maxEncodedLength || content.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(content)) {
|
|
112
|
+
throw new Error("Invalid upload payload");
|
|
113
|
+
}
|
|
114
|
+
const buffer = Buffer.from(content, "base64");
|
|
115
|
+
if (buffer.length > maxBytes || buffer.toString("base64") !== content) {
|
|
116
|
+
throw new Error("Invalid upload payload");
|
|
117
|
+
}
|
|
118
|
+
return buffer;
|
|
119
|
+
}
|
|
120
|
+
function validateUploadId(value) {
|
|
121
|
+
if (!/^[A-Za-z0-9_-]{8,80}$/.test(value)) {
|
|
122
|
+
throw new Error("Invalid upload id");
|
|
123
|
+
}
|
|
124
|
+
return value;
|
|
125
|
+
}
|
|
126
|
+
function defaultPathQuoteStyle() {
|
|
127
|
+
if (process.platform !== "win32") return "posix";
|
|
128
|
+
const shell = (process.env.COMSPEC || "powershell.exe").toLowerCase();
|
|
129
|
+
return shell.includes("powershell") || shell.includes("pwsh") ? "powershell" : "cmd";
|
|
130
|
+
}
|
|
131
|
+
function createUploadFileHandlers(happyHomeDir, now = Date.now, pathQuoteStyle = defaultPathQuoteStyle()) {
|
|
132
|
+
const active = /* @__PURE__ */ new Map();
|
|
133
|
+
let operationQueue = Promise.resolve();
|
|
134
|
+
const serialize = (handler) => (data) => {
|
|
135
|
+
const result = operationQueue.then(() => handler(data), () => handler(data));
|
|
136
|
+
operationQueue = result.then(() => void 0, () => void 0);
|
|
137
|
+
return result;
|
|
138
|
+
};
|
|
139
|
+
const removeActive = async (uploadId) => {
|
|
140
|
+
const upload = active.get(uploadId);
|
|
141
|
+
active.delete(uploadId);
|
|
142
|
+
if (upload) await unlink(upload.tempPath).catch(() => {
|
|
143
|
+
});
|
|
144
|
+
};
|
|
145
|
+
const sweepExpired = async () => {
|
|
146
|
+
const cutoff = now() - UPLOAD_TTL_MS;
|
|
147
|
+
await Promise.all(
|
|
148
|
+
[...active.entries()].filter(([, upload]) => upload.touchedAt < cutoff).map(([uploadId]) => removeActive(uploadId))
|
|
149
|
+
);
|
|
150
|
+
};
|
|
151
|
+
const sweepExpiredFiles = async (dir) => {
|
|
152
|
+
const cutoff = now() - UPLOAD_TTL_MS;
|
|
153
|
+
const entries = await readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
154
|
+
await Promise.all(entries.map(async (entry) => {
|
|
155
|
+
if (!entry.isFile() || !/^\..+\.[A-Za-z0-9_-]{8,80}\.part$/.test(entry.name)) return;
|
|
156
|
+
const path = join(dir, entry.name);
|
|
157
|
+
const fileStat = await stat(path).catch(() => null);
|
|
158
|
+
if (fileStat && fileStat.mtimeMs < cutoff) await unlink(path).catch(() => {
|
|
159
|
+
});
|
|
160
|
+
}));
|
|
161
|
+
};
|
|
162
|
+
const uploadFileUnlocked = async (data) => {
|
|
163
|
+
let tempPath = null;
|
|
164
|
+
try {
|
|
165
|
+
const buffer = decodeUploadBase64(data.content, MAX_USER_UPLOAD_BYTES);
|
|
166
|
+
const dir = join(happyHomeDir, "uploads", safeSegment(data.subdir, "misc", 80));
|
|
167
|
+
await mkdir(dir, { recursive: true });
|
|
168
|
+
const name = safeFileName(data.name);
|
|
169
|
+
const token = randomUUID().replace(/-/g, "").slice(0, 12);
|
|
170
|
+
const target = join(dir, uniqueFileName(name, token));
|
|
171
|
+
tempPath = join(dir, `.${name}.legacy_${randomUUID().replace(/-/g, "")}.part`);
|
|
172
|
+
await writeFile(tempPath, buffer, { flag: "wx" });
|
|
173
|
+
await rename(tempPath, target);
|
|
174
|
+
tempPath = null;
|
|
175
|
+
return { success: true, path: target, pathQuoteStyle, size: buffer.length };
|
|
176
|
+
} catch (error) {
|
|
177
|
+
if (tempPath) await unlink(tempPath).catch(() => {
|
|
178
|
+
});
|
|
179
|
+
return { success: false, error: error instanceof Error ? error.message : "Failed to upload file" };
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
const uploadFileChunkUnlocked = async (data) => {
|
|
183
|
+
try {
|
|
184
|
+
await sweepExpired();
|
|
185
|
+
const uploadId = validateUploadId(data.uploadId);
|
|
186
|
+
if (data.action === "start") {
|
|
187
|
+
if (!Number.isSafeInteger(data.totalSize) || data.totalSize < 0 || data.totalSize > MAX_USER_UPLOAD_BYTES) {
|
|
188
|
+
throw new Error(`File exceeds the ${MAX_USER_UPLOAD_BYTES / 1024 / 1024} MB upload limit`);
|
|
189
|
+
}
|
|
190
|
+
if (active.has(uploadId)) throw new Error("Upload id is already active");
|
|
191
|
+
if (active.size >= MAX_ACTIVE_UPLOADS) throw new Error("Too many active uploads");
|
|
192
|
+
const dir = join(happyHomeDir, "uploads", safeSegment(data.subdir, "misc", 80));
|
|
193
|
+
await mkdir(dir, { recursive: true });
|
|
194
|
+
await sweepExpiredFiles(dir);
|
|
195
|
+
const name = safeFileName(data.name);
|
|
196
|
+
const targetPath = join(dir, uniqueFileName(name, randomUUID().replace(/-/g, "").slice(0, 12)));
|
|
197
|
+
const tempPath = join(dir, `.${name}.${uploadId}.part`);
|
|
198
|
+
await writeFile(tempPath, Buffer.alloc(0), { flag: "wx" });
|
|
199
|
+
active.set(uploadId, { tempPath, targetPath, totalSize: data.totalSize, received: 0, touchedAt: now() });
|
|
200
|
+
return { success: true, size: 0 };
|
|
201
|
+
}
|
|
202
|
+
if (data.action === "abort") {
|
|
203
|
+
const upload2 = active.get(uploadId);
|
|
204
|
+
if (!upload2) return { success: true, size: 0 };
|
|
205
|
+
await removeActive(uploadId);
|
|
206
|
+
return { success: true, size: upload2.received };
|
|
207
|
+
}
|
|
208
|
+
const upload = active.get(uploadId);
|
|
209
|
+
if (!upload) throw new Error("Upload is not active or has expired");
|
|
210
|
+
if (data.action === "append") {
|
|
211
|
+
if (!Number.isSafeInteger(data.offset) || data.offset !== upload.received) {
|
|
212
|
+
throw new Error("Upload chunk is out of order");
|
|
213
|
+
}
|
|
214
|
+
const chunk = decodeUploadBase64(data.content, MAX_USER_UPLOAD_CHUNK_BYTES);
|
|
215
|
+
if (upload.received + chunk.length > upload.totalSize) {
|
|
216
|
+
throw new Error("Upload exceeds declared size");
|
|
217
|
+
}
|
|
218
|
+
await appendFile(upload.tempPath, chunk);
|
|
219
|
+
upload.received += chunk.length;
|
|
220
|
+
upload.touchedAt = now();
|
|
221
|
+
return { success: true, size: upload.received };
|
|
222
|
+
}
|
|
223
|
+
if (data.action !== "finish") throw new Error("Invalid upload action");
|
|
224
|
+
if (upload.received !== upload.totalSize) throw new Error("Upload is incomplete");
|
|
225
|
+
const tempStat = await stat(upload.tempPath);
|
|
226
|
+
if (tempStat.size !== upload.totalSize) throw new Error("Upload size verification failed");
|
|
227
|
+
await rename(upload.tempPath, upload.targetPath);
|
|
228
|
+
active.delete(uploadId);
|
|
229
|
+
return { success: true, path: upload.targetPath, pathQuoteStyle, size: upload.totalSize };
|
|
230
|
+
} catch (error) {
|
|
231
|
+
return { success: false, error: error instanceof Error ? error.message : "Failed to upload file" };
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
return {
|
|
235
|
+
uploadFile: serialize(uploadFileUnlocked),
|
|
236
|
+
uploadFileChunk: serialize(uploadFileChunkUnlocked)
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const execAsync = promisify(exec);
|
|
241
|
+
function registerCommonHandlers(rpcHandlerManager, workingDirectory) {
|
|
242
|
+
rpcHandlerManager.registerHandler("bash", async (data) => {
|
|
243
|
+
logger.debug("Shell command request:", data.command);
|
|
244
|
+
if (data.cwd && data.cwd !== "/") {
|
|
245
|
+
const validation = validatePath(data.cwd, workingDirectory);
|
|
246
|
+
if (!validation.valid) {
|
|
247
|
+
return { success: false, error: validation.error };
|
|
248
|
+
}
|
|
249
|
+
data.cwd = validation.resolvedPath;
|
|
250
|
+
}
|
|
251
|
+
try {
|
|
252
|
+
const options = {
|
|
253
|
+
cwd: data.cwd === "/" ? void 0 : data.cwd,
|
|
254
|
+
timeout: data.timeout || 3e4,
|
|
255
|
+
// Default 30 seconds timeout
|
|
256
|
+
windowsHide: true
|
|
257
|
+
// Prevent cmd.exe popup on Windows for every RPC bash call
|
|
258
|
+
};
|
|
259
|
+
logger.debug("Shell command executing...", { cwd: options.cwd, timeout: options.timeout });
|
|
260
|
+
const { stdout, stderr } = await execAsync(data.command, options);
|
|
261
|
+
logger.debug("Shell command executed, processing result...");
|
|
262
|
+
const result = {
|
|
263
|
+
success: true,
|
|
264
|
+
stdout: stdout ? stdout.toString() : "",
|
|
265
|
+
stderr: stderr ? stderr.toString() : "",
|
|
266
|
+
exitCode: 0
|
|
267
|
+
};
|
|
268
|
+
logger.debug("Shell command result:", {
|
|
269
|
+
success: true,
|
|
270
|
+
exitCode: 0,
|
|
271
|
+
stdoutLen: result.stdout.length,
|
|
272
|
+
stderrLen: result.stderr.length
|
|
273
|
+
});
|
|
274
|
+
return result;
|
|
275
|
+
} catch (error) {
|
|
276
|
+
const execError = error;
|
|
277
|
+
if (execError.code === "ETIMEDOUT" || execError.killed) {
|
|
278
|
+
const result2 = {
|
|
279
|
+
success: false,
|
|
280
|
+
stdout: execError.stdout || "",
|
|
281
|
+
stderr: execError.stderr || "",
|
|
282
|
+
exitCode: typeof execError.code === "number" ? execError.code : -1,
|
|
283
|
+
error: "Command timed out"
|
|
284
|
+
};
|
|
285
|
+
logger.debug("Shell command timed out:", {
|
|
286
|
+
success: false,
|
|
287
|
+
exitCode: result2.exitCode,
|
|
288
|
+
error: "Command timed out"
|
|
289
|
+
});
|
|
290
|
+
return result2;
|
|
291
|
+
}
|
|
292
|
+
const result = {
|
|
293
|
+
success: false,
|
|
294
|
+
stdout: execError.stdout ? execError.stdout.toString() : "",
|
|
295
|
+
stderr: execError.stderr ? execError.stderr.toString() : execError.message || "Command failed",
|
|
296
|
+
exitCode: typeof execError.code === "number" ? execError.code : 1,
|
|
297
|
+
error: execError.message || "Command failed"
|
|
298
|
+
};
|
|
299
|
+
logger.debug("Shell command failed:", {
|
|
300
|
+
success: false,
|
|
301
|
+
exitCode: result.exitCode,
|
|
302
|
+
error: result.error,
|
|
303
|
+
stdoutLen: result.stdout.length,
|
|
304
|
+
stderrLen: result.stderr.length
|
|
305
|
+
});
|
|
306
|
+
return result;
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
rpcHandlerManager.registerHandler("readFile", async (data) => {
|
|
310
|
+
logger.debug("Read file request:", data.path);
|
|
311
|
+
const validation = validatePath(data.path, workingDirectory);
|
|
312
|
+
if (!validation.valid) {
|
|
313
|
+
return { success: false, error: validation.error };
|
|
314
|
+
}
|
|
315
|
+
try {
|
|
316
|
+
const buffer = await readFile(validation.resolvedPath);
|
|
317
|
+
const content = buffer.toString("base64");
|
|
318
|
+
return { success: true, content };
|
|
319
|
+
} catch (error) {
|
|
320
|
+
logger.debug("Failed to read file:", error);
|
|
321
|
+
return { success: false, error: error instanceof Error ? error.message : "Failed to read file" };
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
rpcHandlerManager.registerHandler("writeFile", async (data) => {
|
|
325
|
+
logger.debug("Write file request:", data.path);
|
|
326
|
+
const validation = validatePath(data.path, workingDirectory);
|
|
327
|
+
if (!validation.valid) {
|
|
328
|
+
return { success: false, error: validation.error };
|
|
329
|
+
}
|
|
330
|
+
try {
|
|
331
|
+
if (data.expectedHash !== null && data.expectedHash !== void 0) {
|
|
332
|
+
try {
|
|
333
|
+
const existingBuffer = await readFile(validation.resolvedPath);
|
|
334
|
+
const existingHash = createHash("sha256").update(existingBuffer).digest("hex");
|
|
335
|
+
if (existingHash !== data.expectedHash) {
|
|
336
|
+
return {
|
|
337
|
+
success: false,
|
|
338
|
+
error: `File hash mismatch. Expected: ${data.expectedHash}, Actual: ${existingHash}`
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
} catch (error) {
|
|
342
|
+
const nodeError = error;
|
|
343
|
+
if (nodeError.code !== "ENOENT") {
|
|
344
|
+
throw error;
|
|
345
|
+
}
|
|
346
|
+
return {
|
|
347
|
+
success: false,
|
|
348
|
+
error: "File does not exist but hash was provided"
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
} else {
|
|
352
|
+
try {
|
|
353
|
+
await stat(validation.resolvedPath);
|
|
354
|
+
return {
|
|
355
|
+
success: false,
|
|
356
|
+
error: "File already exists but was expected to be new"
|
|
357
|
+
};
|
|
358
|
+
} catch (error) {
|
|
359
|
+
const nodeError = error;
|
|
360
|
+
if (nodeError.code !== "ENOENT") {
|
|
361
|
+
throw error;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
const buffer = Buffer.from(data.content, "base64");
|
|
366
|
+
await writeFile(validation.resolvedPath, buffer);
|
|
367
|
+
const hash = createHash("sha256").update(buffer).digest("hex");
|
|
368
|
+
return { success: true, hash };
|
|
369
|
+
} catch (error) {
|
|
370
|
+
logger.debug("Failed to write file:", error);
|
|
371
|
+
return { success: false, error: error instanceof Error ? error.message : "Failed to write file" };
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
const uploadHandlers = createUploadFileHandlers(configuration.happyHomeDir);
|
|
375
|
+
rpcHandlerManager.registerHandler("uploadFile", uploadHandlers.uploadFile);
|
|
376
|
+
rpcHandlerManager.registerHandler("uploadFileChunk", uploadHandlers.uploadFileChunk);
|
|
377
|
+
rpcHandlerManager.registerHandler("listDirectory", async (data) => {
|
|
378
|
+
logger.debug("List directory request:", data.path);
|
|
379
|
+
const validation = validatePath(data.path, workingDirectory);
|
|
380
|
+
if (!validation.valid) {
|
|
381
|
+
return { success: false, error: validation.error };
|
|
382
|
+
}
|
|
383
|
+
try {
|
|
384
|
+
const directoryPath = validation.resolvedPath;
|
|
385
|
+
const entries = await readdir(directoryPath, { withFileTypes: true });
|
|
386
|
+
const directoryEntries = await Promise.all(
|
|
387
|
+
entries.map(async (entry) => {
|
|
388
|
+
const fullPath = join(directoryPath, entry.name);
|
|
389
|
+
let type = "other";
|
|
390
|
+
let size;
|
|
391
|
+
let modified;
|
|
392
|
+
if (entry.isDirectory()) {
|
|
393
|
+
type = "directory";
|
|
394
|
+
} else if (entry.isFile()) {
|
|
395
|
+
type = "file";
|
|
396
|
+
}
|
|
397
|
+
try {
|
|
398
|
+
const stats = await stat(fullPath);
|
|
399
|
+
size = stats.size;
|
|
400
|
+
modified = stats.mtime.getTime();
|
|
401
|
+
} catch (error) {
|
|
402
|
+
logger.debug(`Failed to stat ${fullPath}:`, error);
|
|
403
|
+
}
|
|
404
|
+
return {
|
|
405
|
+
name: entry.name,
|
|
406
|
+
type,
|
|
407
|
+
size,
|
|
408
|
+
modified
|
|
409
|
+
};
|
|
410
|
+
})
|
|
411
|
+
);
|
|
412
|
+
directoryEntries.sort((a, b) => {
|
|
413
|
+
if (a.type === "directory" && b.type !== "directory") return -1;
|
|
414
|
+
if (a.type !== "directory" && b.type === "directory") return 1;
|
|
415
|
+
return a.name.localeCompare(b.name);
|
|
416
|
+
});
|
|
417
|
+
return { success: true, entries: directoryEntries };
|
|
418
|
+
} catch (error) {
|
|
419
|
+
logger.debug("Failed to list directory:", error);
|
|
420
|
+
return { success: false, error: error instanceof Error ? error.message : "Failed to list directory" };
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
rpcHandlerManager.registerHandler("getDirectoryTree", async (data) => {
|
|
424
|
+
logger.debug("Get directory tree request:", data.path, "maxDepth:", data.maxDepth);
|
|
425
|
+
const validation = validatePath(data.path, workingDirectory);
|
|
426
|
+
if (!validation.valid) {
|
|
427
|
+
return { success: false, error: validation.error };
|
|
428
|
+
}
|
|
429
|
+
async function buildTree(path, name, currentDepth) {
|
|
430
|
+
try {
|
|
431
|
+
const stats = await stat(path);
|
|
432
|
+
const node = {
|
|
433
|
+
name,
|
|
434
|
+
path,
|
|
435
|
+
type: stats.isDirectory() ? "directory" : "file",
|
|
436
|
+
size: stats.size,
|
|
437
|
+
modified: stats.mtime.getTime()
|
|
438
|
+
};
|
|
439
|
+
if (stats.isDirectory() && currentDepth < data.maxDepth) {
|
|
440
|
+
const entries = await readdir(path, { withFileTypes: true });
|
|
441
|
+
const children = [];
|
|
442
|
+
await Promise.all(
|
|
443
|
+
entries.map(async (entry) => {
|
|
444
|
+
if (entry.isSymbolicLink()) {
|
|
445
|
+
logger.debug(`Skipping symlink: ${join(path, entry.name)}`);
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
const childPath = join(path, entry.name);
|
|
449
|
+
const childNode = await buildTree(childPath, entry.name, currentDepth + 1);
|
|
450
|
+
if (childNode) {
|
|
451
|
+
children.push(childNode);
|
|
452
|
+
}
|
|
453
|
+
})
|
|
454
|
+
);
|
|
455
|
+
children.sort((a, b) => {
|
|
456
|
+
if (a.type === "directory" && b.type !== "directory") return -1;
|
|
457
|
+
if (a.type !== "directory" && b.type === "directory") return 1;
|
|
458
|
+
return a.name.localeCompare(b.name);
|
|
459
|
+
});
|
|
460
|
+
node.children = children;
|
|
461
|
+
}
|
|
462
|
+
return node;
|
|
463
|
+
} catch (error) {
|
|
464
|
+
logger.debug(`Failed to process ${path}:`, error instanceof Error ? error.message : String(error));
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
try {
|
|
469
|
+
if (data.maxDepth < 0) {
|
|
470
|
+
return { success: false, error: "maxDepth must be non-negative" };
|
|
471
|
+
}
|
|
472
|
+
const rootPath = validation.resolvedPath;
|
|
473
|
+
const baseName = rootPath === "/" ? "/" : rootPath.split("/").pop() || rootPath;
|
|
474
|
+
const tree = await buildTree(rootPath, baseName, 0);
|
|
475
|
+
if (!tree) {
|
|
476
|
+
return { success: false, error: "Failed to access the specified path" };
|
|
477
|
+
}
|
|
478
|
+
return { success: true, tree };
|
|
479
|
+
} catch (error) {
|
|
480
|
+
logger.debug("Failed to get directory tree:", error);
|
|
481
|
+
return { success: false, error: error instanceof Error ? error.message : "Failed to get directory tree" };
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
rpcHandlerManager.registerHandler("ripgrep", async (data) => {
|
|
485
|
+
logger.debug("Ripgrep request with args:", data.args, "cwd:", data.cwd);
|
|
486
|
+
if (data.cwd) {
|
|
487
|
+
const validation = validatePath(data.cwd, workingDirectory);
|
|
488
|
+
if (!validation.valid) {
|
|
489
|
+
return { success: false, error: validation.error };
|
|
490
|
+
}
|
|
491
|
+
data.cwd = validation.resolvedPath;
|
|
492
|
+
}
|
|
493
|
+
try {
|
|
494
|
+
const result = await run$1(data.args, { cwd: data.cwd });
|
|
495
|
+
return {
|
|
496
|
+
success: true,
|
|
497
|
+
exitCode: result.exitCode,
|
|
498
|
+
stdout: result.stdout.toString(),
|
|
499
|
+
stderr: result.stderr.toString()
|
|
500
|
+
};
|
|
501
|
+
} catch (error) {
|
|
502
|
+
logger.debug("Failed to run ripgrep:", error);
|
|
503
|
+
return {
|
|
504
|
+
success: false,
|
|
505
|
+
error: error instanceof Error ? error.message : "Failed to run ripgrep"
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
});
|
|
509
|
+
rpcHandlerManager.registerHandler("difftastic", async (data) => {
|
|
510
|
+
logger.debug("Difftastic request with args:", data.args, "cwd:", data.cwd);
|
|
511
|
+
if (data.cwd) {
|
|
512
|
+
const validation = validatePath(data.cwd, workingDirectory);
|
|
513
|
+
if (!validation.valid) {
|
|
514
|
+
return { success: false, error: validation.error };
|
|
515
|
+
}
|
|
516
|
+
data.cwd = validation.resolvedPath;
|
|
517
|
+
}
|
|
518
|
+
try {
|
|
519
|
+
const result = await run(data.args, { cwd: data.cwd });
|
|
520
|
+
return {
|
|
521
|
+
success: true,
|
|
522
|
+
exitCode: result.exitCode,
|
|
523
|
+
stdout: result.stdout.toString(),
|
|
524
|
+
stderr: result.stderr.toString()
|
|
525
|
+
};
|
|
526
|
+
} catch (error) {
|
|
527
|
+
logger.debug("Failed to run difftastic:", error);
|
|
528
|
+
return {
|
|
529
|
+
success: false,
|
|
530
|
+
error: error instanceof Error ? error.message : "Failed to run difftastic"
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
export { registerCommonHandlers as r };
|