svamp-cli 0.2.22 → 0.2.23
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-C32VYCxV.mjs → agentCommands-rofwcLx3.mjs} +2 -2
- package/dist/cli.mjs +30 -30
- package/dist/{commands-DGsQyrpg.mjs → commands-CqULIXFK.mjs} +41 -16
- package/dist/{commands-6ottz7I-.mjs → commands-DCI1dZuS.mjs} +2 -2
- package/dist/{commands-CNDLej2C.mjs → commands-DrNOSpki.mjs} +1 -1
- package/dist/{frpc-Dz3UhcgJ.mjs → frpc-qqYQ6F9T.mjs} +54 -19
- package/dist/index.mjs +1 -1
- package/dist/{package-6Bo1dVcf.mjs → package-D-GTa0i_.mjs} +1 -1
- package/dist/{run-B64CzU72.mjs → run-Ckm62Pws.mjs} +1 -1
- package/dist/{run-CQfp9fM9.mjs → run-YVIJdP0j.mjs} +2 -2
- package/dist/{serveCommands-C515r-sl.mjs → serveCommands-CCbnvtwL.mjs} +4 -4
- package/dist/{serveManager-6vRqOXK_.mjs → serveManager-Cgbl706Q.mjs} +1 -1
- package/package.json +1 -1
|
@@ -148,7 +148,7 @@ async function sessionBroadcast(action, args) {
|
|
|
148
148
|
console.log(`Broadcast sent: ${action}`);
|
|
149
149
|
}
|
|
150
150
|
async function connectToMachineService() {
|
|
151
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
151
|
+
const { connectAndGetMachine } = await import('./commands-DrNOSpki.mjs');
|
|
152
152
|
return connectAndGetMachine();
|
|
153
153
|
}
|
|
154
154
|
async function inboxSend(targetSessionId, opts) {
|
|
@@ -165,7 +165,7 @@ async function inboxSend(targetSessionId, opts) {
|
|
|
165
165
|
}
|
|
166
166
|
const { server, machine } = await connectToMachineService();
|
|
167
167
|
try {
|
|
168
|
-
const { resolveSessionId } = await import('./commands-
|
|
168
|
+
const { resolveSessionId } = await import('./commands-DrNOSpki.mjs');
|
|
169
169
|
const sessions = await machine.listSessions();
|
|
170
170
|
const match = resolveSessionId(sessions, targetSessionId);
|
|
171
171
|
const fullTargetId = match.sessionId;
|
package/dist/cli.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { s as startDaemon, b as stopDaemon, d as daemonStatus } from './run-
|
|
1
|
+
import { s as startDaemon, b as stopDaemon, d as daemonStatus } from './run-YVIJdP0j.mjs';
|
|
2
2
|
import 'os';
|
|
3
3
|
import 'fs/promises';
|
|
4
4
|
import 'fs';
|
|
@@ -36,7 +36,7 @@ async function main() {
|
|
|
36
36
|
await logoutFromHypha();
|
|
37
37
|
} else if (subcommand === "daemon") {
|
|
38
38
|
if (daemonSubcommand === "restart") {
|
|
39
|
-
const { restartDaemon } = await import('./run-
|
|
39
|
+
const { restartDaemon } = await import('./run-YVIJdP0j.mjs').then(function (n) { return n.k; });
|
|
40
40
|
await restartDaemon();
|
|
41
41
|
process.exit(0);
|
|
42
42
|
}
|
|
@@ -238,7 +238,7 @@ async function main() {
|
|
|
238
238
|
console.error("svamp service: Service commands are not available in sandboxed sessions.");
|
|
239
239
|
process.exit(1);
|
|
240
240
|
}
|
|
241
|
-
const { handleServiceCommand } = await import('./commands-
|
|
241
|
+
const { handleServiceCommand } = await import('./commands-CqULIXFK.mjs');
|
|
242
242
|
await handleServiceCommand();
|
|
243
243
|
} else if (subcommand === "serve") {
|
|
244
244
|
const { isSandboxed: isSandboxedServe } = await import('./sandboxDetect-DNTcbgWD.mjs');
|
|
@@ -246,7 +246,7 @@ async function main() {
|
|
|
246
246
|
console.error("svamp serve: Serve commands are not available in sandboxed sessions.");
|
|
247
247
|
process.exit(1);
|
|
248
248
|
}
|
|
249
|
-
const { handleServeCommand } = await import('./serveCommands-
|
|
249
|
+
const { handleServeCommand } = await import('./serveCommands-CCbnvtwL.mjs');
|
|
250
250
|
await handleServeCommand();
|
|
251
251
|
process.exit(0);
|
|
252
252
|
} else if (subcommand === "process" || subcommand === "proc") {
|
|
@@ -255,7 +255,7 @@ async function main() {
|
|
|
255
255
|
console.error("svamp process: Process commands are not available in sandboxed sessions.");
|
|
256
256
|
process.exit(1);
|
|
257
257
|
}
|
|
258
|
-
const { processCommand } = await import('./commands-
|
|
258
|
+
const { processCommand } = await import('./commands-DCI1dZuS.mjs');
|
|
259
259
|
let machineId;
|
|
260
260
|
const processArgs = args.slice(1);
|
|
261
261
|
const mIdx = processArgs.findIndex((a) => a === "--machine" || a === "-m");
|
|
@@ -273,7 +273,7 @@ async function main() {
|
|
|
273
273
|
} else if (!subcommand || subcommand === "start") {
|
|
274
274
|
await handleInteractiveCommand();
|
|
275
275
|
} else if (subcommand === "--version" || subcommand === "-v") {
|
|
276
|
-
const pkg = await import('./package-
|
|
276
|
+
const pkg = await import('./package-D-GTa0i_.mjs').catch(() => ({ default: { version: "unknown" } }));
|
|
277
277
|
console.log(`svamp version: ${pkg.default.version}`);
|
|
278
278
|
} else {
|
|
279
279
|
console.error(`Unknown command: ${subcommand}`);
|
|
@@ -282,7 +282,7 @@ async function main() {
|
|
|
282
282
|
}
|
|
283
283
|
}
|
|
284
284
|
async function handleInteractiveCommand() {
|
|
285
|
-
const { runInteractive } = await import('./run-
|
|
285
|
+
const { runInteractive } = await import('./run-Ckm62Pws.mjs');
|
|
286
286
|
const interactiveArgs = subcommand === "start" ? args.slice(1) : args;
|
|
287
287
|
let directory = process.cwd();
|
|
288
288
|
let resumeSessionId;
|
|
@@ -327,7 +327,7 @@ async function handleAgentCommand() {
|
|
|
327
327
|
return;
|
|
328
328
|
}
|
|
329
329
|
if (agentArgs[0] === "list") {
|
|
330
|
-
const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-
|
|
330
|
+
const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-YVIJdP0j.mjs').then(function (n) { return n.i; });
|
|
331
331
|
console.log("Known agents:");
|
|
332
332
|
for (const [name, config2] of Object.entries(KNOWN_ACP_AGENTS)) {
|
|
333
333
|
console.log(` ${name.padEnd(12)} ${config2.command} ${config2.args.join(" ")} (ACP)`);
|
|
@@ -339,7 +339,7 @@ async function handleAgentCommand() {
|
|
|
339
339
|
console.log('Use "svamp agent -- <command> [args]" for a custom ACP agent.');
|
|
340
340
|
return;
|
|
341
341
|
}
|
|
342
|
-
const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-
|
|
342
|
+
const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-YVIJdP0j.mjs').then(function (n) { return n.i; });
|
|
343
343
|
let cwd = process.cwd();
|
|
344
344
|
const filteredArgs = [];
|
|
345
345
|
for (let i = 0; i < agentArgs.length; i++) {
|
|
@@ -363,12 +363,12 @@ async function handleAgentCommand() {
|
|
|
363
363
|
console.log(`Starting ${config.agentName} agent in ${cwd}...`);
|
|
364
364
|
let backend;
|
|
365
365
|
if (KNOWN_MCP_AGENTS[config.agentName]) {
|
|
366
|
-
const { CodexMcpBackend } = await import('./run-
|
|
366
|
+
const { CodexMcpBackend } = await import('./run-YVIJdP0j.mjs').then(function (n) { return n.j; });
|
|
367
367
|
backend = new CodexMcpBackend({ cwd, log: logFn });
|
|
368
368
|
} else {
|
|
369
|
-
const { AcpBackend } = await import('./run-
|
|
370
|
-
const { GeminiTransport } = await import('./run-
|
|
371
|
-
const { DefaultTransport } = await import('./run-
|
|
369
|
+
const { AcpBackend } = await import('./run-YVIJdP0j.mjs').then(function (n) { return n.h; });
|
|
370
|
+
const { GeminiTransport } = await import('./run-YVIJdP0j.mjs').then(function (n) { return n.G; });
|
|
371
|
+
const { DefaultTransport } = await import('./run-YVIJdP0j.mjs').then(function (n) { return n.D; });
|
|
372
372
|
const transportHandler = config.agentName === "gemini" ? new GeminiTransport() : new DefaultTransport(config.agentName);
|
|
373
373
|
backend = new AcpBackend({
|
|
374
374
|
agentName: config.agentName,
|
|
@@ -495,7 +495,7 @@ async function handleSessionCommand() {
|
|
|
495
495
|
process.exit(1);
|
|
496
496
|
}
|
|
497
497
|
}
|
|
498
|
-
const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionInboxSend, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxClear } = await import('./commands-
|
|
498
|
+
const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionInboxSend, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxClear } = await import('./commands-DrNOSpki.mjs');
|
|
499
499
|
const parseFlagStr = (flag, shortFlag) => {
|
|
500
500
|
for (let i = 1; i < sessionArgs.length; i++) {
|
|
501
501
|
if ((sessionArgs[i] === flag || shortFlag) && i + 1 < sessionArgs.length) {
|
|
@@ -555,7 +555,7 @@ async function handleSessionCommand() {
|
|
|
555
555
|
allowDomain.push(sessionArgs[++i]);
|
|
556
556
|
}
|
|
557
557
|
}
|
|
558
|
-
const { parseShareArg } = await import('./commands-
|
|
558
|
+
const { parseShareArg } = await import('./commands-DrNOSpki.mjs');
|
|
559
559
|
const shareEntries = share.map((s) => parseShareArg(s));
|
|
560
560
|
await sessionSpawn(agent, dir, targetMachineId, {
|
|
561
561
|
message,
|
|
@@ -641,7 +641,7 @@ async function handleSessionCommand() {
|
|
|
641
641
|
console.error("Usage: svamp session approve <session-id> [request-id] [--json]");
|
|
642
642
|
process.exit(1);
|
|
643
643
|
}
|
|
644
|
-
const { sessionApprove } = await import('./commands-
|
|
644
|
+
const { sessionApprove } = await import('./commands-DrNOSpki.mjs');
|
|
645
645
|
const approveReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
|
|
646
646
|
await sessionApprove(sessionArgs[1], approveReqId, targetMachineId, {
|
|
647
647
|
json: hasFlag("--json")
|
|
@@ -651,7 +651,7 @@ async function handleSessionCommand() {
|
|
|
651
651
|
console.error("Usage: svamp session deny <session-id> [request-id] [--json]");
|
|
652
652
|
process.exit(1);
|
|
653
653
|
}
|
|
654
|
-
const { sessionDeny } = await import('./commands-
|
|
654
|
+
const { sessionDeny } = await import('./commands-DrNOSpki.mjs');
|
|
655
655
|
const denyReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
|
|
656
656
|
await sessionDeny(sessionArgs[1], denyReqId, targetMachineId, {
|
|
657
657
|
json: hasFlag("--json")
|
|
@@ -687,7 +687,7 @@ async function handleSessionCommand() {
|
|
|
687
687
|
console.error("Usage: svamp session set-title <title>");
|
|
688
688
|
process.exit(1);
|
|
689
689
|
}
|
|
690
|
-
const { sessionSetTitle } = await import('./agentCommands-
|
|
690
|
+
const { sessionSetTitle } = await import('./agentCommands-rofwcLx3.mjs');
|
|
691
691
|
await sessionSetTitle(title);
|
|
692
692
|
} else if (sessionSubcommand === "set-link") {
|
|
693
693
|
const url = sessionArgs[1];
|
|
@@ -696,7 +696,7 @@ async function handleSessionCommand() {
|
|
|
696
696
|
process.exit(1);
|
|
697
697
|
}
|
|
698
698
|
const label = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
|
|
699
|
-
const { sessionSetLink } = await import('./agentCommands-
|
|
699
|
+
const { sessionSetLink } = await import('./agentCommands-rofwcLx3.mjs');
|
|
700
700
|
await sessionSetLink(url, label);
|
|
701
701
|
} else if (sessionSubcommand === "notify") {
|
|
702
702
|
const message = sessionArgs[1];
|
|
@@ -705,7 +705,7 @@ async function handleSessionCommand() {
|
|
|
705
705
|
process.exit(1);
|
|
706
706
|
}
|
|
707
707
|
const level = parseFlagStr("--level") || "info";
|
|
708
|
-
const { sessionNotify } = await import('./agentCommands-
|
|
708
|
+
const { sessionNotify } = await import('./agentCommands-rofwcLx3.mjs');
|
|
709
709
|
await sessionNotify(message, level);
|
|
710
710
|
} else if (sessionSubcommand === "broadcast") {
|
|
711
711
|
const action = sessionArgs[1];
|
|
@@ -713,7 +713,7 @@ async function handleSessionCommand() {
|
|
|
713
713
|
console.error("Usage: svamp session broadcast <action> [args...]\nActions: open-canvas <url> [label], close-canvas, toast <message>");
|
|
714
714
|
process.exit(1);
|
|
715
715
|
}
|
|
716
|
-
const { sessionBroadcast } = await import('./agentCommands-
|
|
716
|
+
const { sessionBroadcast } = await import('./agentCommands-rofwcLx3.mjs');
|
|
717
717
|
await sessionBroadcast(action, sessionArgs.slice(2).filter((a) => !a.startsWith("--")));
|
|
718
718
|
} else if (sessionSubcommand === "inbox") {
|
|
719
719
|
const inboxSubcmd = sessionArgs[1];
|
|
@@ -724,7 +724,7 @@ async function handleSessionCommand() {
|
|
|
724
724
|
process.exit(1);
|
|
725
725
|
}
|
|
726
726
|
if (agentSessionId) {
|
|
727
|
-
const { inboxSend } = await import('./agentCommands-
|
|
727
|
+
const { inboxSend } = await import('./agentCommands-rofwcLx3.mjs');
|
|
728
728
|
await inboxSend(sessionArgs[2], {
|
|
729
729
|
body: sessionArgs[3],
|
|
730
730
|
subject: parseFlagStr("--subject"),
|
|
@@ -739,7 +739,7 @@ async function handleSessionCommand() {
|
|
|
739
739
|
}
|
|
740
740
|
} else if (inboxSubcmd === "list" || inboxSubcmd === "ls") {
|
|
741
741
|
if (agentSessionId && !sessionArgs[2]) {
|
|
742
|
-
const { inboxList } = await import('./agentCommands-
|
|
742
|
+
const { inboxList } = await import('./agentCommands-rofwcLx3.mjs');
|
|
743
743
|
await inboxList({
|
|
744
744
|
unread: hasFlag("--unread"),
|
|
745
745
|
limit: parseFlagInt("--limit"),
|
|
@@ -761,7 +761,7 @@ async function handleSessionCommand() {
|
|
|
761
761
|
process.exit(1);
|
|
762
762
|
}
|
|
763
763
|
if (agentSessionId && !sessionArgs[3]) {
|
|
764
|
-
const { inboxList } = await import('./agentCommands-
|
|
764
|
+
const { inboxList } = await import('./agentCommands-rofwcLx3.mjs');
|
|
765
765
|
await sessionInboxRead(agentSessionId, sessionArgs[2], targetMachineId);
|
|
766
766
|
} else if (sessionArgs[3]) {
|
|
767
767
|
await sessionInboxRead(sessionArgs[2], sessionArgs[3], targetMachineId);
|
|
@@ -771,7 +771,7 @@ async function handleSessionCommand() {
|
|
|
771
771
|
}
|
|
772
772
|
} else if (inboxSubcmd === "reply") {
|
|
773
773
|
if (agentSessionId && sessionArgs[2] && sessionArgs[3] && !sessionArgs[4]) {
|
|
774
|
-
const { inboxReply } = await import('./agentCommands-
|
|
774
|
+
const { inboxReply } = await import('./agentCommands-rofwcLx3.mjs');
|
|
775
775
|
await inboxReply(sessionArgs[2], sessionArgs[3]);
|
|
776
776
|
} else if (sessionArgs[2] && sessionArgs[3] && sessionArgs[4]) {
|
|
777
777
|
await sessionInboxReply(sessionArgs[2], sessionArgs[3], sessionArgs[4], targetMachineId);
|
|
@@ -807,7 +807,7 @@ async function handleMachineCommand() {
|
|
|
807
807
|
return;
|
|
808
808
|
}
|
|
809
809
|
if (machineSubcommand === "share") {
|
|
810
|
-
const { machineShare } = await import('./commands-
|
|
810
|
+
const { machineShare } = await import('./commands-DrNOSpki.mjs');
|
|
811
811
|
let machineId;
|
|
812
812
|
const shareArgs = [];
|
|
813
813
|
for (let i = 1; i < machineArgs.length; i++) {
|
|
@@ -837,7 +837,7 @@ async function handleMachineCommand() {
|
|
|
837
837
|
}
|
|
838
838
|
await machineShare(machineId, { add, remove, list, configPath, showConfig });
|
|
839
839
|
} else if (machineSubcommand === "exec") {
|
|
840
|
-
const { machineExec } = await import('./commands-
|
|
840
|
+
const { machineExec } = await import('./commands-DrNOSpki.mjs');
|
|
841
841
|
let machineId;
|
|
842
842
|
let cwd;
|
|
843
843
|
const cmdParts = [];
|
|
@@ -857,7 +857,7 @@ async function handleMachineCommand() {
|
|
|
857
857
|
}
|
|
858
858
|
await machineExec(machineId, command, cwd);
|
|
859
859
|
} else if (machineSubcommand === "info") {
|
|
860
|
-
const { machineInfo } = await import('./commands-
|
|
860
|
+
const { machineInfo } = await import('./commands-DrNOSpki.mjs');
|
|
861
861
|
let machineId;
|
|
862
862
|
for (let i = 1; i < machineArgs.length; i++) {
|
|
863
863
|
if ((machineArgs[i] === "--machine" || machineArgs[i] === "-m") && i + 1 < machineArgs.length) {
|
|
@@ -877,10 +877,10 @@ async function handleMachineCommand() {
|
|
|
877
877
|
level = machineArgs[++i];
|
|
878
878
|
}
|
|
879
879
|
}
|
|
880
|
-
const { machineNotify } = await import('./agentCommands-
|
|
880
|
+
const { machineNotify } = await import('./agentCommands-rofwcLx3.mjs');
|
|
881
881
|
await machineNotify(message, level);
|
|
882
882
|
} else if (machineSubcommand === "ls") {
|
|
883
|
-
const { machineLs } = await import('./commands-
|
|
883
|
+
const { machineLs } = await import('./commands-DrNOSpki.mjs');
|
|
884
884
|
let machineId;
|
|
885
885
|
let showHidden = false;
|
|
886
886
|
let path;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import * as path from 'path';
|
|
2
2
|
|
|
3
|
+
function getFlag(args, flag) {
|
|
4
|
+
const idx = args.indexOf(flag);
|
|
5
|
+
return idx !== -1 && idx + 1 < args.length ? args[idx + 1] : void 0;
|
|
6
|
+
}
|
|
3
7
|
function getAllFlags(args, flag) {
|
|
4
8
|
const values = [];
|
|
5
9
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -44,12 +48,23 @@ async function serviceExpose(args) {
|
|
|
44
48
|
const positional = positionalArgs(args);
|
|
45
49
|
const name = positional[0];
|
|
46
50
|
const ports = parsePorts(args);
|
|
51
|
+
const group = getFlag(args, "--group");
|
|
52
|
+
const groupKey = getFlag(args, "--group-key");
|
|
53
|
+
const healthCheck = getFlag(args, "--health-check");
|
|
54
|
+
const healthPath = getFlag(args, "--health-path");
|
|
55
|
+
const healthInterval = getFlag(args, "--health-interval");
|
|
47
56
|
if (!name || ports.length === 0) {
|
|
48
|
-
console.error("Usage: svamp service expose <name> --port <port> [--port <port2>]");
|
|
57
|
+
console.error("Usage: svamp service expose <name> --port <port> [--port <port2>] [options]");
|
|
49
58
|
process.exit(1);
|
|
50
59
|
}
|
|
51
|
-
const { runFrpcTunnel } = await import('./frpc-
|
|
52
|
-
await runFrpcTunnel(name, ports
|
|
60
|
+
const { runFrpcTunnel } = await import('./frpc-qqYQ6F9T.mjs');
|
|
61
|
+
await runFrpcTunnel(name, ports, void 0, {
|
|
62
|
+
group,
|
|
63
|
+
groupKey,
|
|
64
|
+
healthCheckType: healthCheck,
|
|
65
|
+
healthCheckPath: healthPath,
|
|
66
|
+
healthCheckInterval: healthInterval ? parseInt(healthInterval, 10) : void 0
|
|
67
|
+
});
|
|
53
68
|
}
|
|
54
69
|
async function serviceServe(args) {
|
|
55
70
|
const positional = positionalArgs(args);
|
|
@@ -75,7 +90,7 @@ async function serviceServe(args) {
|
|
|
75
90
|
};
|
|
76
91
|
process.on("SIGINT", cleanup);
|
|
77
92
|
process.on("SIGTERM", cleanup);
|
|
78
|
-
const { runFrpcTunnel } = await import('./frpc-
|
|
93
|
+
const { runFrpcTunnel } = await import('./frpc-qqYQ6F9T.mjs');
|
|
79
94
|
await runFrpcTunnel(name, [caddyPort]);
|
|
80
95
|
} catch (err) {
|
|
81
96
|
console.error(`Error serving directory: ${err.message}`);
|
|
@@ -128,24 +143,34 @@ function printServiceHelp() {
|
|
|
128
143
|
svamp service \u2014 Expose local services via frpc tunnels
|
|
129
144
|
|
|
130
145
|
Usage:
|
|
131
|
-
svamp service expose <name> --port <port> [
|
|
132
|
-
svamp service serve <name> [directory] [--no-listing]
|
|
133
|
-
svamp service tunnel <name> --port <port> [
|
|
134
|
-
svamp service list
|
|
135
|
-
svamp service delete <name>
|
|
146
|
+
svamp service expose <name> --port <port> [options] Expose local ports via tunnel
|
|
147
|
+
svamp service serve <name> [directory] [--no-listing] Serve static files via tunnel
|
|
148
|
+
svamp service tunnel <name> --port <port> [options] Alias for expose
|
|
149
|
+
svamp service list List active tunnels (daemon)
|
|
150
|
+
svamp service delete <name> Stop a tunnel (daemon)
|
|
151
|
+
|
|
152
|
+
Options:
|
|
153
|
+
--port <port> Port to expose (repeatable for multi-port)
|
|
154
|
+
--group <name> Service group \u2014 multiple machines share the same URL
|
|
155
|
+
--group-key <secret> Shared key for the service group
|
|
156
|
+
--health-check <tcp|http> Enable health checks on local backend
|
|
157
|
+
--health-path <path> HTTP health check path (e.g., /health)
|
|
158
|
+
--health-interval <sec> Health check interval (default: 10s)
|
|
136
159
|
|
|
137
|
-
|
|
138
|
-
|
|
160
|
+
Service Groups:
|
|
161
|
+
Run the same command on different machines with --group to create a
|
|
162
|
+
load-balanced service. frps round-robins traffic across all group members.
|
|
163
|
+
Unhealthy backends are auto-removed when --health-check is enabled.
|
|
139
164
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
FRPS_AUTH_TOKEN frps authentication token
|
|
144
|
-
FRPS_SUBDOMAIN_HOST Base domain for subdomains (default: svc.hypha.aicell.io)
|
|
165
|
+
Machine A: svamp service expose my-api --port 8000 --group my-api --group-key secret123
|
|
166
|
+
Machine B: svamp service expose my-api --port 8000 --group my-api --group-key secret123
|
|
167
|
+
\u2192 Both serve at the same URL, frps load-balances between them
|
|
145
168
|
|
|
146
169
|
Examples:
|
|
147
170
|
svamp service expose my-api --port 8000
|
|
171
|
+
svamp service expose my-api --port 8000 --health-check http --health-path /health
|
|
148
172
|
svamp service expose my-api --port 8000 --port 3000
|
|
173
|
+
svamp service expose my-api --port 8000 --group my-api --group-key s3cret
|
|
149
174
|
svamp service serve my-site ./dist
|
|
150
175
|
svamp service serve my-site
|
|
151
176
|
`.trim());
|
|
@@ -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-DrNOSpki.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-YVIJdP0j.mjs';
|
|
9
9
|
import 'os';
|
|
10
10
|
import 'fs/promises';
|
|
11
11
|
import 'url';
|
|
@@ -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-YVIJdP0j.mjs';
|
|
6
6
|
import 'os';
|
|
7
7
|
import 'fs/promises';
|
|
8
8
|
import 'fs';
|
|
@@ -2,13 +2,17 @@ import { spawn, execSync } from 'child_process';
|
|
|
2
2
|
import { mkdirSync, writeFileSync, unlinkSync, existsSync, chmodSync, readFileSync } from 'fs';
|
|
3
3
|
import { join } from 'path';
|
|
4
4
|
import { homedir, platform, arch } from 'os';
|
|
5
|
-
import {
|
|
5
|
+
import { createHash } from 'crypto';
|
|
6
6
|
|
|
7
7
|
const FRP_VERSION = "0.61.1";
|
|
8
8
|
const BIN_DIR = join(homedir(), ".svamp", "bin");
|
|
9
9
|
const FRPC_BIN = join(BIN_DIR, platform() === "win32" ? "frpc.exe" : "frpc");
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
function isInCluster() {
|
|
11
|
+
return !!(process.env.KUBERNETES_SERVICE_HOST || process.env.SANDBOX_ID);
|
|
12
|
+
}
|
|
13
|
+
const DEFAULT_FRPS_ADDR = isInCluster() ? "frps.hypha.svc.cluster.local" : "frps-ctrl.svc.hypha.aicell.io";
|
|
14
|
+
const DEFAULT_FRPS_PORT = isInCluster() ? 7e3 : 443;
|
|
15
|
+
const FRPS_PUBLIC_TOKEN = "hypha-frps-public";
|
|
12
16
|
function getFrpcDownloadUrl() {
|
|
13
17
|
const os = platform();
|
|
14
18
|
const a = arch();
|
|
@@ -108,12 +112,18 @@ function generateFrpcConfig(config, proxies) {
|
|
|
108
112
|
'auth.method = "token"',
|
|
109
113
|
`auth.token = "${config.authToken}"`,
|
|
110
114
|
"",
|
|
115
|
+
"# Hypha JWT token for server-side authentication",
|
|
116
|
+
...config.hyphaToken ? [`metadatas.token = "${config.hyphaToken}"`] : [],
|
|
117
|
+
"",
|
|
111
118
|
"# Transport",
|
|
112
119
|
...useWSS ? ['transport.protocol = "wss"'] : [],
|
|
113
120
|
"transport.heartbeatInterval = 30",
|
|
114
121
|
"transport.heartbeatTimeout = 90",
|
|
115
122
|
"transport.poolCount = 5",
|
|
116
123
|
"",
|
|
124
|
+
"# Don't exit on login failure \u2014 let frpc keep retrying",
|
|
125
|
+
"loginFailExit = false",
|
|
126
|
+
"",
|
|
117
127
|
'log.to = "console"',
|
|
118
128
|
'log.level = "info"',
|
|
119
129
|
""
|
|
@@ -130,6 +140,21 @@ function generateFrpcConfig(config, proxies) {
|
|
|
130
140
|
if (proxy.customDomains && proxy.customDomains.length > 0) {
|
|
131
141
|
lines.push(`customDomains = [${proxy.customDomains.map((d) => `"${d}"`).join(", ")}]`);
|
|
132
142
|
}
|
|
143
|
+
if (proxy.group) {
|
|
144
|
+
lines.push(`loadBalancer.group = "${proxy.group}"`);
|
|
145
|
+
if (proxy.groupKey) {
|
|
146
|
+
lines.push(`loadBalancer.groupKey = "${proxy.groupKey}"`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (proxy.healthCheckType) {
|
|
150
|
+
lines.push(`healthCheck.type = "${proxy.healthCheckType}"`);
|
|
151
|
+
if (proxy.healthCheckType === "http" && proxy.healthCheckPath) {
|
|
152
|
+
lines.push(`healthCheck.path = "${proxy.healthCheckPath}"`);
|
|
153
|
+
}
|
|
154
|
+
lines.push(`healthCheck.intervalSeconds = ${proxy.healthCheckInterval || 10}`);
|
|
155
|
+
lines.push(`healthCheck.timeoutSeconds = ${proxy.healthCheckTimeout || 3}`);
|
|
156
|
+
lines.push(`healthCheck.maxFailed = ${proxy.healthCheckMaxFailed || 3}`);
|
|
157
|
+
}
|
|
133
158
|
if (proxy.type === "http") {
|
|
134
159
|
lines.push("transport.useEncryption = false");
|
|
135
160
|
lines.push("transport.useCompression = false");
|
|
@@ -152,17 +177,37 @@ class FrpcTunnel {
|
|
|
152
177
|
constructor(options) {
|
|
153
178
|
this.options = options;
|
|
154
179
|
this.log = options.log || ((msg) => console.log(`[FRPC] ${msg}`));
|
|
180
|
+
const hyphaToken = options.serverConfig?.hyphaToken || process.env.HYPHA_TOKEN || "";
|
|
155
181
|
this.serverConfig = {
|
|
156
182
|
serverAddr: options.serverConfig?.serverAddr || process.env.FRPS_SERVER_ADDR || DEFAULT_FRPS_ADDR,
|
|
157
183
|
serverPort: options.serverConfig?.serverPort || parseInt(process.env.FRPS_SERVER_PORT || "", 10) || DEFAULT_FRPS_PORT,
|
|
158
|
-
authToken: options.serverConfig?.authToken || process.env.FRPS_AUTH_TOKEN ||
|
|
184
|
+
authToken: options.serverConfig?.authToken || process.env.FRPS_AUTH_TOKEN || FRPS_PUBLIC_TOKEN,
|
|
185
|
+
hyphaToken,
|
|
159
186
|
subDomainHost: options.serverConfig?.subDomainHost || process.env.FRPS_SUBDOMAIN_HOST || "svc.hypha.aicell.io"
|
|
160
187
|
};
|
|
161
|
-
if (!this.serverConfig.
|
|
188
|
+
if (!this.serverConfig.hyphaToken) {
|
|
162
189
|
throw new Error(
|
|
163
|
-
|
|
190
|
+
'Hypha token required for frpc authentication. Run "svamp login" or set HYPHA_TOKEN.'
|
|
164
191
|
);
|
|
165
192
|
}
|
|
193
|
+
const machineId = homedir();
|
|
194
|
+
const machineHash = createHash("sha256").update(machineId).digest("hex").slice(0, 6);
|
|
195
|
+
this.proxies = options.ports.map((port) => {
|
|
196
|
+
const subdomain = options.subdomains?.get(port) || (options.group ? `${options.group}-${createHash("sha256").update(options.group).digest("hex").slice(0, 8)}` : `${options.name}-${port}-${createHash("sha256").update(`${options.name}-${port}-${machineId}`).digest("hex").slice(0, 8)}`);
|
|
197
|
+
const proxyName = options.group ? `${options.name}-${port}-${machineHash}` : `${options.name}-${port}`;
|
|
198
|
+
return {
|
|
199
|
+
name: proxyName,
|
|
200
|
+
type: "http",
|
|
201
|
+
localIP: options.localHost || "127.0.0.1",
|
|
202
|
+
localPort: port,
|
|
203
|
+
subdomain,
|
|
204
|
+
group: options.group,
|
|
205
|
+
groupKey: options.groupKey,
|
|
206
|
+
healthCheckType: options.healthCheckType,
|
|
207
|
+
healthCheckPath: options.healthCheckPath,
|
|
208
|
+
healthCheckInterval: options.healthCheckInterval
|
|
209
|
+
};
|
|
210
|
+
});
|
|
166
211
|
const configDir = join(homedir(), ".svamp", "frpc");
|
|
167
212
|
mkdirSync(configDir, { recursive: true });
|
|
168
213
|
this.configPath = join(configDir, `${options.name}.toml`);
|
|
@@ -172,18 +217,7 @@ class FrpcTunnel {
|
|
|
172
217
|
if (this._destroyed) return;
|
|
173
218
|
if (this.process) return;
|
|
174
219
|
const frpcPath = await ensureFrpc(this.log);
|
|
175
|
-
const
|
|
176
|
-
const subdomain = this.options.subdomains?.get(port) || `${this.options.name}-${port}-${randomUUID().slice(0, 8)}`;
|
|
177
|
-
return {
|
|
178
|
-
name: `${this.options.name}-${port}`,
|
|
179
|
-
type: "http",
|
|
180
|
-
localIP: this.options.localHost || "127.0.0.1",
|
|
181
|
-
localPort: port,
|
|
182
|
-
subdomain
|
|
183
|
-
};
|
|
184
|
-
});
|
|
185
|
-
this.proxies = proxies;
|
|
186
|
-
const configContent = generateFrpcConfig(this.serverConfig, proxies);
|
|
220
|
+
const configContent = generateFrpcConfig(this.serverConfig, this.proxies);
|
|
187
221
|
writeFileSync(this.configPath, configContent);
|
|
188
222
|
this.log(`Config written to ${this.configPath}`);
|
|
189
223
|
return new Promise((resolve, reject) => {
|
|
@@ -299,12 +333,13 @@ class FrpcTunnel {
|
|
|
299
333
|
return urls;
|
|
300
334
|
}
|
|
301
335
|
}
|
|
302
|
-
async function runFrpcTunnel(name, ports, serverConfig) {
|
|
336
|
+
async function runFrpcTunnel(name, ports, serverConfig, tunnelOptions) {
|
|
303
337
|
const portList = ports.join(", ");
|
|
304
338
|
const tunnel = new FrpcTunnel({
|
|
305
339
|
name,
|
|
306
340
|
ports,
|
|
307
341
|
serverConfig,
|
|
342
|
+
...tunnelOptions,
|
|
308
343
|
onConnect: () => {
|
|
309
344
|
console.log(`Tunnel connected: ${name} \u2192 localhost:[${portList}]`);
|
|
310
345
|
const urls = tunnel.getUrls();
|
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-YVIJdP0j.mjs';
|
|
2
2
|
import 'os';
|
|
3
3
|
import 'fs/promises';
|
|
4
4
|
import 'fs';
|
|
@@ -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-YVIJdP0j.mjs';
|
|
6
6
|
import { createServer } from 'node:http';
|
|
7
7
|
import { spawn } from 'node:child_process';
|
|
8
8
|
import { createInterface } from 'node:readline';
|
|
@@ -1092,7 +1092,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
1092
1092
|
const tunnels = handlers.tunnels;
|
|
1093
1093
|
if (!tunnels) throw new Error("Tunnel management not available");
|
|
1094
1094
|
if (tunnels.has(params.name)) throw new Error(`Tunnel '${params.name}' already running`);
|
|
1095
|
-
const { FrpcTunnel } = await import('./frpc-
|
|
1095
|
+
const { FrpcTunnel } = await import('./frpc-qqYQ6F9T.mjs');
|
|
1096
1096
|
const tunnel = new FrpcTunnel({
|
|
1097
1097
|
name: params.name,
|
|
1098
1098
|
ports: params.ports,
|
|
@@ -6235,7 +6235,7 @@ async function startDaemon(options) {
|
|
|
6235
6235
|
const supervisor = new ProcessSupervisor(join(SVAMP_HOME, "processes"));
|
|
6236
6236
|
await supervisor.init();
|
|
6237
6237
|
const tunnels = /* @__PURE__ */ new Map();
|
|
6238
|
-
const { ServeManager } = await import('./serveManager-
|
|
6238
|
+
const { ServeManager } = await import('./serveManager-Cgbl706Q.mjs');
|
|
6239
6239
|
const serveManager = new ServeManager(SVAMP_HOME, (msg) => logger.log(`[SERVE] ${msg}`), hyphaServerUrl);
|
|
6240
6240
|
ensureAutoInstalledSkills(logger).catch(() => {
|
|
6241
6241
|
});
|
|
@@ -52,7 +52,7 @@ async function handleServeCommand() {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
async function serveAdd(args, machineId) {
|
|
55
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
55
|
+
const { connectAndGetMachine } = await import('./commands-DrNOSpki.mjs');
|
|
56
56
|
const pos = positionalArgs(args);
|
|
57
57
|
const name = pos[0];
|
|
58
58
|
if (!name) {
|
|
@@ -84,7 +84,7 @@ async function serveAdd(args, machineId) {
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
async function serveRemove(args, machineId) {
|
|
87
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
87
|
+
const { connectAndGetMachine } = await import('./commands-DrNOSpki.mjs');
|
|
88
88
|
const pos = positionalArgs(args);
|
|
89
89
|
const name = pos[0];
|
|
90
90
|
if (!name) {
|
|
@@ -104,7 +104,7 @@ async function serveRemove(args, machineId) {
|
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
async function serveList(args, machineId) {
|
|
107
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
107
|
+
const { connectAndGetMachine } = await import('./commands-DrNOSpki.mjs');
|
|
108
108
|
const all = hasFlag(args, "--all", "-a");
|
|
109
109
|
const json = hasFlag(args, "--json");
|
|
110
110
|
const sessionId = getFlag(args, "--session");
|
|
@@ -137,7 +137,7 @@ async function serveList(args, machineId) {
|
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
async function serveInfo(machineId) {
|
|
140
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
140
|
+
const { connectAndGetMachine } = await import('./commands-DrNOSpki.mjs');
|
|
141
141
|
const { machine, server } = await connectAndGetMachine(machineId);
|
|
142
142
|
try {
|
|
143
143
|
const info = await machine.serveInfo();
|
|
@@ -533,7 +533,7 @@ button{padding:10px 24px;background:#0969da;color:#fff;border:none;border-radius
|
|
|
533
533
|
/** Start frpc tunnel for the Caddy port. */
|
|
534
534
|
async ensureTunnel() {
|
|
535
535
|
try {
|
|
536
|
-
const { FrpcTunnel } = await import('./frpc-
|
|
536
|
+
const { FrpcTunnel } = await import('./frpc-qqYQ6F9T.mjs');
|
|
537
537
|
this.frpcTunnel = new FrpcTunnel({
|
|
538
538
|
name: this.serviceName,
|
|
539
539
|
ports: [this.port],
|