svamp-cli 0.2.129 → 0.2.131
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-CZk6NL7b.mjs → agentCommands-D59UqyHc.mjs} +4 -4
- package/dist/{auth-C4miUceQ.mjs → auth-ex1TLJGI.mjs} +1 -1
- package/dist/cli.mjs +55 -55
- package/dist/{commands-CK1ZOskY.mjs → commands-BdDj6MWA.mjs} +19 -8
- package/dist/{commands-BV30A1zt.mjs → commands-CP0LaCNP.mjs} +1 -1
- package/dist/{commands-CWIKYhzM.mjs → commands-Cc9cCSjY.mjs} +2 -2
- package/dist/{commands-oF0MQ_jX.mjs → commands-ChqgXlxM.mjs} +2 -2
- package/dist/{commands-CCqAWMnX.mjs → commands-DlknWHyv.mjs} +1 -1
- package/dist/{commands-DEZSgxop.mjs → commands-Dw2SDC7m.mjs} +2 -2
- package/dist/{fleet-BwmE0enl.mjs → fleet-Bo5UCnbZ.mjs} +1 -1
- package/dist/{frpc-BpBOWRbL.mjs → frpc-DjCP6NoG.mjs} +147 -8
- package/dist/{headlessCli-Cj4WQsCx.mjs → headlessCli-B4ajzkit.mjs} +2 -2
- package/dist/index.mjs +1 -1
- package/dist/{package-DzPfT1Xs.mjs → package-B2OzFsgB.mjs} +2 -2
- package/dist/{run-BaTwfE1Q.mjs → run-BIwWpHSR.mjs} +141 -33
- package/dist/{run-C6Q6ZlNu.mjs → run-DwKCJsbF.mjs} +1 -1
- package/dist/{serveCommands-GzGpHWlP.mjs → serveCommands-IUmUvv8B.mjs} +5 -5
- package/dist/{serveManager-cPgahjYE.mjs → serveManager-D7_YZY-E.mjs} +2 -2
- package/dist/{sideband-D_Hzijan.mjs → sideband-BnEpfp8h.mjs} +1 -1
- package/package.json +2 -2
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { spawn, execSync } from 'child_process';
|
|
2
|
+
import { createServer } from 'net';
|
|
2
3
|
import { mkdirSync, writeFileSync, unlinkSync, existsSync, chmodSync, readFileSync } from 'fs';
|
|
3
4
|
import { join } from 'path';
|
|
4
5
|
import { homedir, platform, arch } from 'os';
|
|
5
|
-
import {
|
|
6
|
-
import { h as getFrpsSubdomainHost, i as getFrpsServerPort, j as getFrpsServerAddr } from './run-
|
|
6
|
+
import { randomUUID, createHash } from 'crypto';
|
|
7
|
+
import { h as getFrpsSubdomainHost, i as getFrpsServerPort, j as getFrpsServerAddr } from './run-BIwWpHSR.mjs';
|
|
7
8
|
import 'fs/promises';
|
|
8
9
|
import 'url';
|
|
9
10
|
import 'node:crypto';
|
|
@@ -124,7 +125,7 @@ async function ensureFrpc(log) {
|
|
|
124
125
|
}
|
|
125
126
|
return FRPC_BIN;
|
|
126
127
|
}
|
|
127
|
-
function generateFrpcConfig(config, proxies) {
|
|
128
|
+
function generateFrpcConfig(config, proxies, admin) {
|
|
128
129
|
const useWSS = config.serverPort === 443;
|
|
129
130
|
const lines = [
|
|
130
131
|
"# Auto-generated by svamp \u2014 do not edit",
|
|
@@ -154,6 +155,14 @@ function generateFrpcConfig(config, proxies) {
|
|
|
154
155
|
'log.level = "info"',
|
|
155
156
|
""
|
|
156
157
|
];
|
|
158
|
+
if (admin) {
|
|
159
|
+
lines.push("# Local admin/status API (loopback only \u2014 polled by the svamp daemon)");
|
|
160
|
+
lines.push('webServer.addr = "127.0.0.1"');
|
|
161
|
+
lines.push(`webServer.port = ${admin.port}`);
|
|
162
|
+
lines.push(`webServer.user = "${admin.user}"`);
|
|
163
|
+
lines.push(`webServer.password = "${admin.password}"`);
|
|
164
|
+
lines.push("");
|
|
165
|
+
}
|
|
157
166
|
for (const proxy of proxies) {
|
|
158
167
|
lines.push(`[[proxies]]`);
|
|
159
168
|
lines.push(`name = "${proxy.name}"`);
|
|
@@ -189,6 +198,42 @@ function generateFrpcConfig(config, proxies) {
|
|
|
189
198
|
}
|
|
190
199
|
return lines.join("\n");
|
|
191
200
|
}
|
|
201
|
+
function getFreePort() {
|
|
202
|
+
return new Promise((resolve, reject) => {
|
|
203
|
+
const srv = createServer();
|
|
204
|
+
srv.unref();
|
|
205
|
+
srv.on("error", reject);
|
|
206
|
+
srv.listen(0, "127.0.0.1", () => {
|
|
207
|
+
const addr = srv.address();
|
|
208
|
+
const port = typeof addr === "object" && addr ? addr.port : 0;
|
|
209
|
+
srv.close(() => port ? resolve(port) : reject(new Error("no port")));
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
function parseFrpcStatus(payload, proxyNames) {
|
|
214
|
+
const byName = /* @__PURE__ */ new Map();
|
|
215
|
+
if (payload && typeof payload === "object") {
|
|
216
|
+
for (const group of Object.values(payload)) {
|
|
217
|
+
if (!Array.isArray(group)) continue;
|
|
218
|
+
for (const p of group) {
|
|
219
|
+
if (p && typeof p.name === "string") {
|
|
220
|
+
byName.set(p.name, { status: String(p.status ?? ""), err: p.err ? String(p.err) : void 0 });
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
const missing = [];
|
|
226
|
+
const failed = [];
|
|
227
|
+
for (const name of proxyNames) {
|
|
228
|
+
const entry = byName.get(name);
|
|
229
|
+
if (!entry) {
|
|
230
|
+
missing.push(name);
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
if (entry.status !== "running") failed.push({ name, status: entry.status, err: entry.err });
|
|
234
|
+
}
|
|
235
|
+
return { allRunning: missing.length === 0 && failed.length === 0, missing, failed };
|
|
236
|
+
}
|
|
192
237
|
class FrpcTunnel {
|
|
193
238
|
process = null;
|
|
194
239
|
_connected = false;
|
|
@@ -211,6 +256,11 @@ class FrpcTunnel {
|
|
|
211
256
|
_lastProbeOkAt = 0;
|
|
212
257
|
_lastProbeFailAt = 0;
|
|
213
258
|
_probeOk = false;
|
|
259
|
+
// frpc admin/status API state (set when options.adminStatus is true).
|
|
260
|
+
_adminPort = 0;
|
|
261
|
+
_adminUser = "svamp";
|
|
262
|
+
_adminPassword = randomUUID();
|
|
263
|
+
_statusTimer = null;
|
|
214
264
|
constructor(options) {
|
|
215
265
|
this.options = options;
|
|
216
266
|
this.log = options.log || ((msg) => console.log(`[FRPC] ${msg}`));
|
|
@@ -255,7 +305,18 @@ class FrpcTunnel {
|
|
|
255
305
|
if (this._destroyed) return;
|
|
256
306
|
if (this.process) return;
|
|
257
307
|
const frpcPath = await ensureFrpc(this.log);
|
|
258
|
-
|
|
308
|
+
let admin;
|
|
309
|
+
if (this.options.adminStatus) {
|
|
310
|
+
if (!this._adminPort) {
|
|
311
|
+
try {
|
|
312
|
+
this._adminPort = await getFreePort();
|
|
313
|
+
} catch (err) {
|
|
314
|
+
this.log(`admin port alloc failed: ${err?.message ?? err}`);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
if (this._adminPort) admin = { port: this._adminPort, user: this._adminUser, password: this._adminPassword };
|
|
318
|
+
}
|
|
319
|
+
const configContent = generateFrpcConfig(this.serverConfig, this.proxies, admin);
|
|
259
320
|
writeFileSync(this.configPath, configContent);
|
|
260
321
|
this.log(`Config written to ${this.configPath}`);
|
|
261
322
|
return new Promise((resolve, reject) => {
|
|
@@ -335,6 +396,8 @@ class FrpcTunnel {
|
|
|
335
396
|
}
|
|
336
397
|
}
|
|
337
398
|
});
|
|
399
|
+
} else if (this.options.adminStatus && this._adminPort) {
|
|
400
|
+
this.startAdminStatusLoop();
|
|
338
401
|
}
|
|
339
402
|
setTimeout(() => {
|
|
340
403
|
if (!resolved) {
|
|
@@ -433,11 +496,86 @@ class FrpcTunnel {
|
|
|
433
496
|
this._probeTimer = null;
|
|
434
497
|
}
|
|
435
498
|
}
|
|
499
|
+
/**
|
|
500
|
+
* Poll frpc's loopback admin API (`/api/status`) to track whether this
|
|
501
|
+
* tunnel's proxies are registered ("running"). Feeds the same `_probeOk` /
|
|
502
|
+
* staleness fields the daemon health loop watches, so a ghosted/stuck proxy
|
|
503
|
+
* is detected and recreated even with no HTTP health endpoint on the backend.
|
|
504
|
+
*
|
|
505
|
+
* Conservative semantics (critical infra — must not churn healthy tunnels):
|
|
506
|
+
* - all proxies "running" → ok (refresh lastProbeOkAt)
|
|
507
|
+
* - a proxy present but not running, or missing after a grace period
|
|
508
|
+
* → fail (sets lastProbeFailAt; daemon recreates after staleness)
|
|
509
|
+
* - admin API unreachable → INCONCLUSIVE: leave _probeOk untouched
|
|
510
|
+
* (a transient blip can't flip ok→fail)
|
|
511
|
+
*/
|
|
512
|
+
startAdminStatusLoop() {
|
|
513
|
+
this.stopAdminStatusLoop();
|
|
514
|
+
if (!this._adminPort) return;
|
|
515
|
+
const proxyNames = this.proxies.map((p) => p.name);
|
|
516
|
+
const intervalMs = this.options.probeIntervalMs ?? 3e4;
|
|
517
|
+
const startedAt = Date.now();
|
|
518
|
+
const auth = "Basic " + Buffer.from(`${this._adminUser}:${this._adminPassword}`).toString("base64");
|
|
519
|
+
this._probeOk = true;
|
|
520
|
+
this._lastProbeOkAt = Date.now();
|
|
521
|
+
let inFlight = false;
|
|
522
|
+
const poll = async () => {
|
|
523
|
+
if (this._destroyed || inFlight || !this.process) return;
|
|
524
|
+
inFlight = true;
|
|
525
|
+
try {
|
|
526
|
+
const ctrl = new AbortController();
|
|
527
|
+
const timer = setTimeout(() => ctrl.abort(), 5e3);
|
|
528
|
+
let payload;
|
|
529
|
+
try {
|
|
530
|
+
const resp = await fetch(`http://127.0.0.1:${this._adminPort}/api/status`, {
|
|
531
|
+
headers: { Authorization: auth },
|
|
532
|
+
signal: ctrl.signal
|
|
533
|
+
});
|
|
534
|
+
if (!resp.ok) throw new Error(`admin status ${resp.status}`);
|
|
535
|
+
payload = await resp.json();
|
|
536
|
+
} finally {
|
|
537
|
+
clearTimeout(timer);
|
|
538
|
+
}
|
|
539
|
+
const { allRunning, missing, failed } = parseFrpcStatus(payload, proxyNames);
|
|
540
|
+
const graceElapsed = Date.now() - startedAt > 2e4;
|
|
541
|
+
if (allRunning || !failed.length && !graceElapsed) {
|
|
542
|
+
const wasFailing = !this._probeOk;
|
|
543
|
+
this._probeOk = true;
|
|
544
|
+
this._lastProbeOkAt = Date.now();
|
|
545
|
+
if (wasFailing) this.log(`admin status ok: all proxies running`);
|
|
546
|
+
} else {
|
|
547
|
+
const wasOk = this._probeOk;
|
|
548
|
+
this._probeOk = false;
|
|
549
|
+
this._lastProbeFailAt = Date.now();
|
|
550
|
+
if (wasOk) {
|
|
551
|
+
const detail = [
|
|
552
|
+
...failed.map((f) => `${f.name}=${f.status}${f.err ? ` (${f.err})` : ""}`),
|
|
553
|
+
...missing.map((m) => `${m}=missing`)
|
|
554
|
+
].join(", ");
|
|
555
|
+
this.log(`admin status fail: ${detail}`);
|
|
556
|
+
this.options.onProbeFail?.(new Error(`frpc proxy not running: ${detail}`));
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
} catch {
|
|
560
|
+
} finally {
|
|
561
|
+
inFlight = false;
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
if (intervalMs > 0) this._statusTimer = setInterval(poll, intervalMs);
|
|
565
|
+
setTimeout(() => void poll(), 3e3);
|
|
566
|
+
}
|
|
567
|
+
stopAdminStatusLoop() {
|
|
568
|
+
if (this._statusTimer) {
|
|
569
|
+
clearInterval(this._statusTimer);
|
|
570
|
+
this._statusTimer = null;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
436
573
|
/** Disconnect and stop the frpc process. */
|
|
437
574
|
destroy() {
|
|
438
575
|
this._destroyed = true;
|
|
439
576
|
this._connected = false;
|
|
440
577
|
this.stopProbeLoop();
|
|
578
|
+
this.stopAdminStatusLoop();
|
|
441
579
|
if (this.process) {
|
|
442
580
|
this.process.kill("SIGTERM");
|
|
443
581
|
const p = this.process;
|
|
@@ -473,8 +611,8 @@ class FrpcTunnel {
|
|
|
473
611
|
firstErrorAt: this._firstErrorAt,
|
|
474
612
|
restartAttempts: this._restartAttempts,
|
|
475
613
|
failingDurationMs: this._firstErrorAt > 0 ? Date.now() - this._firstErrorAt : 0,
|
|
476
|
-
probe: this.resolveProbeUrl() ? {
|
|
477
|
-
url: this.resolveProbeUrl()
|
|
614
|
+
probe: this.resolveProbeUrl() || this.options.adminStatus && this._adminPort ? {
|
|
615
|
+
url: this.resolveProbeUrl() || `frpc-admin:${this._adminPort}/api/status`,
|
|
478
616
|
ok: this._probeOk,
|
|
479
617
|
lastOkAt: this._lastProbeOkAt,
|
|
480
618
|
lastFailAt: this._lastProbeFailAt,
|
|
@@ -485,7 +623,8 @@ class FrpcTunnel {
|
|
|
485
623
|
/** Update the Hypha token. Rewrites config; takes effect on next frpc restart. */
|
|
486
624
|
updateToken(newToken) {
|
|
487
625
|
this.serverConfig.hyphaToken = newToken;
|
|
488
|
-
const
|
|
626
|
+
const admin = this.options.adminStatus && this._adminPort ? { port: this._adminPort, user: this._adminUser, password: this._adminPassword } : void 0;
|
|
627
|
+
const configContent = generateFrpcConfig(this.serverConfig, this.proxies, admin);
|
|
489
628
|
writeFileSync(this.configPath, configContent);
|
|
490
629
|
this.log("Config updated with fresh token");
|
|
491
630
|
}
|
|
@@ -539,4 +678,4 @@ async function runFrpcTunnel(name, ports, serverConfig, tunnelOptions) {
|
|
|
539
678
|
}
|
|
540
679
|
}
|
|
541
680
|
|
|
542
|
-
export { FrpcTunnel, ensureFrpc, generateFrpcConfig, runFrpcTunnel };
|
|
681
|
+
export { FrpcTunnel, ensureFrpc, generateFrpcConfig, getFreePort, parseFrpcStatus, runFrpcTunnel };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { D as resolveModel, V as describeMisconfiguration, W as buildMachineDeps } from './run-
|
|
2
|
-
import { handleRealtimeEvent, initMachineVoiceSession } from './sideband-
|
|
1
|
+
import { D as resolveModel, V as describeMisconfiguration, W as buildMachineDeps } from './run-BIwWpHSR.mjs';
|
|
2
|
+
import { handleRealtimeEvent, initMachineVoiceSession } from './sideband-BnEpfp8h.mjs';
|
|
3
3
|
import { WebSocket } from 'ws';
|
|
4
4
|
import { execSync, spawn } from 'child_process';
|
|
5
5
|
import 'os';
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { c as connectToHypha, a as createSessionStore, d as daemonStatus, g as getHyphaServerUrl, r as registerMachineService, s as startDaemon, b as stopDaemon } from './run-
|
|
1
|
+
export { c as connectToHypha, a as createSessionStore, d as daemonStatus, g as getHyphaServerUrl, r as registerMachineService, s as startDaemon, b as stopDaemon } from './run-BIwWpHSR.mjs';
|
|
2
2
|
import 'os';
|
|
3
3
|
import 'fs/promises';
|
|
4
4
|
import 'fs';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
var name = "svamp-cli";
|
|
2
|
-
var version = "0.2.
|
|
2
|
+
var version = "0.2.131";
|
|
3
3
|
var description = "Svamp CLI — AI workspace daemon on Hypha Cloud";
|
|
4
4
|
var author = "Amun AI AB";
|
|
5
5
|
var license = "SEE LICENSE IN LICENSE";
|
|
@@ -19,7 +19,7 @@ var exports$1 = {
|
|
|
19
19
|
var scripts = {
|
|
20
20
|
build: "rm -rf dist bin/skills && mkdir -p bin/skills && cp -r ../../skills/artifact bin/skills/artifact && cp -r ../../skills/loop bin/skills/loop && cp -r ../../skills/crew bin/skills/crew && tsc --noEmit && pkgroll",
|
|
21
21
|
typecheck: "tsc --noEmit",
|
|
22
|
-
test: "npx tsx test/test-context-window.mjs && npx tsx test/test-instance-config.mjs && npx tsx test/test-authorize.mjs && npx tsx test/test-normalize-allowed-user.mjs && npx tsx test/test-share-url.mjs && npx tsx test/test-update-sharing-normalization.mjs && npx tsx test/test-staged-homes-sweep.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-isolation-decision.mjs && npx tsx test/test-loop-activation.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-claude-auth.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-inbox-guard.mjs && npx tsx test/test-auto-topic.mjs && npx tsx test/test-project-info.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-codex-backend.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-session-send-query.mjs && npx tsx test/test-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-machine-list-directory.mjs && npx tsx test/test-service-commands.mjs && npx tsx test/test-supervisor.mjs && npx tsx test/test-supervisor-lock.mjs && node test/test-supervisor-restart.mjs && npx tsx test/test-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox.mjs && npx tsx test/test-checklist.mjs && npx tsx test/test-short-id.mjs && npx tsx test/test-transcript-edit.mjs && npx tsx test/test-edit-history.mjs && npx tsx test/test-friendly-name.mjs && npx tsx test/test-session-rpc-dispatch.mjs && npx tsx test/test-sandbox-cli.mjs && npx tsx test/test-serve-manager.mjs && npx tsx test/test-serve-stability.mjs && npx tsx test/test-frpc-e2e.mjs --unit-only && node test/pinnedClaudeCode.test.mjs && node test/fleet.test.mjs && npx tsx test/test-routine.mjs && npx tsx test/test-routine-rpc.mjs && npx tsx test/test-checklist-watchdog.mjs && npx tsx test/test-session-file.mjs && npx tsx test/test-channel-rpc.mjs && npx tsx test/test-wise-agent.mjs && npx tsx test/test-channel-agent.mjs && npx tsx test/test-channels-service.mjs && npx tsx test/test-channel-async-reply.mjs && npx tsx test/test-channel-binding.mjs && npx tsx test/test-channel-identity.mjs && npx tsx test/test-wise-agent-auth.mjs && npx tsx test/test-channel-http.mjs && npx tsx test/test-wise-voice.mjs && npx tsx test/test-wise-headless.mjs && npx tsx test/test-wise-machine.mjs && npx tsx test/test-crew-merge.mjs",
|
|
22
|
+
test: "npx tsx test/test-context-window.mjs && npx tsx test/test-instance-config.mjs && npx tsx test/test-authorize.mjs && npx tsx test/test-normalize-allowed-user.mjs && npx tsx test/test-share-url.mjs && npx tsx test/test-update-sharing-normalization.mjs && npx tsx test/test-staged-homes-sweep.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-isolation-decision.mjs && npx tsx test/test-loop-activation.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-claude-auth.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-inbox-guard.mjs && npx tsx test/test-auto-topic.mjs && npx tsx test/test-project-info.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-codex-backend.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-session-send-query.mjs && npx tsx test/test-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-machine-list-directory.mjs && npx tsx test/test-service-commands.mjs && npx tsx test/test-supervisor.mjs && npx tsx test/test-supervisor-lock.mjs && node test/test-supervisor-restart.mjs && npx tsx test/test-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox.mjs && npx tsx test/test-checklist.mjs && npx tsx test/test-short-id.mjs && npx tsx test/test-transcript-edit.mjs && npx tsx test/test-edit-history.mjs && npx tsx test/test-friendly-name.mjs && npx tsx test/test-session-rpc-dispatch.mjs && npx tsx test/test-sandbox-cli.mjs && npx tsx test/test-serve-manager.mjs && npx tsx test/test-serve-stability.mjs && npx tsx test/test-frpc-e2e.mjs --unit-only && npx tsx test/test-frpc-status.mjs && node test/pinnedClaudeCode.test.mjs && node test/fleet.test.mjs && npx tsx test/test-routine.mjs && npx tsx test/test-routine-rpc.mjs && npx tsx test/test-checklist-watchdog.mjs && npx tsx test/test-session-file.mjs && npx tsx test/test-channel-rpc.mjs && npx tsx test/test-wise-agent.mjs && npx tsx test/test-channel-agent.mjs && npx tsx test/test-channels-service.mjs && npx tsx test/test-channel-async-reply.mjs && npx tsx test/test-channel-binding.mjs && npx tsx test/test-channel-identity.mjs && npx tsx test/test-wise-agent-auth.mjs && npx tsx test/test-channel-http.mjs && npx tsx test/test-wise-voice.mjs && npx tsx test/test-wise-headless.mjs && npx tsx test/test-wise-machine.mjs && npx tsx test/test-crew-merge.mjs",
|
|
23
23
|
"test:hypha": "node --no-warnings test/test-hypha-service.mjs",
|
|
24
24
|
dev: "tsx src/cli.ts",
|
|
25
25
|
"dev:daemon": "tsx src/cli.ts daemon start-sync",
|
|
@@ -2677,7 +2677,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
2677
2677
|
const tunnels = handlers.tunnels;
|
|
2678
2678
|
if (!tunnels) throw new Error("Tunnel management not available");
|
|
2679
2679
|
if (tunnels.has(params.name)) throw new Error(`Tunnel '${params.name}' already running`);
|
|
2680
|
-
const { FrpcTunnel } = await import('./frpc-
|
|
2680
|
+
const { FrpcTunnel } = await import('./frpc-DjCP6NoG.mjs');
|
|
2681
2681
|
const tunnel = new FrpcTunnel({
|
|
2682
2682
|
name: params.name,
|
|
2683
2683
|
ports: params.ports,
|
|
@@ -2686,6 +2686,10 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
2686
2686
|
healthCheckType: params.healthCheckType,
|
|
2687
2687
|
healthCheckPath: params.healthCheckPath,
|
|
2688
2688
|
healthCheckInterval: params.healthCheckInterval,
|
|
2689
|
+
// Poll frpc's loopback admin API for backend-agnostic
|
|
2690
|
+
// ghost/stuck-proxy detection (the daemon health loop recreates
|
|
2691
|
+
// on persistent failure).
|
|
2692
|
+
adminStatus: true,
|
|
2689
2693
|
onError: (err) => console.error(`[FRPC] ${params.name}: ${err.message}`),
|
|
2690
2694
|
onConnect: () => console.log(`[FRPC] ${params.name}: connected`),
|
|
2691
2695
|
onDisconnect: () => console.log(`[FRPC] ${params.name}: disconnected, will auto-reconnect`)
|
|
@@ -2718,14 +2722,47 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
2718
2722
|
handlers.forgetExposedTunnel?.(params.name);
|
|
2719
2723
|
return { name: params.name, stopped: true };
|
|
2720
2724
|
},
|
|
2721
|
-
/**
|
|
2725
|
+
/**
|
|
2726
|
+
* List the full CONFIGURED set of daemon-managed tunnels with a
|
|
2727
|
+
* derived per-tunnel `state`, not just the ones currently live. The
|
|
2728
|
+
* configured set comes from the persisted specs (survives restarts +
|
|
2729
|
+
* mid-recreate gaps); each is joined with its live FrpcTunnel status
|
|
2730
|
+
* if present. A tunnel that's persisted but not live (failed restore,
|
|
2731
|
+
* recreating) shows up as `reconnecting` instead of silently vanishing.
|
|
2732
|
+
*/
|
|
2722
2733
|
tunnelList: async (context) => {
|
|
2723
2734
|
authorizeRequest(context, currentMetadata.sharing, "view");
|
|
2724
2735
|
const tunnels = handlers.tunnels;
|
|
2725
2736
|
if (!tunnels) return [];
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2737
|
+
const specs = handlers.listExposedTunnels?.() ?? [];
|
|
2738
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2739
|
+
const rows = [];
|
|
2740
|
+
const stateOf = (s) => {
|
|
2741
|
+
if (!s) return "reconnecting";
|
|
2742
|
+
if (s.probe && !s.probe.ok) return "failed";
|
|
2743
|
+
if (s.connected) return "connected";
|
|
2744
|
+
return s.restartAttempts > 0 ? "reconnecting" : "failed";
|
|
2745
|
+
};
|
|
2746
|
+
for (const spec of specs) {
|
|
2747
|
+
seen.add(spec.name);
|
|
2748
|
+
const tunnel = tunnels.get(spec.name);
|
|
2749
|
+
const status = tunnel ? tunnel.status : null;
|
|
2750
|
+
rows.push({
|
|
2751
|
+
name: spec.name,
|
|
2752
|
+
ports: spec.ports,
|
|
2753
|
+
group: spec.group,
|
|
2754
|
+
configured: true,
|
|
2755
|
+
live: !!tunnel,
|
|
2756
|
+
state: stateOf(status),
|
|
2757
|
+
...status ?? {}
|
|
2758
|
+
});
|
|
2759
|
+
}
|
|
2760
|
+
for (const [name, tunnel] of tunnels) {
|
|
2761
|
+
if (seen.has(name)) continue;
|
|
2762
|
+
const status = tunnel.status;
|
|
2763
|
+
rows.push({ ...status, name, configured: false, live: true, state: stateOf(status) });
|
|
2764
|
+
}
|
|
2765
|
+
return rows;
|
|
2729
2766
|
},
|
|
2730
2767
|
// ── Shared static file server ────────────────────────────────────
|
|
2731
2768
|
/** Add a mount to the shared static file server. */
|
|
@@ -2938,7 +2975,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
|
|
|
2938
2975
|
}
|
|
2939
2976
|
const deps = buildSessionDeps(rpc, { cwd, ownerEmail: owner });
|
|
2940
2977
|
const sender = { name: context?.user?.email || context?.user?.id || "user", kind: "user", verified: true };
|
|
2941
|
-
const { toolsForRole } = await import('./sideband-
|
|
2978
|
+
const { toolsForRole } = await import('./sideband-BnEpfp8h.mjs');
|
|
2942
2979
|
const r2 = await runWiseAgent({ message: params.message, sender, config: { tools: toolsForRole(role2) }, deps, transport, model: resolved.model });
|
|
2943
2980
|
return fmt(r2);
|
|
2944
2981
|
}
|
|
@@ -3037,7 +3074,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
|
|
|
3037
3074
|
if (r.error || !r.sender) return { error: r.error || "unauthorized" };
|
|
3038
3075
|
const callId = "call_" + Math.random().toString(16).slice(2, 12);
|
|
3039
3076
|
const rendered = renderMessage(c, { sender: r.sender, body: { message: kwargs.message }, callId });
|
|
3040
|
-
const { queryCore } = await import('./commands-
|
|
3077
|
+
const { queryCore } = await import('./commands-CP0LaCNP.mjs');
|
|
3041
3078
|
const timeout = c.reply?.timeout_sec || 120;
|
|
3042
3079
|
let result;
|
|
3043
3080
|
try {
|
|
@@ -3519,9 +3556,20 @@ function patchStoredText(msg, newText) {
|
|
|
3519
3556
|
return true;
|
|
3520
3557
|
}
|
|
3521
3558
|
if (data?.type === "assistant" && Array.isArray(data?.message?.content)) {
|
|
3522
|
-
const
|
|
3523
|
-
|
|
3559
|
+
const content = data.message.content;
|
|
3560
|
+
const isText = (b) => b && b.type === "text" && typeof b.text === "string";
|
|
3561
|
+
const textBlocks = content.filter(isText);
|
|
3562
|
+
if (textBlocks.length >= 1) {
|
|
3524
3563
|
textBlocks[0].text = newText;
|
|
3564
|
+
let seen = false;
|
|
3565
|
+
data.message.content = content.filter((b) => {
|
|
3566
|
+
if (!isText(b)) return true;
|
|
3567
|
+
if (!seen) {
|
|
3568
|
+
seen = true;
|
|
3569
|
+
return true;
|
|
3570
|
+
}
|
|
3571
|
+
return false;
|
|
3572
|
+
});
|
|
3525
3573
|
return true;
|
|
3526
3574
|
}
|
|
3527
3575
|
}
|
|
@@ -7734,11 +7782,21 @@ function applyTranscriptEdit(file, index, newText) {
|
|
|
7734
7782
|
if (target.type === "assistant") {
|
|
7735
7783
|
const content = target?.message?.content;
|
|
7736
7784
|
if (!Array.isArray(content)) return { ok: false, reason: "assistant content is not a block array" };
|
|
7737
|
-
const
|
|
7738
|
-
|
|
7739
|
-
|
|
7785
|
+
const isText = (b) => b && b.type === "text" && typeof b.text === "string";
|
|
7786
|
+
const textBlocks = content.filter(isText);
|
|
7787
|
+
if (textBlocks.length === 0) {
|
|
7788
|
+
return { ok: false, reason: "expected at least 1 text block, found 0" };
|
|
7740
7789
|
}
|
|
7741
7790
|
textBlocks[0].text = newText;
|
|
7791
|
+
let seen = false;
|
|
7792
|
+
target.message.content = content.filter((b) => {
|
|
7793
|
+
if (!isText(b)) return true;
|
|
7794
|
+
if (!seen) {
|
|
7795
|
+
seen = true;
|
|
7796
|
+
return true;
|
|
7797
|
+
}
|
|
7798
|
+
return false;
|
|
7799
|
+
});
|
|
7742
7800
|
} else if (target.type === "user") {
|
|
7743
7801
|
if (typeof target?.message?.content !== "string") {
|
|
7744
7802
|
return { ok: false, reason: "user content is not a string" };
|
|
@@ -11328,7 +11386,28 @@ async function startDaemon(options) {
|
|
|
11328
11386
|
const list = loadExposedTunnels().filter((t) => t.name !== name);
|
|
11329
11387
|
saveExposedTunnels(list);
|
|
11330
11388
|
}
|
|
11331
|
-
|
|
11389
|
+
async function createExposedTunnel(spec) {
|
|
11390
|
+
const { FrpcTunnel } = await import('./frpc-DjCP6NoG.mjs');
|
|
11391
|
+
const tunnel = new FrpcTunnel({
|
|
11392
|
+
name: spec.name,
|
|
11393
|
+
ports: spec.ports,
|
|
11394
|
+
group: spec.group,
|
|
11395
|
+
groupKey: spec.groupKey,
|
|
11396
|
+
healthCheckType: spec.healthCheckType,
|
|
11397
|
+
healthCheckPath: spec.healthCheckPath,
|
|
11398
|
+
healthCheckInterval: spec.healthCheckInterval,
|
|
11399
|
+
// Backend-agnostic ghost/stuck-proxy detection via frpc's loopback
|
|
11400
|
+
// admin API — exposed backends rarely have an HTTP health endpoint.
|
|
11401
|
+
adminStatus: true,
|
|
11402
|
+
onError: (err) => logger.log(`[FRPC ${spec.name}] ${err.message}`),
|
|
11403
|
+
onConnect: () => logger.log(`[FRPC ${spec.name}] connected`),
|
|
11404
|
+
onDisconnect: () => logger.log(`[FRPC ${spec.name}] disconnected, will auto-reconnect`)
|
|
11405
|
+
});
|
|
11406
|
+
await tunnel.connect();
|
|
11407
|
+
return tunnel;
|
|
11408
|
+
}
|
|
11409
|
+
const tunnelRecreateState = /* @__PURE__ */ new Map();
|
|
11410
|
+
const { ServeManager } = await import('./serveManager-D7_YZY-E.mjs');
|
|
11332
11411
|
const serveManager = new ServeManager(SVAMP_HOME, (msg) => logger.log(`[SERVE] ${msg}`), hyphaServerUrl);
|
|
11333
11412
|
ensureAutoInstalledSkills(logger).catch(() => {
|
|
11334
11413
|
});
|
|
@@ -13988,7 +14067,8 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
13988
14067
|
serveManager,
|
|
13989
14068
|
sharingNotificationSync,
|
|
13990
14069
|
persistExposedTunnel,
|
|
13991
|
-
forgetExposedTunnel
|
|
14070
|
+
forgetExposedTunnel,
|
|
14071
|
+
listExposedTunnels: () => loadExposedTunnels().map((t) => ({ name: t.name, ports: t.ports, group: t.group, addedAt: t.addedAt }))
|
|
13992
14072
|
}
|
|
13993
14073
|
);
|
|
13994
14074
|
logger.log(`Machine service registered: svamp-machine-${machineId}`);
|
|
@@ -14016,23 +14096,10 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
14016
14096
|
const specs = loadExposedTunnels();
|
|
14017
14097
|
if (specs.length === 0) return;
|
|
14018
14098
|
logger.log(`[exposed-tunnels] Restoring ${specs.length} tunnel(s) from ${EXPOSED_TUNNELS_FILE}`);
|
|
14019
|
-
const { FrpcTunnel } = await import('./frpc-BpBOWRbL.mjs');
|
|
14020
14099
|
for (const spec of specs) {
|
|
14021
14100
|
if (tunnels.has(spec.name)) continue;
|
|
14022
14101
|
try {
|
|
14023
|
-
const tunnel =
|
|
14024
|
-
name: spec.name,
|
|
14025
|
-
ports: spec.ports,
|
|
14026
|
-
group: spec.group,
|
|
14027
|
-
groupKey: spec.groupKey,
|
|
14028
|
-
healthCheckType: spec.healthCheckType,
|
|
14029
|
-
healthCheckPath: spec.healthCheckPath,
|
|
14030
|
-
healthCheckInterval: spec.healthCheckInterval,
|
|
14031
|
-
onError: (err) => logger.log(`[FRPC ${spec.name}] ${err.message}`),
|
|
14032
|
-
onConnect: () => logger.log(`[FRPC ${spec.name}] connected (restored)`),
|
|
14033
|
-
onDisconnect: () => logger.log(`[FRPC ${spec.name}] disconnected, will auto-reconnect`)
|
|
14034
|
-
});
|
|
14035
|
-
await tunnel.connect();
|
|
14102
|
+
const tunnel = await createExposedTunnel(spec);
|
|
14036
14103
|
tunnels.set(spec.name, tunnel);
|
|
14037
14104
|
logger.log(`[exposed-tunnels] Restored: ${spec.name} \u2192 ports ${spec.ports.join(",")}`);
|
|
14038
14105
|
} catch (err) {
|
|
@@ -14124,7 +14191,8 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
14124
14191
|
}
|
|
14125
14192
|
if (persistedSessions.length > 0) {
|
|
14126
14193
|
logger.log(`Restoring ${persistedSessions.length} persisted session(s)...`);
|
|
14127
|
-
|
|
14194
|
+
const restoreConcurrency = Math.max(1, parseInt(process.env.SVAMP_RESTORE_CONCURRENCY || "8", 10) || 8);
|
|
14195
|
+
const restoreOne = async (persisted) => {
|
|
14128
14196
|
try {
|
|
14129
14197
|
const isOrphaned = persisted.machineId && persisted.machineId !== machineId;
|
|
14130
14198
|
if (isOrphaned) {
|
|
@@ -14175,7 +14243,19 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
14175
14243
|
} catch (err) {
|
|
14176
14244
|
logger.error(`Error restoring session ${persisted.sessionId}:`, err.message);
|
|
14177
14245
|
}
|
|
14178
|
-
}
|
|
14246
|
+
};
|
|
14247
|
+
let restoreCursor = 0;
|
|
14248
|
+
const restoreWorker = async () => {
|
|
14249
|
+
while (restoreCursor < persistedSessions.length) {
|
|
14250
|
+
const persisted = persistedSessions[restoreCursor++];
|
|
14251
|
+
await restoreOne(persisted);
|
|
14252
|
+
}
|
|
14253
|
+
};
|
|
14254
|
+
const t0 = Date.now();
|
|
14255
|
+
await Promise.all(
|
|
14256
|
+
Array.from({ length: Math.min(restoreConcurrency, persistedSessions.length) }, () => restoreWorker())
|
|
14257
|
+
);
|
|
14258
|
+
logger.log(`Restored ${persistedSessions.length} session(s) in ${Date.now() - t0}ms (concurrency ${restoreConcurrency})`);
|
|
14179
14259
|
}
|
|
14180
14260
|
if (sessionsToAutoContinue.length > 0 && !options?.noAutoContinue) {
|
|
14181
14261
|
logger.log(`Auto-continuing ${sessionsToAutoContinue.length} interrupted session(s)...`);
|
|
@@ -14390,11 +14470,39 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
14390
14470
|
for (const [name, tunnel] of tunnels) {
|
|
14391
14471
|
const health = tunnel.status;
|
|
14392
14472
|
const reason = tunnelLooksDead(health);
|
|
14393
|
-
if (reason) {
|
|
14394
|
-
|
|
14395
|
-
|
|
14473
|
+
if (!reason) {
|
|
14474
|
+
tunnelRecreateState.delete(name);
|
|
14475
|
+
continue;
|
|
14476
|
+
}
|
|
14477
|
+
const spec = loadExposedTunnels().find((t) => t.name === name);
|
|
14478
|
+
if (!spec) {
|
|
14479
|
+
logger.log(`frpc tunnel '${name}' ${reason}, no persisted spec \u2014 destroying (cannot recreate)`);
|
|
14480
|
+
try {
|
|
14481
|
+
tunnel.destroy();
|
|
14482
|
+
} catch {
|
|
14483
|
+
}
|
|
14396
14484
|
tunnels.delete(name);
|
|
14485
|
+
tunnelRecreateState.delete(name);
|
|
14486
|
+
continue;
|
|
14397
14487
|
}
|
|
14488
|
+
const now = Date.now();
|
|
14489
|
+
const st = tunnelRecreateState.get(name) ?? { nextAttemptAt: 0, attempts: 0 };
|
|
14490
|
+
if (now < st.nextAttemptAt) continue;
|
|
14491
|
+
st.attempts++;
|
|
14492
|
+
st.nextAttemptAt = now + Math.min(15e3 * Math.pow(2, st.attempts - 1), 5 * 6e4);
|
|
14493
|
+
tunnelRecreateState.set(name, st);
|
|
14494
|
+
logger.log(`frpc tunnel '${name}' ${reason} \u2014 recreating (attempt ${st.attempts})`);
|
|
14495
|
+
try {
|
|
14496
|
+
tunnel.destroy();
|
|
14497
|
+
} catch {
|
|
14498
|
+
}
|
|
14499
|
+
tunnels.delete(name);
|
|
14500
|
+
createExposedTunnel(spec).then((fresh) => {
|
|
14501
|
+
tunnels.set(name, fresh);
|
|
14502
|
+
logger.log(`frpc tunnel '${name}' recreated`);
|
|
14503
|
+
}).catch((err) => {
|
|
14504
|
+
logger.log(`frpc tunnel '${name}' recreate failed: ${err.message} (will retry)`);
|
|
14505
|
+
});
|
|
14398
14506
|
}
|
|
14399
14507
|
} finally {
|
|
14400
14508
|
heartbeatRunning = false;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import { X as generateFriendlyName, m as shortId, c as connectToHypha, a as createSessionStore, r as registerMachineService, Y as generateHookSettings } from './run-
|
|
1
|
+
import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import { X as generateFriendlyName, m as shortId, c as connectToHypha, a as createSessionStore, r as registerMachineService, Y as generateHookSettings } from './run-BIwWpHSR.mjs';
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import { resolve, join } from 'node:path';
|
|
4
4
|
import { existsSync, readFileSync, watch } from 'node:fs';
|
|
@@ -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-CP0LaCNP.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-CP0LaCNP.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-CP0LaCNP.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-CP0LaCNP.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-CP0LaCNP.mjs');
|
|
239
239
|
const { machine, server } = await connectAndGetMachine(machineId);
|
|
240
240
|
try {
|
|
241
241
|
const info = await machine.serveInfo();
|
|
@@ -4,7 +4,7 @@ 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 { k as getHyphaServerUrl, S as ServeAuth, l as hasCookieToken } from './run-
|
|
7
|
+
import { k as getHyphaServerUrl, S as ServeAuth, l as hasCookieToken } from './run-BIwWpHSR.mjs';
|
|
8
8
|
import 'os';
|
|
9
9
|
import 'fs/promises';
|
|
10
10
|
import 'url';
|
|
@@ -713,7 +713,7 @@ class ServeManager {
|
|
|
713
713
|
const mount = this.mounts.get(mountName);
|
|
714
714
|
const subdomainOverride = mount?.access === "link" && mount.linkToken ? /* @__PURE__ */ new Map([[this.port, `static-${subdomainSafe}-${mount.linkToken}`]]) : void 0;
|
|
715
715
|
try {
|
|
716
|
-
const { FrpcTunnel } = await import('./frpc-
|
|
716
|
+
const { FrpcTunnel } = await import('./frpc-DjCP6NoG.mjs');
|
|
717
717
|
let tunnel;
|
|
718
718
|
tunnel = new FrpcTunnel({
|
|
719
719
|
name: tunnelName,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { R as READ_ONLY_TOOLS, z as loadMachineContext, A as buildMachineInstructions, B as machineToolsForRole, C as buildMachineTools } from './run-
|
|
1
|
+
import { R as READ_ONLY_TOOLS, z as loadMachineContext, A as buildMachineInstructions, B as machineToolsForRole, C as buildMachineTools } from './run-BIwWpHSR.mjs';
|
|
2
2
|
import 'node:child_process';
|
|
3
3
|
import 'os';
|
|
4
4
|
import 'fs/promises';
|