svamp-cli 0.2.257 → 0.2.259
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/{agentCommands-fCsOp7ko.mjs → agentCommands-w72BRYhk.mjs} +6 -9
- package/dist/{auth-BH6Awl3O.mjs → auth-CLFNmaXL.mjs} +2 -5
- package/dist/cli.mjs +156 -69
- package/dist/{commands-DNIxtTXe.mjs → commands-BPxSEwAc.mjs} +3 -6
- package/dist/{commands-B6BkPRui.mjs → commands-BpcWHrQ7.mjs} +8 -9
- package/dist/{commands-CE1PdEJJ.mjs → commands-BtXxn3tI.mjs} +2 -5
- package/dist/{commands-B5veY89L.mjs → commands-CXiGBP6w.mjs} +2 -5
- package/dist/{commands-BpNDUqvv.mjs → commands-D3jsQ9Sj.mjs} +21 -18
- package/dist/{commands-BzF6GzdR.mjs → commands-DVEsNZUB.mjs} +2 -5
- package/dist/{commands-BCmpKBjg.mjs → commands-bQxTpr-M.mjs} +2 -5
- package/dist/{fleet-XYsLuf-3.mjs → fleet-BC9JHEWF.mjs} +3 -6
- package/dist/{frpc-QESvQN-s.mjs → frpc-BCOnJSAM.mjs} +11 -10
- package/dist/{headlessCli-DuCmcrAL.mjs → headlessCli-fagwmUja.mjs} +3 -6
- package/dist/index.mjs +2 -5
- package/dist/{package-BA3c2JLu.mjs → package-Dn7kNPhz.mjs} +2 -2
- package/dist/{pinnedClaudeCode-DuLXaoGP.mjs → pinnedClaudeCode-B9O-hKxm.mjs} +1 -1
- package/dist/{rpc-DCeDG4c7.mjs → rpc-D-1o_gWF.mjs} +2 -5
- package/dist/{rpc-Bscxex4z.mjs → rpc-Dko-Fkk6.mjs} +2 -5
- package/dist/{run-BmOCcZRG.mjs → run-BWBtm0gY.mjs} +1 -5
- package/dist/{run-BtGnnEMI.mjs → run-CT8Leg3-.mjs} +729 -425
- package/dist/{scheduler-Dbqmnd_o.mjs → scheduler-CN8jChyQ.mjs} +2 -5
- package/dist/{serveCommands-DueTsJSe.mjs → serveCommands-sWtLnJRW.mjs} +5 -5
- package/dist/{serveManager-BclzoPIb.mjs → serveManager-BuXk1_SH.mjs} +180 -77
- package/dist/{sideband-C_ifGgde.mjs → sideband-ByYvGtj3.mjs} +2 -5
- package/dist/staticFileServer-CbYnj2bH.mjs +255 -0
- package/package.json +2 -2
- package/dist/caddy-CuTbE3NY.mjs +0 -322
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as resolveProjectRoot, H as listWorkflows, I as isWorkflowEnabled, J as workflowCrons, C as runWorkflow, K as cronMatches } from './run-
|
|
1
|
+
import { n as resolveProjectRoot, H as listWorkflows, I as isWorkflowEnabled, J as workflowCrons, C as runWorkflow, K as cronMatches } from './run-CT8Leg3-.mjs';
|
|
2
2
|
import 'os';
|
|
3
3
|
import 'fs/promises';
|
|
4
4
|
import 'fs';
|
|
@@ -14,10 +14,7 @@ import 'node:path';
|
|
|
14
14
|
import 'node:events';
|
|
15
15
|
import 'node:os';
|
|
16
16
|
import '@agentclientprotocol/sdk';
|
|
17
|
-
import '
|
|
18
|
-
import '@modelcontextprotocol/sdk/client/stdio.js';
|
|
19
|
-
import '@modelcontextprotocol/sdk/types.js';
|
|
20
|
-
import 'zod';
|
|
17
|
+
import 'node:readline';
|
|
21
18
|
import 'node:fs/promises';
|
|
22
19
|
import 'node:util';
|
|
23
20
|
import 'yaml';
|
|
@@ -54,7 +54,7 @@ async function handleServeCommand() {
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
async function serveAdd(args, machineId) {
|
|
57
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
57
|
+
const { connectAndGetMachine } = await import('./commands-BtXxn3tI.mjs');
|
|
58
58
|
const pos = positionalArgs(args);
|
|
59
59
|
const name = pos[0];
|
|
60
60
|
if (!name) {
|
|
@@ -93,7 +93,7 @@ async function serveAdd(args, machineId) {
|
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
async function serveApply(args, machineId) {
|
|
96
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
96
|
+
const { connectAndGetMachine } = await import('./commands-BtXxn3tI.mjs');
|
|
97
97
|
const fs = await import('fs');
|
|
98
98
|
const yaml = await import('yaml');
|
|
99
99
|
const file = positionalArgs(args)[0];
|
|
@@ -182,7 +182,7 @@ async function serveApply(args, machineId) {
|
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
184
|
async function serveRemove(args, machineId) {
|
|
185
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
185
|
+
const { connectAndGetMachine } = await import('./commands-BtXxn3tI.mjs');
|
|
186
186
|
const pos = positionalArgs(args);
|
|
187
187
|
const name = pos[0];
|
|
188
188
|
if (!name) {
|
|
@@ -202,7 +202,7 @@ async function serveRemove(args, machineId) {
|
|
|
202
202
|
}
|
|
203
203
|
}
|
|
204
204
|
async function serveList(args, machineId) {
|
|
205
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
205
|
+
const { connectAndGetMachine } = await import('./commands-BtXxn3tI.mjs');
|
|
206
206
|
const all = hasFlag(args, "--all", "-a");
|
|
207
207
|
const json = hasFlag(args, "--json");
|
|
208
208
|
const sessionId = getFlag(args, "--session");
|
|
@@ -235,7 +235,7 @@ async function serveList(args, machineId) {
|
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
237
|
async function serveInfo(machineId) {
|
|
238
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
238
|
+
const { connectAndGetMachine } = await import('./commands-BtXxn3tI.mjs');
|
|
239
239
|
const { machine, server } = await connectAndGetMachine(machineId);
|
|
240
240
|
try {
|
|
241
241
|
const info = await machine.serveInfo();
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { spawn } from 'child_process';
|
|
1
|
+
import { spawn, execSync } from 'child_process';
|
|
2
2
|
import * as crypto from 'crypto';
|
|
3
3
|
import * as fs from 'fs';
|
|
4
4
|
import * as http from 'http';
|
|
5
5
|
import * as net from 'net';
|
|
6
6
|
import * as path from 'path';
|
|
7
|
-
import {
|
|
7
|
+
import { serveStaticMount } from './staticFileServer-CbYnj2bH.mjs';
|
|
8
|
+
import { l as getHyphaServerUrl, S as ServeAuth, m as hasCookieToken } from './run-CT8Leg3-.mjs';
|
|
8
9
|
import 'os';
|
|
9
10
|
import 'fs/promises';
|
|
10
11
|
import 'url';
|
|
@@ -16,10 +17,7 @@ import 'node:path';
|
|
|
16
17
|
import 'node:events';
|
|
17
18
|
import 'node:os';
|
|
18
19
|
import '@agentclientprotocol/sdk';
|
|
19
|
-
import '
|
|
20
|
-
import '@modelcontextprotocol/sdk/client/stdio.js';
|
|
21
|
-
import '@modelcontextprotocol/sdk/types.js';
|
|
22
|
-
import 'zod';
|
|
20
|
+
import 'node:readline';
|
|
23
21
|
import 'node:fs/promises';
|
|
24
22
|
import 'node:util';
|
|
25
23
|
import 'yaml';
|
|
@@ -56,6 +54,27 @@ async function tryReservePort(preferred) {
|
|
|
56
54
|
});
|
|
57
55
|
});
|
|
58
56
|
}
|
|
57
|
+
function killOrphanedCaddy(log) {
|
|
58
|
+
if (process.platform === "win32") return;
|
|
59
|
+
try {
|
|
60
|
+
const out = execSync("ps -axo pid=,command=", { encoding: "utf-8" });
|
|
61
|
+
const pids = [];
|
|
62
|
+
for (const line of out.split("\n")) {
|
|
63
|
+
const m = /^\s*(\d+)\s+(.*)$/.exec(line);
|
|
64
|
+
if (!m) continue;
|
|
65
|
+
const [, pid, cmd] = m;
|
|
66
|
+
if (cmd.includes(".svamp/bin/caddy") && pid !== String(process.pid)) pids.push(pid);
|
|
67
|
+
}
|
|
68
|
+
for (const pid of pids) {
|
|
69
|
+
try {
|
|
70
|
+
process.kill(Number(pid), "SIGKILL");
|
|
71
|
+
} catch {
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (pids.length) log(`Reaped ${pids.length} orphaned Caddy process(es) \u2014 retired in favor of the native file server (#0358).`);
|
|
75
|
+
} catch {
|
|
76
|
+
}
|
|
77
|
+
}
|
|
59
78
|
const MOUNT_NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
|
|
60
79
|
function validateMountName(name) {
|
|
61
80
|
if (!name || name.length > 128) {
|
|
@@ -68,18 +87,14 @@ function validateMountName(name) {
|
|
|
68
87
|
class ServeManager {
|
|
69
88
|
mounts = /* @__PURE__ */ new Map();
|
|
70
89
|
port = 0;
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
// Caddy internal port
|
|
74
|
-
/** Last-used ports loaded from disk — used as preferred values on next start
|
|
90
|
+
// public HTTP server port (serves static files natively — #0358)
|
|
91
|
+
/** Last-used port loaded from disk — used as the preferred value on next start
|
|
75
92
|
* so external configs (tunnels, cron, bookmarks) survive daemon restarts. */
|
|
76
93
|
persistedPort;
|
|
77
|
-
persistedCaddyPort;
|
|
78
94
|
/** Per-mount frpc tunnel — each mount gets its own subdomain `static-<name>-<hash>`. */
|
|
79
95
|
mountTunnels = /* @__PURE__ */ new Map();
|
|
80
96
|
/** hostname (lowercased, no port) → mount name. Updated when tunnels connect. */
|
|
81
97
|
hostToMount = /* @__PURE__ */ new Map();
|
|
82
|
-
caddy = null;
|
|
83
98
|
proxyServer = null;
|
|
84
99
|
auth = null;
|
|
85
100
|
/** Live child processes for managed mounts. Keyed by mount name. */
|
|
@@ -159,9 +174,6 @@ class ServeManager {
|
|
|
159
174
|
};
|
|
160
175
|
this.mounts.set(spec.name, mount);
|
|
161
176
|
await this.ensureRunning();
|
|
162
|
-
if (resolvedDir && this.caddy?.isRunning) {
|
|
163
|
-
await this.caddy.addMount(spec.name, resolvedDir);
|
|
164
|
-
}
|
|
165
177
|
await this.startMountTunnel(spec.name);
|
|
166
178
|
if (spec.process && !spec.process.wakeOnRequest) {
|
|
167
179
|
try {
|
|
@@ -198,13 +210,6 @@ class ServeManager {
|
|
|
198
210
|
for (const [host, mountName] of this.hostToMount.entries()) {
|
|
199
211
|
if (mountName === name) this.hostToMount.delete(host);
|
|
200
212
|
}
|
|
201
|
-
if (this.caddy?.isRunning) {
|
|
202
|
-
try {
|
|
203
|
-
await this.caddy.removeMount(name);
|
|
204
|
-
} catch (err) {
|
|
205
|
-
this.log(`Warning: Caddy mount removal failed: ${err.message}`);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
213
|
this.persist();
|
|
209
214
|
this.log(`Mount removed: ${name}`);
|
|
210
215
|
if (this.mounts.size === 0) {
|
|
@@ -225,12 +230,12 @@ class ServeManager {
|
|
|
225
230
|
* Get server info — each mount has its own URL (per-mount subdomain).
|
|
226
231
|
*/
|
|
227
232
|
getInfo() {
|
|
228
|
-
const running = this.
|
|
233
|
+
const running = this.proxyServer != null;
|
|
229
234
|
const firstMount = this.mounts.values().next().value;
|
|
230
235
|
const firstUrl = firstMount ? this.getMountUrl(firstMount.name) : null;
|
|
231
236
|
return {
|
|
232
237
|
url: firstUrl,
|
|
233
|
-
port: running ? this.
|
|
238
|
+
port: running ? this.port : 0,
|
|
234
239
|
authProxyPort: running ? this.port : 0,
|
|
235
240
|
running,
|
|
236
241
|
mountCount: this.mounts.size,
|
|
@@ -249,7 +254,6 @@ class ServeManager {
|
|
|
249
254
|
if (!fs.existsSync(this.persistFile)) return;
|
|
250
255
|
const raw = JSON.parse(fs.readFileSync(this.persistFile, "utf-8"));
|
|
251
256
|
this.persistedPort = raw.port;
|
|
252
|
-
this.persistedCaddyPort = raw.caddyPort;
|
|
253
257
|
if (!raw.mounts || raw.mounts.length === 0) return;
|
|
254
258
|
let restoredCount = 0;
|
|
255
259
|
for (const m of raw.mounts) {
|
|
@@ -327,11 +331,6 @@ class ServeManager {
|
|
|
327
331
|
await new Promise((resolve) => this.proxyServer.close(() => resolve()));
|
|
328
332
|
this.proxyServer = null;
|
|
329
333
|
}
|
|
330
|
-
if (this.caddy) {
|
|
331
|
-
await this.caddy.stop();
|
|
332
|
-
this.caddy = null;
|
|
333
|
-
this.log("Caddy stopped");
|
|
334
|
-
}
|
|
335
334
|
this.auth?.destroy();
|
|
336
335
|
}
|
|
337
336
|
// ── Managed-process lifecycle ─────────────────────────────────────────
|
|
@@ -488,8 +487,7 @@ class ServeManager {
|
|
|
488
487
|
persist() {
|
|
489
488
|
const state = {
|
|
490
489
|
mounts: Array.from(this.mounts.values()),
|
|
491
|
-
...this.port > 0 ? { port: this.port } : {}
|
|
492
|
-
...this.caddyPort > 0 ? { caddyPort: this.caddyPort } : {}
|
|
490
|
+
...this.port > 0 ? { port: this.port } : {}
|
|
493
491
|
};
|
|
494
492
|
try {
|
|
495
493
|
fs.writeFileSync(this.persistFile, JSON.stringify(state, null, 2));
|
|
@@ -499,32 +497,24 @@ class ServeManager {
|
|
|
499
497
|
}
|
|
500
498
|
/** Start auth proxy + Caddy if not already running. Per-mount tunnels are started separately. */
|
|
501
499
|
async ensureRunning() {
|
|
502
|
-
if (this.
|
|
503
|
-
|
|
500
|
+
if (this.proxyServer) return;
|
|
501
|
+
killOrphanedCaddy((m) => this.log(m));
|
|
504
502
|
this.port = await tryReservePort(this.persistedPort);
|
|
505
|
-
const adminPort = await findFreePort();
|
|
506
503
|
if (this.persistedPort && this.port !== this.persistedPort) {
|
|
507
504
|
this.log(`\u26A0 Previous serve port ${this.persistedPort} unavailable \u2014 using ${this.port}. Downstream configs referencing the old port will need updating.`);
|
|
508
505
|
}
|
|
509
|
-
if (this.persistedCaddyPort && this.caddyPort !== this.persistedCaddyPort) {
|
|
510
|
-
this.log(`\u26A0 Previous Caddy port ${this.persistedCaddyPort} unavailable \u2014 using ${this.caddyPort} (Caddy is internal; no downstream impact).`);
|
|
511
|
-
}
|
|
512
|
-
const { CaddyManager } = await import('./caddy-CuTbE3NY.mjs');
|
|
513
|
-
this.caddy = new CaddyManager({
|
|
514
|
-
listenPort: this.caddyPort,
|
|
515
|
-
adminPort,
|
|
516
|
-
configDir: path.join(path.dirname(this.persistFile), "caddy"),
|
|
517
|
-
log: (msg) => this.log(`[Caddy] ${msg}`)
|
|
518
|
-
});
|
|
519
|
-
for (const mount of this.mounts.values()) {
|
|
520
|
-
if (mount.directory) {
|
|
521
|
-
await this.caddy.addMount(mount.name, mount.directory);
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
await this.caddy.start();
|
|
525
|
-
this.log(`Caddy file server started on 127.0.0.1:${this.caddyPort}`);
|
|
526
506
|
await this.startAuthProxy();
|
|
527
|
-
this.log(`
|
|
507
|
+
this.log(`Static file server started on 127.0.0.1:${this.port}`);
|
|
508
|
+
}
|
|
509
|
+
/** Minimal mount-listing page for the server root (replaces Caddy's root route). */
|
|
510
|
+
mountListHtml() {
|
|
511
|
+
const esc = (s) => s.replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c]);
|
|
512
|
+
const items = Array.from(this.mounts.values()).filter((m) => m.directory).map((m) => `<li><a href="/${esc(m.name)}/">${esc(m.name)}</a> \u2014 ${esc(m.directory || "")}</li>`).join("\n");
|
|
513
|
+
return `<!DOCTYPE html><html><head><meta charset="utf-8"><title>Svamp File Server</title>
|
|
514
|
+
<style>body{font-family:system-ui,sans-serif;max-width:700px;margin:40px auto;padding:0 20px;color:#333}
|
|
515
|
+
h1{font-size:1.3rem}ul{list-style:none;padding:0}li{padding:8px 0;border-bottom:1px solid #eee}
|
|
516
|
+
a{color:#0969da;text-decoration:none;font-weight:500}a:hover{text-decoration:underline}</style></head>
|
|
517
|
+
<body><h1>Svamp File Server</h1><ul>${items || "<li>No mounts registered.</li>"}</ul></body></html>`;
|
|
528
518
|
}
|
|
529
519
|
/** Start a lightweight Node.js HTTP proxy with auth + upload support. */
|
|
530
520
|
startAuthProxy() {
|
|
@@ -604,6 +594,21 @@ class ServeManager {
|
|
|
604
594
|
const base = path.resolve(mount.directory);
|
|
605
595
|
const fp = path.resolve(path.join(base, basePath));
|
|
606
596
|
if (fp !== base && !fp.startsWith(base + path.sep)) return null;
|
|
597
|
+
try {
|
|
598
|
+
const realRoot = fs.realpathSync(base);
|
|
599
|
+
let ancestor = fp;
|
|
600
|
+
while (!fs.existsSync(ancestor) && path.dirname(ancestor) !== ancestor) {
|
|
601
|
+
ancestor = path.dirname(ancestor);
|
|
602
|
+
}
|
|
603
|
+
const realAncestor = fs.realpathSync(ancestor);
|
|
604
|
+
if (realAncestor !== realRoot && !realAncestor.startsWith(realRoot + path.sep)) return null;
|
|
605
|
+
if (fs.existsSync(fp) && fs.lstatSync(fp).isSymbolicLink()) {
|
|
606
|
+
const realTarget = fs.realpathSync(fp);
|
|
607
|
+
if (realTarget !== realRoot && !realTarget.startsWith(realRoot + path.sep)) return null;
|
|
608
|
+
}
|
|
609
|
+
} catch {
|
|
610
|
+
return null;
|
|
611
|
+
}
|
|
607
612
|
return fp;
|
|
608
613
|
};
|
|
609
614
|
if ((req.method === "PUT" || req.method === "DELETE") && mount && mount.directory) {
|
|
@@ -658,7 +663,7 @@ class ServeManager {
|
|
|
658
663
|
const handle = this.managedProcs.get(mount.name);
|
|
659
664
|
if (handle) handle.lastRequestAt = Date.now();
|
|
660
665
|
const targetPath = mountResolvedByHost ? req.url || "/" : (basePath || "/") + (url.search || "");
|
|
661
|
-
const
|
|
666
|
+
const proxyReq = http.request({
|
|
662
667
|
hostname: "127.0.0.1",
|
|
663
668
|
port: cfg.port,
|
|
664
669
|
path: targetPath,
|
|
@@ -668,37 +673,135 @@ class ServeManager {
|
|
|
668
673
|
res.writeHead(proxyRes.statusCode || 200, proxyRes.headers);
|
|
669
674
|
proxyRes.pipe(res);
|
|
670
675
|
});
|
|
671
|
-
|
|
676
|
+
proxyReq.on("error", (err) => {
|
|
672
677
|
if (!res.headersSent) {
|
|
673
678
|
res.writeHead(502);
|
|
674
679
|
res.end(`Backend error: ${err.message}`);
|
|
675
680
|
}
|
|
676
681
|
});
|
|
677
|
-
|
|
682
|
+
const abortUpstream = () => {
|
|
683
|
+
if (!proxyReq.destroyed) proxyReq.destroy();
|
|
684
|
+
};
|
|
685
|
+
req.on("aborted", abortUpstream);
|
|
686
|
+
res.on("close", () => {
|
|
687
|
+
if (!res.writableFinished) abortUpstream();
|
|
688
|
+
});
|
|
689
|
+
proxyReq.setTimeout(12e4, abortUpstream);
|
|
690
|
+
req.pipe(proxyReq);
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
if (mount && mount.directory) {
|
|
694
|
+
serveStaticMount(req, res, {
|
|
695
|
+
rootDir: mount.directory,
|
|
696
|
+
relPath: basePath || "/",
|
|
697
|
+
// Path-based access is prefixed with /<mountName>; host-based has no prefix.
|
|
698
|
+
mountUrlPrefix: mountResolvedByHost ? "" : `/${mountName}`,
|
|
699
|
+
browse: true});
|
|
678
700
|
return;
|
|
679
701
|
}
|
|
680
|
-
|
|
681
|
-
if (
|
|
682
|
-
|
|
683
|
-
|
|
702
|
+
const cors = { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET, HEAD, OPTIONS", "Access-Control-Allow-Headers": "*" };
|
|
703
|
+
if (url.pathname === "/" || basePath === "/") {
|
|
704
|
+
res.writeHead(200, { ...cors, "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-store" });
|
|
705
|
+
res.end(this.mountListHtml());
|
|
706
|
+
} else {
|
|
707
|
+
res.writeHead(404, { ...cors, "Content-Type": "text/plain" });
|
|
708
|
+
res.end("Not found");
|
|
684
709
|
}
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
710
|
+
});
|
|
711
|
+
server.on("upgrade", (req, clientSocket, head) => {
|
|
712
|
+
const deny = (code, reason) => {
|
|
713
|
+
try {
|
|
714
|
+
clientSocket.write(`HTTP/1.1 ${code} ${reason}\r
|
|
715
|
+
Connection: close\r
|
|
716
|
+
\r
|
|
717
|
+
`);
|
|
718
|
+
} catch {
|
|
719
|
+
}
|
|
720
|
+
try {
|
|
721
|
+
clientSocket.destroy();
|
|
722
|
+
} catch {
|
|
723
|
+
}
|
|
724
|
+
};
|
|
725
|
+
void (async () => {
|
|
726
|
+
try {
|
|
727
|
+
const url = new URL(req.url || "/", `http://127.0.0.1:${this.port}`);
|
|
728
|
+
const incomingHost = (req.headers.host || "").split(":")[0].toLowerCase();
|
|
729
|
+
const hostMount = this.hostToMount.get(incomingHost);
|
|
730
|
+
let mountName;
|
|
731
|
+
let mountResolvedByHost = false;
|
|
732
|
+
if (hostMount && this.mounts.has(hostMount)) {
|
|
733
|
+
mountName = hostMount;
|
|
734
|
+
mountResolvedByHost = true;
|
|
735
|
+
} else {
|
|
736
|
+
mountName = url.pathname.split("/").filter(Boolean)[0];
|
|
737
|
+
}
|
|
738
|
+
const mount = mountName ? this.mounts.get(mountName) : void 0;
|
|
739
|
+
if (!mount || !mount.process) {
|
|
740
|
+
deny(404, "Not Found");
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
if (mount.access !== "public" && mount.access !== "link") {
|
|
744
|
+
if (mount.access === "owner" && !mount.ownerEmail) {
|
|
745
|
+
deny(403, "Forbidden");
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
const userEmail = this.auth ? await this.auth.authenticate(req).catch(() => null) : null;
|
|
749
|
+
const allowed = userEmail && this.auth ? this.auth.isAuthorized(userEmail, mount.access, mount.ownerEmail) : false;
|
|
750
|
+
if (!allowed) {
|
|
751
|
+
deny(userEmail ? 403 : 401, userEmail ? "Forbidden" : "Unauthorized");
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
const cfg = mount.process;
|
|
756
|
+
if (cfg.wakeOnRequest || !this.managedProcs.has(mount.name)) {
|
|
757
|
+
try {
|
|
758
|
+
await this.ensureManagedRunning(mount.name);
|
|
759
|
+
} catch {
|
|
760
|
+
deny(503, "Backend Not Ready");
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
const handle = this.managedProcs.get(mount.name);
|
|
765
|
+
if (handle) handle.lastRequestAt = Date.now();
|
|
766
|
+
const targetPath = mountResolvedByHost ? req.url || "/" : (url.pathname.slice(`/${mountName}`.length) || "/") + (url.search || "");
|
|
767
|
+
const upstream = net.connect(cfg.port, "127.0.0.1", () => {
|
|
768
|
+
const lines = [`${req.method} ${targetPath} HTTP/1.1`];
|
|
769
|
+
for (let i = 0; i < req.rawHeaders.length; i += 2) {
|
|
770
|
+
lines.push(`${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}`);
|
|
771
|
+
}
|
|
772
|
+
upstream.write(lines.join("\r\n") + "\r\n\r\n");
|
|
773
|
+
if (head && head.length) upstream.write(head);
|
|
774
|
+
upstream.pipe(clientSocket);
|
|
775
|
+
clientSocket.pipe(upstream);
|
|
776
|
+
});
|
|
777
|
+
const teardown = () => {
|
|
778
|
+
try {
|
|
779
|
+
upstream.destroy();
|
|
780
|
+
} catch {
|
|
781
|
+
}
|
|
782
|
+
try {
|
|
783
|
+
clientSocket.destroy();
|
|
784
|
+
} catch {
|
|
785
|
+
}
|
|
786
|
+
};
|
|
787
|
+
upstream.on("error", teardown);
|
|
788
|
+
clientSocket.on("error", teardown);
|
|
789
|
+
upstream.on("close", () => {
|
|
790
|
+
try {
|
|
791
|
+
clientSocket.destroy();
|
|
792
|
+
} catch {
|
|
793
|
+
}
|
|
794
|
+
});
|
|
795
|
+
clientSocket.on("close", () => {
|
|
796
|
+
try {
|
|
797
|
+
upstream.destroy();
|
|
798
|
+
} catch {
|
|
799
|
+
}
|
|
800
|
+
});
|
|
801
|
+
} catch {
|
|
802
|
+
deny(500, "Internal Server Error");
|
|
699
803
|
}
|
|
700
|
-
});
|
|
701
|
-
req.pipe(proxyReq);
|
|
804
|
+
})();
|
|
702
805
|
});
|
|
703
806
|
this.proxyServer = server;
|
|
704
807
|
server.listen(this.port, "127.0.0.1", () => resolve());
|
|
@@ -751,7 +854,7 @@ class ServeManager {
|
|
|
751
854
|
const mount = this.mounts.get(mountName);
|
|
752
855
|
const subdomainOverride = mount?.access === "link" && mount.linkToken ? /* @__PURE__ */ new Map([[this.port, buildLinkSubdomain(subdomainSafe, mount.linkToken)]]) : void 0;
|
|
753
856
|
try {
|
|
754
|
-
const { FrpcTunnel } = await import('./frpc-
|
|
857
|
+
const { FrpcTunnel } = await import('./frpc-BCOnJSAM.mjs');
|
|
755
858
|
let tunnel;
|
|
756
859
|
tunnel = new FrpcTunnel({
|
|
757
860
|
name: tunnelName,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { R as READ_ONLY_TOOLS, N as loadMachineContext, O as buildMachineInstructions, P as machineToolsForRole, Q as buildMachineTools } from './run-
|
|
1
|
+
import { R as READ_ONLY_TOOLS, N as loadMachineContext, O as buildMachineInstructions, P as machineToolsForRole, Q as buildMachineTools } from './run-CT8Leg3-.mjs';
|
|
2
2
|
import 'node:child_process';
|
|
3
3
|
import 'os';
|
|
4
4
|
import 'fs/promises';
|
|
@@ -14,10 +14,7 @@ import 'node:path';
|
|
|
14
14
|
import 'node:events';
|
|
15
15
|
import 'node:os';
|
|
16
16
|
import '@agentclientprotocol/sdk';
|
|
17
|
-
import '
|
|
18
|
-
import '@modelcontextprotocol/sdk/client/stdio.js';
|
|
19
|
-
import '@modelcontextprotocol/sdk/types.js';
|
|
20
|
-
import 'zod';
|
|
17
|
+
import 'node:readline';
|
|
21
18
|
import 'node:fs/promises';
|
|
22
19
|
import 'node:util';
|
|
23
20
|
import 'yaml';
|