svamp-cli 0.1.60 → 0.1.62
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/cli.mjs +19 -19
- package/dist/{commands-9Kb21VH-.mjs → commands-CBTCiCjK.mjs} +1 -1
- package/dist/{commands-BUvYDka4.mjs → commands-DTNg_sCX.mjs} +2 -2
- package/dist/{commands-Dvftls28.mjs → commands-DXia-6W4.mjs} +2 -2
- package/dist/index.mjs +1 -1
- package/dist/{package-ST5rOzw8.mjs → package-BYxU0Wzp.mjs} +1 -1
- package/dist/{run-CWOk5gWn.mjs → run-Bds_JVXp.mjs} +144 -163
- package/dist/{run-DAoPkBhj.mjs → run-Dg1i7D_o.mjs} +1 -1
- package/dist/{tunnel-Dh1bJZ6R.mjs → tunnel-CtPReHFY.mjs} +59 -43
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { b as stopDaemon, s as startDaemon, d as daemonStatus } from './run-
|
|
1
|
+
import { b as stopDaemon, s as startDaemon, d as daemonStatus } from './run-Bds_JVXp.mjs';
|
|
2
2
|
import 'os';
|
|
3
3
|
import 'fs/promises';
|
|
4
4
|
import 'fs';
|
|
@@ -106,10 +106,10 @@ async function main() {
|
|
|
106
106
|
} else if (subcommand === "skills") {
|
|
107
107
|
await handleSkillsCommand();
|
|
108
108
|
} else if (subcommand === "service" || subcommand === "svc") {
|
|
109
|
-
const { handleServiceCommand } = await import('./commands-
|
|
109
|
+
const { handleServiceCommand } = await import('./commands-DXia-6W4.mjs');
|
|
110
110
|
await handleServiceCommand();
|
|
111
111
|
} else if (subcommand === "process" || subcommand === "proc") {
|
|
112
|
-
const { processCommand } = await import('./commands-
|
|
112
|
+
const { processCommand } = await import('./commands-DTNg_sCX.mjs');
|
|
113
113
|
let machineId;
|
|
114
114
|
const processArgs = args.slice(1);
|
|
115
115
|
const mIdx = processArgs.findIndex((a) => a === "--machine" || a === "-m");
|
|
@@ -127,7 +127,7 @@ async function main() {
|
|
|
127
127
|
} else if (!subcommand || subcommand === "start") {
|
|
128
128
|
await handleInteractiveCommand();
|
|
129
129
|
} else if (subcommand === "--version" || subcommand === "-v") {
|
|
130
|
-
const pkg = await import('./package-
|
|
130
|
+
const pkg = await import('./package-BYxU0Wzp.mjs').catch(() => ({ default: { version: "unknown" } }));
|
|
131
131
|
console.log(`svamp version: ${pkg.default.version}`);
|
|
132
132
|
} else {
|
|
133
133
|
console.error(`Unknown command: ${subcommand}`);
|
|
@@ -136,7 +136,7 @@ async function main() {
|
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
138
|
async function handleInteractiveCommand() {
|
|
139
|
-
const { runInteractive } = await import('./run-
|
|
139
|
+
const { runInteractive } = await import('./run-Dg1i7D_o.mjs');
|
|
140
140
|
const interactiveArgs = subcommand === "start" ? args.slice(1) : args;
|
|
141
141
|
let directory = process.cwd();
|
|
142
142
|
let resumeSessionId;
|
|
@@ -181,7 +181,7 @@ async function handleAgentCommand() {
|
|
|
181
181
|
return;
|
|
182
182
|
}
|
|
183
183
|
if (agentArgs[0] === "list") {
|
|
184
|
-
const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-
|
|
184
|
+
const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-Bds_JVXp.mjs').then(function (n) { return n.i; });
|
|
185
185
|
console.log("Known agents:");
|
|
186
186
|
for (const [name, config2] of Object.entries(KNOWN_ACP_AGENTS)) {
|
|
187
187
|
console.log(` ${name.padEnd(12)} ${config2.command} ${config2.args.join(" ")} (ACP)`);
|
|
@@ -193,7 +193,7 @@ async function handleAgentCommand() {
|
|
|
193
193
|
console.log('Use "svamp agent -- <command> [args]" for a custom ACP agent.');
|
|
194
194
|
return;
|
|
195
195
|
}
|
|
196
|
-
const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-
|
|
196
|
+
const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-Bds_JVXp.mjs').then(function (n) { return n.i; });
|
|
197
197
|
let cwd = process.cwd();
|
|
198
198
|
const filteredArgs = [];
|
|
199
199
|
for (let i = 0; i < agentArgs.length; i++) {
|
|
@@ -217,12 +217,12 @@ async function handleAgentCommand() {
|
|
|
217
217
|
console.log(`Starting ${config.agentName} agent in ${cwd}...`);
|
|
218
218
|
let backend;
|
|
219
219
|
if (KNOWN_MCP_AGENTS[config.agentName]) {
|
|
220
|
-
const { CodexMcpBackend } = await import('./run-
|
|
220
|
+
const { CodexMcpBackend } = await import('./run-Bds_JVXp.mjs').then(function (n) { return n.j; });
|
|
221
221
|
backend = new CodexMcpBackend({ cwd, log: logFn });
|
|
222
222
|
} else {
|
|
223
|
-
const { AcpBackend } = await import('./run-
|
|
224
|
-
const { GeminiTransport } = await import('./run-
|
|
225
|
-
const { DefaultTransport } = await import('./run-
|
|
223
|
+
const { AcpBackend } = await import('./run-Bds_JVXp.mjs').then(function (n) { return n.h; });
|
|
224
|
+
const { GeminiTransport } = await import('./run-Bds_JVXp.mjs').then(function (n) { return n.G; });
|
|
225
|
+
const { DefaultTransport } = await import('./run-Bds_JVXp.mjs').then(function (n) { return n.D; });
|
|
226
226
|
const transportHandler = config.agentName === "gemini" ? new GeminiTransport() : new DefaultTransport(config.agentName);
|
|
227
227
|
backend = new AcpBackend({
|
|
228
228
|
agentName: config.agentName,
|
|
@@ -340,7 +340,7 @@ async function handleSessionCommand() {
|
|
|
340
340
|
printSessionHelp();
|
|
341
341
|
return;
|
|
342
342
|
}
|
|
343
|
-
const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionQueueAdd, sessionQueueList, sessionQueueClear } = await import('./commands-
|
|
343
|
+
const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionQueueAdd, sessionQueueList, sessionQueueClear } = await import('./commands-CBTCiCjK.mjs');
|
|
344
344
|
const parseFlagStr = (flag, shortFlag) => {
|
|
345
345
|
for (let i = 1; i < sessionArgs.length; i++) {
|
|
346
346
|
if ((sessionArgs[i] === flag || shortFlag) && i + 1 < sessionArgs.length) {
|
|
@@ -400,7 +400,7 @@ async function handleSessionCommand() {
|
|
|
400
400
|
allowDomain.push(sessionArgs[++i]);
|
|
401
401
|
}
|
|
402
402
|
}
|
|
403
|
-
const { parseShareArg } = await import('./commands-
|
|
403
|
+
const { parseShareArg } = await import('./commands-CBTCiCjK.mjs');
|
|
404
404
|
const shareEntries = share.map((s) => parseShareArg(s));
|
|
405
405
|
await sessionSpawn(agent, dir, targetMachineId, {
|
|
406
406
|
message,
|
|
@@ -484,7 +484,7 @@ async function handleSessionCommand() {
|
|
|
484
484
|
console.error("Usage: svamp session approve <session-id> [request-id] [--json]");
|
|
485
485
|
process.exit(1);
|
|
486
486
|
}
|
|
487
|
-
const { sessionApprove } = await import('./commands-
|
|
487
|
+
const { sessionApprove } = await import('./commands-CBTCiCjK.mjs');
|
|
488
488
|
const approveReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
|
|
489
489
|
await sessionApprove(sessionArgs[1], approveReqId, targetMachineId, {
|
|
490
490
|
json: hasFlag("--json")
|
|
@@ -494,7 +494,7 @@ async function handleSessionCommand() {
|
|
|
494
494
|
console.error("Usage: svamp session deny <session-id> [request-id] [--json]");
|
|
495
495
|
process.exit(1);
|
|
496
496
|
}
|
|
497
|
-
const { sessionDeny } = await import('./commands-
|
|
497
|
+
const { sessionDeny } = await import('./commands-CBTCiCjK.mjs');
|
|
498
498
|
const denyReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
|
|
499
499
|
await sessionDeny(sessionArgs[1], denyReqId, targetMachineId, {
|
|
500
500
|
json: hasFlag("--json")
|
|
@@ -563,7 +563,7 @@ async function handleMachineCommand() {
|
|
|
563
563
|
return;
|
|
564
564
|
}
|
|
565
565
|
if (machineSubcommand === "share") {
|
|
566
|
-
const { machineShare } = await import('./commands-
|
|
566
|
+
const { machineShare } = await import('./commands-CBTCiCjK.mjs');
|
|
567
567
|
let machineId;
|
|
568
568
|
const shareArgs = [];
|
|
569
569
|
for (let i = 1; i < machineArgs.length; i++) {
|
|
@@ -593,7 +593,7 @@ async function handleMachineCommand() {
|
|
|
593
593
|
}
|
|
594
594
|
await machineShare(machineId, { add, remove, list, configPath, showConfig });
|
|
595
595
|
} else if (machineSubcommand === "exec") {
|
|
596
|
-
const { machineExec } = await import('./commands-
|
|
596
|
+
const { machineExec } = await import('./commands-CBTCiCjK.mjs');
|
|
597
597
|
let machineId;
|
|
598
598
|
let cwd;
|
|
599
599
|
const cmdParts = [];
|
|
@@ -613,7 +613,7 @@ async function handleMachineCommand() {
|
|
|
613
613
|
}
|
|
614
614
|
await machineExec(machineId, command, cwd);
|
|
615
615
|
} else if (machineSubcommand === "info") {
|
|
616
|
-
const { machineInfo } = await import('./commands-
|
|
616
|
+
const { machineInfo } = await import('./commands-CBTCiCjK.mjs');
|
|
617
617
|
let machineId;
|
|
618
618
|
for (let i = 1; i < machineArgs.length; i++) {
|
|
619
619
|
if ((machineArgs[i] === "--machine" || machineArgs[i] === "-m") && i + 1 < machineArgs.length) {
|
|
@@ -622,7 +622,7 @@ async function handleMachineCommand() {
|
|
|
622
622
|
}
|
|
623
623
|
await machineInfo(machineId);
|
|
624
624
|
} else if (machineSubcommand === "ls") {
|
|
625
|
-
const { machineLs } = await import('./commands-
|
|
625
|
+
const { machineLs } = await import('./commands-CBTCiCjK.mjs');
|
|
626
626
|
let machineId;
|
|
627
627
|
let showHidden = false;
|
|
628
628
|
let path;
|
|
@@ -2,7 +2,7 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
2
2
|
import { execSync } from 'node:child_process';
|
|
3
3
|
import { resolve, join } from 'node:path';
|
|
4
4
|
import os from 'node:os';
|
|
5
|
-
import { l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha } from './run-
|
|
5
|
+
import { l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha } from './run-Bds_JVXp.mjs';
|
|
6
6
|
import 'os';
|
|
7
7
|
import 'fs/promises';
|
|
8
8
|
import 'fs';
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { writeFileSync, readFileSync } from 'fs';
|
|
2
2
|
import { resolve } from 'path';
|
|
3
|
-
import { connectAndGetMachine } from './commands-
|
|
3
|
+
import { connectAndGetMachine } from './commands-CBTCiCjK.mjs';
|
|
4
4
|
import 'node:fs';
|
|
5
5
|
import 'node:child_process';
|
|
6
6
|
import 'node:path';
|
|
7
7
|
import 'node:os';
|
|
8
|
-
import './run-
|
|
8
|
+
import './run-Bds_JVXp.mjs';
|
|
9
9
|
import 'os';
|
|
10
10
|
import 'fs/promises';
|
|
11
11
|
import 'url';
|
|
@@ -296,7 +296,7 @@ Service is live:`);
|
|
|
296
296
|
}
|
|
297
297
|
} else {
|
|
298
298
|
console.log(`No SANDBOX_ID detected \u2014 starting reverse tunnel.`);
|
|
299
|
-
const { runTunnel } = await import('./tunnel-
|
|
299
|
+
const { runTunnel } = await import('./tunnel-CtPReHFY.mjs');
|
|
300
300
|
await runTunnel(name, ports);
|
|
301
301
|
}
|
|
302
302
|
} catch (err) {
|
|
@@ -312,7 +312,7 @@ async function serviceTunnel(args) {
|
|
|
312
312
|
console.error("Usage: svamp service tunnel <name> --port <port> [--port <port2>]");
|
|
313
313
|
process.exit(1);
|
|
314
314
|
}
|
|
315
|
-
const { runTunnel } = await import('./tunnel-
|
|
315
|
+
const { runTunnel } = await import('./tunnel-CtPReHFY.mjs');
|
|
316
316
|
await runTunnel(name, ports);
|
|
317
317
|
}
|
|
318
318
|
async function handleServiceCommand() {
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { c as connectToHypha, d as daemonStatus, g as getHyphaServerUrl, r as registerMachineService, a as registerSessionService, s as startDaemon, b as stopDaemon } from './run-
|
|
1
|
+
export { c as connectToHypha, d as daemonStatus, g as getHyphaServerUrl, r as registerMachineService, a as registerSessionService, s as startDaemon, b as stopDaemon } from './run-Bds_JVXp.mjs';
|
|
2
2
|
import 'os';
|
|
3
3
|
import 'fs/promises';
|
|
4
4
|
import 'fs';
|
|
@@ -313,35 +313,9 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
313
313
|
let currentDaemonState = { ...daemonState };
|
|
314
314
|
let metadataVersion = 1;
|
|
315
315
|
let daemonStateVersion = 1;
|
|
316
|
-
const
|
|
317
|
-
const
|
|
318
|
-
const
|
|
319
|
-
if (idx >= 0) {
|
|
320
|
-
listeners.splice(idx, 1);
|
|
321
|
-
console.log(`[HYPHA MACHINE] Listener removed (${reason}), remaining: ${listeners.length}`);
|
|
322
|
-
const rintfId = listener._rintf_service_id;
|
|
323
|
-
if (rintfId) {
|
|
324
|
-
server.unregisterService(rintfId).catch(() => {
|
|
325
|
-
});
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
};
|
|
329
|
-
const notifyListeners = (update) => {
|
|
330
|
-
for (let i = listeners.length - 1; i >= 0; i--) {
|
|
331
|
-
try {
|
|
332
|
-
const result = listeners[i].onUpdate(update);
|
|
333
|
-
if (result && typeof result.catch === "function") {
|
|
334
|
-
const listener = listeners[i];
|
|
335
|
-
result.catch((err) => {
|
|
336
|
-
console.error(`[HYPHA MACHINE] Async listener error:`, err);
|
|
337
|
-
removeListener(listener, "async error");
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
} catch (err) {
|
|
341
|
-
console.error(`[HYPHA MACHINE] Listener error:`, err);
|
|
342
|
-
removeListener(listeners[i], "sync error");
|
|
343
|
-
}
|
|
344
|
-
}
|
|
316
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
317
|
+
const notifySubscribers = (update) => {
|
|
318
|
+
for (const push of subscribers) push(update);
|
|
345
319
|
};
|
|
346
320
|
const serviceInfo = await server.registerService(
|
|
347
321
|
{
|
|
@@ -427,7 +401,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
427
401
|
machineId
|
|
428
402
|
});
|
|
429
403
|
if (result.type === "success" && result.sessionId) {
|
|
430
|
-
|
|
404
|
+
notifySubscribers({
|
|
431
405
|
type: "new-session",
|
|
432
406
|
sessionId: result.sessionId,
|
|
433
407
|
machineId
|
|
@@ -440,7 +414,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
440
414
|
stopSession: async (sessionId, context) => {
|
|
441
415
|
authorizeRequest(context, currentMetadata.sharing, "admin");
|
|
442
416
|
const result = handlers.stopSession(sessionId);
|
|
443
|
-
|
|
417
|
+
notifySubscribers({
|
|
444
418
|
type: "session-stopped",
|
|
445
419
|
sessionId,
|
|
446
420
|
machineId
|
|
@@ -481,7 +455,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
481
455
|
sharing: currentMetadata.sharing,
|
|
482
456
|
securityContextConfig: currentMetadata.securityContextConfig
|
|
483
457
|
});
|
|
484
|
-
|
|
458
|
+
notifySubscribers({
|
|
485
459
|
type: "update-machine",
|
|
486
460
|
machineId,
|
|
487
461
|
metadata: { value: currentMetadata, version: metadataVersion }
|
|
@@ -511,7 +485,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
511
485
|
}
|
|
512
486
|
currentDaemonState = newState;
|
|
513
487
|
daemonStateVersion++;
|
|
514
|
-
|
|
488
|
+
notifySubscribers({
|
|
515
489
|
type: "update-machine",
|
|
516
490
|
machineId,
|
|
517
491
|
daemonState: { value: currentDaemonState, version: daemonStateVersion }
|
|
@@ -541,7 +515,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
541
515
|
sharing: currentMetadata.sharing,
|
|
542
516
|
securityContextConfig: currentMetadata.securityContextConfig
|
|
543
517
|
});
|
|
544
|
-
|
|
518
|
+
notifySubscribers({
|
|
545
519
|
type: "update-machine",
|
|
546
520
|
machineId,
|
|
547
521
|
metadata: { value: currentMetadata, version: metadataVersion }
|
|
@@ -562,19 +536,48 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
562
536
|
sharing: currentMetadata.sharing,
|
|
563
537
|
securityContextConfig: currentMetadata.securityContextConfig
|
|
564
538
|
});
|
|
565
|
-
|
|
539
|
+
notifySubscribers({
|
|
566
540
|
type: "update-machine",
|
|
567
541
|
machineId,
|
|
568
542
|
metadata: { value: currentMetadata, version: metadataVersion }
|
|
569
543
|
});
|
|
570
544
|
return { success: true };
|
|
571
545
|
},
|
|
572
|
-
//
|
|
573
|
-
|
|
546
|
+
// Live update stream — yields machine state changes as they happen.
|
|
547
|
+
// Frontend iterates with `for await (const update of machine.subscribe())`.
|
|
548
|
+
subscribe: async function* (context) {
|
|
574
549
|
authorizeRequest(context, currentMetadata.sharing, "view");
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
550
|
+
const pending = [];
|
|
551
|
+
let wake = null;
|
|
552
|
+
const push = (update) => {
|
|
553
|
+
pending.push(update);
|
|
554
|
+
wake?.();
|
|
555
|
+
};
|
|
556
|
+
subscribers.add(push);
|
|
557
|
+
console.log(`[HYPHA MACHINE] subscribe() started (total: ${subscribers.size})`);
|
|
558
|
+
try {
|
|
559
|
+
yield {
|
|
560
|
+
type: "update-machine",
|
|
561
|
+
machineId,
|
|
562
|
+
metadata: { value: currentMetadata, version: metadataVersion },
|
|
563
|
+
daemonState: { value: currentDaemonState, version: daemonStateVersion }
|
|
564
|
+
};
|
|
565
|
+
while (true) {
|
|
566
|
+
while (pending.length === 0) {
|
|
567
|
+
await new Promise((r) => {
|
|
568
|
+
wake = r;
|
|
569
|
+
});
|
|
570
|
+
wake = null;
|
|
571
|
+
}
|
|
572
|
+
while (pending.length > 0) {
|
|
573
|
+
yield pending.shift();
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
} finally {
|
|
577
|
+
subscribers.delete(push);
|
|
578
|
+
wake?.();
|
|
579
|
+
console.log(`[HYPHA MACHINE] subscribe() ended (remaining: ${subscribers.size})`);
|
|
580
|
+
}
|
|
578
581
|
},
|
|
579
582
|
// Shell access
|
|
580
583
|
bash: async (command, cwd, context) => {
|
|
@@ -761,7 +764,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
761
764
|
updateMetadata: (newMetadata) => {
|
|
762
765
|
currentMetadata = newMetadata;
|
|
763
766
|
metadataVersion++;
|
|
764
|
-
|
|
767
|
+
notifySubscribers({
|
|
765
768
|
type: "update-machine",
|
|
766
769
|
machineId,
|
|
767
770
|
metadata: { value: currentMetadata, version: metadataVersion }
|
|
@@ -770,7 +773,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
770
773
|
updateDaemonState: (newState) => {
|
|
771
774
|
currentDaemonState = newState;
|
|
772
775
|
daemonStateVersion++;
|
|
773
|
-
|
|
776
|
+
notifySubscribers({
|
|
774
777
|
type: "update-machine",
|
|
775
778
|
machineId,
|
|
776
779
|
daemonState: { value: currentDaemonState, version: daemonStateVersion }
|
|
@@ -819,35 +822,9 @@ async function registerSessionService(server, sessionId, initialMetadata, initia
|
|
|
819
822
|
mode: "remote",
|
|
820
823
|
time: Date.now()
|
|
821
824
|
};
|
|
822
|
-
const
|
|
823
|
-
const
|
|
824
|
-
const
|
|
825
|
-
if (idx >= 0) {
|
|
826
|
-
listeners.splice(idx, 1);
|
|
827
|
-
console.log(`[HYPHA SESSION ${sessionId}] Listener removed (${reason}), remaining: ${listeners.length}`);
|
|
828
|
-
const rintfId = listener._rintf_service_id;
|
|
829
|
-
if (rintfId) {
|
|
830
|
-
server.unregisterService(rintfId).catch(() => {
|
|
831
|
-
});
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
};
|
|
835
|
-
const notifyListeners = (update) => {
|
|
836
|
-
for (let i = listeners.length - 1; i >= 0; i--) {
|
|
837
|
-
try {
|
|
838
|
-
const result = listeners[i].onUpdate(update);
|
|
839
|
-
if (result && typeof result.catch === "function") {
|
|
840
|
-
const listener = listeners[i];
|
|
841
|
-
result.catch((err) => {
|
|
842
|
-
console.error(`[HYPHA SESSION ${sessionId}] Async listener error:`, err);
|
|
843
|
-
removeListener(listener, "async error");
|
|
844
|
-
});
|
|
845
|
-
}
|
|
846
|
-
} catch (err) {
|
|
847
|
-
console.error(`[HYPHA SESSION ${sessionId}] Listener error:`, err);
|
|
848
|
-
removeListener(listeners[i], "sync error");
|
|
849
|
-
}
|
|
850
|
-
}
|
|
825
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
826
|
+
const notifySubscribers = (update) => {
|
|
827
|
+
for (const push of subscribers) push(update);
|
|
851
828
|
};
|
|
852
829
|
const pushMessage = (content, role = "agent") => {
|
|
853
830
|
let wrappedContent;
|
|
@@ -878,7 +855,7 @@ async function registerSessionService(server, sessionId, initialMetadata, initia
|
|
|
878
855
|
if (options?.messagesDir) {
|
|
879
856
|
appendMessage(options.messagesDir, sessionId, msg);
|
|
880
857
|
}
|
|
881
|
-
|
|
858
|
+
notifySubscribers({
|
|
882
859
|
type: "new-message",
|
|
883
860
|
sessionId,
|
|
884
861
|
message: msg
|
|
@@ -939,7 +916,7 @@ async function registerSessionService(server, sessionId, initialMetadata, initia
|
|
|
939
916
|
if (options?.messagesDir) {
|
|
940
917
|
appendMessage(options.messagesDir, sessionId, msg);
|
|
941
918
|
}
|
|
942
|
-
|
|
919
|
+
notifySubscribers({
|
|
943
920
|
type: "new-message",
|
|
944
921
|
sessionId,
|
|
945
922
|
message: msg
|
|
@@ -966,7 +943,7 @@ async function registerSessionService(server, sessionId, initialMetadata, initia
|
|
|
966
943
|
}
|
|
967
944
|
metadata = newMetadata;
|
|
968
945
|
metadataVersion++;
|
|
969
|
-
|
|
946
|
+
notifySubscribers({
|
|
970
947
|
type: "update-session",
|
|
971
948
|
sessionId,
|
|
972
949
|
metadata: { value: metadata, version: metadataVersion }
|
|
@@ -1007,7 +984,7 @@ async function registerSessionService(server, sessionId, initialMetadata, initia
|
|
|
1007
984
|
}
|
|
1008
985
|
agentState = newState;
|
|
1009
986
|
agentStateVersion++;
|
|
1010
|
-
|
|
987
|
+
notifySubscribers({
|
|
1011
988
|
type: "update-session",
|
|
1012
989
|
sessionId,
|
|
1013
990
|
agentState: { value: agentState, version: agentStateVersion }
|
|
@@ -1046,7 +1023,7 @@ async function registerSessionService(server, sessionId, initialMetadata, initia
|
|
|
1046
1023
|
// ── Activity ──
|
|
1047
1024
|
keepAlive: async (thinking, mode, context) => {
|
|
1048
1025
|
lastActivity = { active: true, thinking: thinking || false, mode: mode || "remote", time: Date.now() };
|
|
1049
|
-
|
|
1026
|
+
notifySubscribers({
|
|
1050
1027
|
type: "activity",
|
|
1051
1028
|
sessionId,
|
|
1052
1029
|
...lastActivity
|
|
@@ -1054,7 +1031,7 @@ async function registerSessionService(server, sessionId, initialMetadata, initia
|
|
|
1054
1031
|
},
|
|
1055
1032
|
sessionEnd: async (context) => {
|
|
1056
1033
|
lastActivity = { active: false, thinking: false, mode: "remote", time: Date.now() };
|
|
1057
|
-
|
|
1034
|
+
notifySubscribers({
|
|
1058
1035
|
type: "activity",
|
|
1059
1036
|
sessionId,
|
|
1060
1037
|
...lastActivity
|
|
@@ -1128,7 +1105,7 @@ async function registerSessionService(server, sessionId, initialMetadata, initia
|
|
|
1128
1105
|
}
|
|
1129
1106
|
metadata = { ...metadata, sharing: newSharing };
|
|
1130
1107
|
metadataVersion++;
|
|
1131
|
-
|
|
1108
|
+
notifySubscribers({
|
|
1132
1109
|
type: "update-session",
|
|
1133
1110
|
sessionId,
|
|
1134
1111
|
metadata: { value: metadata, version: metadataVersion }
|
|
@@ -1146,7 +1123,7 @@ async function registerSessionService(server, sessionId, initialMetadata, initia
|
|
|
1146
1123
|
}
|
|
1147
1124
|
metadata = { ...metadata, securityContext: newSecurityContext };
|
|
1148
1125
|
metadataVersion++;
|
|
1149
|
-
|
|
1126
|
+
notifySubscribers({
|
|
1150
1127
|
type: "update-session",
|
|
1151
1128
|
sessionId,
|
|
1152
1129
|
metadata: { value: metadata, version: metadataVersion }
|
|
@@ -1161,64 +1138,55 @@ async function registerSessionService(server, sessionId, initialMetadata, initia
|
|
|
1161
1138
|
}
|
|
1162
1139
|
return await callbacks.onApplySystemPrompt(prompt);
|
|
1163
1140
|
},
|
|
1164
|
-
// ──
|
|
1165
|
-
|
|
1141
|
+
// ── Live Update Stream ──
|
|
1142
|
+
//
|
|
1143
|
+
// Returns an async generator that yields real-time updates for this session.
|
|
1144
|
+
// hypha-rpc proxies the generator across the RPC boundary — the frontend
|
|
1145
|
+
// iterates with `for await (const update of service.subscribe())`.
|
|
1146
|
+
//
|
|
1147
|
+
// Initial state is replayed as the first batch of yields so the frontend
|
|
1148
|
+
// can reconstruct full session state without a separate RPC call.
|
|
1149
|
+
// Cleanup is automatic: when the frontend disconnects, hypha-rpc calls the
|
|
1150
|
+
// generator's close method, triggering the finally block which removes the
|
|
1151
|
+
// subscriber. No reverse `_rintf` service is registered.
|
|
1152
|
+
subscribe: async function* (context) {
|
|
1166
1153
|
authorizeRequest(context, metadata.sharing, "view");
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
sessionId,
|
|
1176
|
-
message: msg
|
|
1177
|
-
});
|
|
1178
|
-
if (result && typeof result.catch === "function") {
|
|
1179
|
-
try {
|
|
1180
|
-
await result;
|
|
1181
|
-
} catch (err) {
|
|
1182
|
-
console.error(`[HYPHA SESSION ${sessionId}] Replay listener error, removing:`, err?.message ?? err);
|
|
1183
|
-
removeListener(callback, "replay error");
|
|
1184
|
-
return { success: false, error: "Listener removed during replay" };
|
|
1185
|
-
}
|
|
1186
|
-
}
|
|
1187
|
-
} catch (err) {
|
|
1188
|
-
console.error(`[HYPHA SESSION ${sessionId}] Replay listener error, removing:`, err?.message ?? err);
|
|
1189
|
-
removeListener(callback, "replay error");
|
|
1190
|
-
return { success: false, error: "Listener removed during replay" };
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
if (listeners.indexOf(callback) < 0) {
|
|
1194
|
-
return { success: false, error: "Listener was removed during replay" };
|
|
1195
|
-
}
|
|
1154
|
+
const pending = [];
|
|
1155
|
+
let wake = null;
|
|
1156
|
+
const push = (update) => {
|
|
1157
|
+
pending.push(update);
|
|
1158
|
+
wake?.();
|
|
1159
|
+
};
|
|
1160
|
+
subscribers.add(push);
|
|
1161
|
+
console.log(`[HYPHA SESSION ${sessionId}] subscribe() started (total: ${subscribers.size})`);
|
|
1196
1162
|
try {
|
|
1197
|
-
|
|
1163
|
+
yield {
|
|
1198
1164
|
type: "update-session",
|
|
1199
1165
|
sessionId,
|
|
1200
1166
|
metadata: { value: metadata, version: metadataVersion },
|
|
1201
1167
|
agentState: { value: agentState, version: agentStateVersion }
|
|
1202
|
-
}
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
}
|
|
1168
|
+
};
|
|
1169
|
+
const MAX_REPLAY = 50;
|
|
1170
|
+
for (const msg of messages.slice(-MAX_REPLAY)) {
|
|
1171
|
+
yield { type: "new-message", sessionId, message: msg };
|
|
1206
1172
|
}
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
}
|
|
1173
|
+
yield { type: "activity", sessionId, ...lastActivity };
|
|
1174
|
+
while (true) {
|
|
1175
|
+
while (pending.length === 0) {
|
|
1176
|
+
await new Promise((r) => {
|
|
1177
|
+
wake = r;
|
|
1178
|
+
});
|
|
1179
|
+
wake = null;
|
|
1180
|
+
}
|
|
1181
|
+
while (pending.length > 0) {
|
|
1182
|
+
yield pending.shift();
|
|
1183
|
+
}
|
|
1218
1184
|
}
|
|
1219
|
-
}
|
|
1185
|
+
} finally {
|
|
1186
|
+
subscribers.delete(push);
|
|
1187
|
+
wake?.();
|
|
1188
|
+
console.log(`[HYPHA SESSION ${sessionId}] subscribe() ended (remaining: ${subscribers.size})`);
|
|
1220
1189
|
}
|
|
1221
|
-
return { success: true, listenerId: listeners.length - 1 };
|
|
1222
1190
|
}
|
|
1223
1191
|
},
|
|
1224
1192
|
{ overwrite: true }
|
|
@@ -1233,7 +1201,7 @@ async function registerSessionService(server, sessionId, initialMetadata, initia
|
|
|
1233
1201
|
updateMetadata: (newMetadata) => {
|
|
1234
1202
|
metadata = newMetadata;
|
|
1235
1203
|
metadataVersion++;
|
|
1236
|
-
|
|
1204
|
+
notifySubscribers({
|
|
1237
1205
|
type: "update-session",
|
|
1238
1206
|
sessionId,
|
|
1239
1207
|
metadata: { value: metadata, version: metadataVersion }
|
|
@@ -1242,7 +1210,7 @@ async function registerSessionService(server, sessionId, initialMetadata, initia
|
|
|
1242
1210
|
updateAgentState: (newAgentState) => {
|
|
1243
1211
|
agentState = newAgentState;
|
|
1244
1212
|
agentStateVersion++;
|
|
1245
|
-
|
|
1213
|
+
notifySubscribers({
|
|
1246
1214
|
type: "update-session",
|
|
1247
1215
|
sessionId,
|
|
1248
1216
|
agentState: { value: agentState, version: agentStateVersion }
|
|
@@ -1250,7 +1218,7 @@ async function registerSessionService(server, sessionId, initialMetadata, initia
|
|
|
1250
1218
|
},
|
|
1251
1219
|
sendKeepAlive: (thinking, mode) => {
|
|
1252
1220
|
lastActivity = { active: true, thinking: thinking || false, mode: mode || "remote", time: Date.now() };
|
|
1253
|
-
|
|
1221
|
+
notifySubscribers({
|
|
1254
1222
|
type: "activity",
|
|
1255
1223
|
sessionId,
|
|
1256
1224
|
...lastActivity
|
|
@@ -1258,7 +1226,7 @@ async function registerSessionService(server, sessionId, initialMetadata, initia
|
|
|
1258
1226
|
},
|
|
1259
1227
|
sendSessionEnd: () => {
|
|
1260
1228
|
lastActivity = { active: false, thinking: false, mode: "remote", time: Date.now() };
|
|
1261
|
-
|
|
1229
|
+
notifySubscribers({
|
|
1262
1230
|
type: "activity",
|
|
1263
1231
|
sessionId,
|
|
1264
1232
|
...lastActivity
|
|
@@ -1274,7 +1242,7 @@ async function registerSessionService(server, sessionId, initialMetadata, initia
|
|
|
1274
1242
|
} catch {
|
|
1275
1243
|
}
|
|
1276
1244
|
}
|
|
1277
|
-
|
|
1245
|
+
notifySubscribers({
|
|
1278
1246
|
type: "clear-messages",
|
|
1279
1247
|
sessionId
|
|
1280
1248
|
});
|
|
@@ -4985,20 +4953,7 @@ async function startDaemon(options) {
|
|
|
4985
4953
|
logger.log(`Hypha connection permanently lost: ${reason}`);
|
|
4986
4954
|
requestShutdown("hypha-disconnected", String(reason));
|
|
4987
4955
|
});
|
|
4988
|
-
let lastHyphaMessageAt = Date.now();
|
|
4989
|
-
const attachMessageTimestampListener = () => {
|
|
4990
|
-
const conn = server.rpc?._connection;
|
|
4991
|
-
const ws = conn?._websocket;
|
|
4992
|
-
if (ws) {
|
|
4993
|
-
ws.addEventListener("message", () => {
|
|
4994
|
-
lastHyphaMessageAt = Date.now();
|
|
4995
|
-
});
|
|
4996
|
-
lastHyphaMessageAt = Date.now();
|
|
4997
|
-
}
|
|
4998
|
-
};
|
|
4999
|
-
attachMessageTimestampListener();
|
|
5000
4956
|
server.on("services_registered", () => {
|
|
5001
|
-
attachMessageTimestampListener();
|
|
5002
4957
|
if (consecutiveHeartbeatFailures > 0) {
|
|
5003
4958
|
logger.log(`Hypha reconnection successful \u2014 services re-registered (resetting ${consecutiveHeartbeatFailures} failures)`);
|
|
5004
4959
|
consecutiveHeartbeatFailures = 0;
|
|
@@ -6747,7 +6702,7 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6747
6702
|
console.log(` Service: svamp-machine-${machineId}`);
|
|
6748
6703
|
console.log(` Log file: ${logger.logFilePath}`);
|
|
6749
6704
|
const HEARTBEAT_INTERVAL_MS = 1e4;
|
|
6750
|
-
const
|
|
6705
|
+
const PING_TIMEOUT_MS = 15e3;
|
|
6751
6706
|
const MAX_FAILURES = 60;
|
|
6752
6707
|
const POST_RECONNECT_GRACE_MS = 2e4;
|
|
6753
6708
|
let heartbeatRunning = false;
|
|
@@ -6778,32 +6733,58 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6778
6733
|
}
|
|
6779
6734
|
} catch {
|
|
6780
6735
|
}
|
|
6736
|
+
for (const [key, session] of pidToTrackedSession) {
|
|
6737
|
+
const child = session.childProcess;
|
|
6738
|
+
if (child && child.pid) {
|
|
6739
|
+
try {
|
|
6740
|
+
process.kill(child.pid, 0);
|
|
6741
|
+
} catch {
|
|
6742
|
+
logger.log(`Removing stale session (child PID ${child.pid} dead): ${session.svampSessionId}`);
|
|
6743
|
+
session.hyphaService?.disconnect().catch(() => {
|
|
6744
|
+
});
|
|
6745
|
+
pidToTrackedSession.delete(key);
|
|
6746
|
+
}
|
|
6747
|
+
}
|
|
6748
|
+
}
|
|
6781
6749
|
const inGrace = lastReconnectAt > 0 && Date.now() - lastReconnectAt < POST_RECONNECT_GRACE_MS;
|
|
6782
|
-
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
|
|
6786
|
-
|
|
6750
|
+
if (!inGrace) {
|
|
6751
|
+
try {
|
|
6752
|
+
const pingStart = Date.now();
|
|
6753
|
+
await Promise.race([
|
|
6754
|
+
server.echo("ping"),
|
|
6755
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("Ping timed out")), PING_TIMEOUT_MS))
|
|
6756
|
+
]);
|
|
6757
|
+
const pingMs = Date.now() - pingStart;
|
|
6758
|
+
if (pingMs > 5e3) {
|
|
6759
|
+
logger.log(`Slow ping: ${pingMs}ms (server under load)`);
|
|
6760
|
+
}
|
|
6761
|
+
if (consecutiveHeartbeatFailures > 0) {
|
|
6762
|
+
logger.log(`Heartbeat recovered after ${consecutiveHeartbeatFailures} failures`);
|
|
6763
|
+
consecutiveHeartbeatFailures = 0;
|
|
6764
|
+
}
|
|
6765
|
+
} catch (err) {
|
|
6787
6766
|
consecutiveHeartbeatFailures++;
|
|
6788
6767
|
if (consecutiveHeartbeatFailures === 1) {
|
|
6789
|
-
logger.log(`
|
|
6768
|
+
logger.log(`Ping failed: ${err.message}`);
|
|
6790
6769
|
} else if (consecutiveHeartbeatFailures % 6 === 0) {
|
|
6791
|
-
logger.log(`
|
|
6770
|
+
logger.log(`Connection down for ${consecutiveHeartbeatFailures * HEARTBEAT_INTERVAL_MS / 1e3}s (${consecutiveHeartbeatFailures}/${MAX_FAILURES})`);
|
|
6792
6771
|
}
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
|
|
6772
|
+
if (consecutiveHeartbeatFailures === 1 || consecutiveHeartbeatFailures % 3 === 0) {
|
|
6773
|
+
const conn = server.rpc?._connection;
|
|
6774
|
+
const ws = conn?._websocket;
|
|
6775
|
+
if (ws?.readyState === 1) {
|
|
6776
|
+
logger.log("Force-closing stale WebSocket to trigger reconnection");
|
|
6777
|
+
try {
|
|
6778
|
+
ws.close(4e3, "Stale connection");
|
|
6779
|
+
} catch {
|
|
6780
|
+
}
|
|
6781
|
+
}
|
|
6796
6782
|
}
|
|
6797
6783
|
if (consecutiveHeartbeatFailures >= MAX_FAILURES) {
|
|
6798
6784
|
logger.log(`Heartbeat failed ${MAX_FAILURES} times. Shutting down.`);
|
|
6799
|
-
requestShutdown("heartbeat-timeout",
|
|
6785
|
+
requestShutdown("heartbeat-timeout", err.message);
|
|
6800
6786
|
}
|
|
6801
|
-
} else {
|
|
6802
|
-
lastHyphaMessageAt = Date.now();
|
|
6803
6787
|
}
|
|
6804
|
-
} else if (consecutiveHeartbeatFailures > 0 && timeSinceMsg < GHOST_TIMEOUT_MS / 2) {
|
|
6805
|
-
logger.log(`Heartbeat recovered after ${consecutiveHeartbeatFailures} failures`);
|
|
6806
|
-
consecutiveHeartbeatFailures = 0;
|
|
6807
6788
|
}
|
|
6808
6789
|
} finally {
|
|
6809
6790
|
heartbeatRunning = false;
|
|
@@ -2,7 +2,7 @@ import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(im
|
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import { join, resolve } from 'node:path';
|
|
4
4
|
import { mkdirSync, writeFileSync, existsSync, unlinkSync, readFileSync, watch } from 'node:fs';
|
|
5
|
-
import { c as connectToHypha, a as registerSessionService } from './run-
|
|
5
|
+
import { c as connectToHypha, a as registerSessionService } from './run-Bds_JVXp.mjs';
|
|
6
6
|
import { createServer } from 'node:http';
|
|
7
7
|
import { spawn } from 'node:child_process';
|
|
8
8
|
import { createInterface } from 'node:readline';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as os from 'os';
|
|
2
|
+
import * as http from 'http';
|
|
2
3
|
import { requireSandboxApiEnv } from './api-Cegey1dh.mjs';
|
|
3
4
|
import { WebSocket } from 'ws';
|
|
4
5
|
|
|
@@ -123,56 +124,71 @@ class TunnelClient {
|
|
|
123
124
|
async proxyRequest(req) {
|
|
124
125
|
this.requestCount++;
|
|
125
126
|
const port = req.port || this.options.ports[0];
|
|
126
|
-
const url = `http://${this.options.localHost}:${port}${req.path}`;
|
|
127
|
-
const controller = new AbortController();
|
|
128
|
-
const timeout = setTimeout(() => controller.abort(), this.options.requestTimeout);
|
|
129
127
|
const forwardHeaders = { ...req.headers };
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
128
|
+
const chunks = [];
|
|
129
|
+
const status_holder = { status: 502, headers: {} };
|
|
130
|
+
await new Promise((resolve, reject) => {
|
|
131
|
+
const timeout = setTimeout(() => reject(new Error("timeout")), this.options.requestTimeout);
|
|
132
|
+
const options = {
|
|
133
|
+
hostname: this.options.localHost,
|
|
134
|
+
port,
|
|
135
|
+
path: req.path,
|
|
136
|
+
method: req.method,
|
|
137
|
+
headers: forwardHeaders
|
|
138
|
+
};
|
|
139
|
+
const httpReq = http.request(options, (res) => {
|
|
140
|
+
status_holder.status = res.statusCode ?? 502;
|
|
141
|
+
const rawHeaders = res.headers;
|
|
142
|
+
for (const [key, value] of Object.entries(rawHeaders)) {
|
|
143
|
+
if (Array.isArray(value)) {
|
|
144
|
+
status_holder.headers[key] = value.join(", ");
|
|
145
|
+
} else if (value !== void 0) {
|
|
146
|
+
status_holder.headers[key] = value;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
150
|
+
res.on("end", () => {
|
|
151
|
+
clearTimeout(timeout);
|
|
152
|
+
resolve();
|
|
153
|
+
});
|
|
154
|
+
res.on("error", (e) => {
|
|
155
|
+
clearTimeout(timeout);
|
|
156
|
+
reject(e);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
httpReq.on("error", (e) => {
|
|
160
|
+
clearTimeout(timeout);
|
|
161
|
+
reject(e);
|
|
148
162
|
});
|
|
163
|
+
if (req.body && !["GET", "HEAD"].includes(req.method.toUpperCase())) {
|
|
164
|
+
httpReq.write(Buffer.from(req.body, "base64"));
|
|
165
|
+
}
|
|
166
|
+
httpReq.end();
|
|
167
|
+
}).then(() => {
|
|
168
|
+
const bodyBuffer = Buffer.concat(chunks);
|
|
169
|
+
const bodyBase64 = bodyBuffer.length > 0 ? bodyBuffer.toString("base64") : void 0;
|
|
170
|
+
for (const h of ["connection", "keep-alive", "transfer-encoding"]) {
|
|
171
|
+
delete status_holder.headers[h];
|
|
172
|
+
}
|
|
149
173
|
this.send({
|
|
150
174
|
type: "response",
|
|
151
175
|
id: req.id,
|
|
152
|
-
status:
|
|
153
|
-
headers,
|
|
176
|
+
status: status_holder.status,
|
|
177
|
+
headers: status_holder.headers,
|
|
154
178
|
body: bodyBase64
|
|
155
179
|
});
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
type: "response",
|
|
169
|
-
id: req.id,
|
|
170
|
-
status: 502,
|
|
171
|
-
headers: { "content-type": "text/plain" },
|
|
172
|
-
body: Buffer.from(`Tunnel: local service error: ${err.message}`).toString("base64")
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
}
|
|
180
|
+
}).catch((err) => {
|
|
181
|
+
const isTimeout = err.message === "timeout";
|
|
182
|
+
this.send({
|
|
183
|
+
type: "response",
|
|
184
|
+
id: req.id,
|
|
185
|
+
status: isTimeout ? 504 : 502,
|
|
186
|
+
headers: { "content-type": "text/plain" },
|
|
187
|
+
body: Buffer.from(
|
|
188
|
+
isTimeout ? "Tunnel: request timeout" : `Tunnel: local service error: ${err.message}`
|
|
189
|
+
).toString("base64")
|
|
190
|
+
});
|
|
191
|
+
});
|
|
176
192
|
}
|
|
177
193
|
// ── WebSocket proxying ───────────────────────────────────────────────
|
|
178
194
|
async handleWsOpen(msg) {
|