svamp-cli 0.2.21 → 0.2.22

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.
@@ -52,7 +52,7 @@ async function handleServeCommand() {
52
52
  }
53
53
  }
54
54
  async function serveAdd(args, machineId) {
55
- const { connectAndGetMachine } = await import('./commands-DVCdUK0p.mjs');
55
+ const { connectAndGetMachine } = await import('./commands-CNDLej2C.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-DVCdUK0p.mjs');
87
+ const { connectAndGetMachine } = await import('./commands-CNDLej2C.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-DVCdUK0p.mjs');
107
+ const { connectAndGetMachine } = await import('./commands-CNDLej2C.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-DVCdUK0p.mjs');
140
+ const { connectAndGetMachine } = await import('./commands-CNDLej2C.mjs');
141
141
  const { machine, server } = await connectAndGetMachine(machineId);
142
142
  try {
143
143
  const info = await machine.serveInfo();
@@ -530,47 +530,26 @@ button{padding:10px 24px;background:#0969da;color:#fff;border:none;border-radius
530
530
  server.on("error", reject);
531
531
  });
532
532
  }
533
- /** Start frpc tunnel for the Caddy port, or add K8s backend on cloud. */
533
+ /** Start frpc tunnel for the Caddy port. */
534
534
  async ensureTunnel() {
535
535
  try {
536
- const { getSandboxEnv } = await import('./api-BRbsyqJ4.mjs');
537
- const env = getSandboxEnv();
538
- if (env.sandboxId) {
539
- const { createServiceGroup, addBackend } = await import('./api-BRbsyqJ4.mjs');
540
- try {
541
- const group = await createServiceGroup(this.serviceName, [this.port]);
542
- this.serviceUrl = group.ports?.[0]?.url || group.url || null;
543
- await addBackend(this.serviceName);
544
- this.log(`Cloud backend added. URL: ${this.serviceUrl}`);
545
- } catch (err) {
546
- if (err.message?.includes("already exists")) {
547
- const { getServiceGroup } = await import('./api-BRbsyqJ4.mjs');
548
- const existing = await getServiceGroup(this.serviceName);
549
- this.serviceUrl = existing.ports?.[0]?.url || existing.url || null;
550
- this.log(`Reusing existing service group. URL: ${this.serviceUrl}`);
551
- } else {
552
- throw err;
536
+ const { FrpcTunnel } = await import('./frpc-Dz3UhcgJ.mjs');
537
+ this.frpcTunnel = new FrpcTunnel({
538
+ name: this.serviceName,
539
+ ports: [this.port],
540
+ onError: (err) => this.log(`frpc error: ${err.message}`),
541
+ onConnect: () => {
542
+ const url = this.frpcTunnel?.getUrls().get(this.port);
543
+ if (url) {
544
+ this.serviceUrl = url;
545
+ this.log(`frpc tunnel connected. URL: ${this.serviceUrl}`);
553
546
  }
554
- }
555
- } else {
556
- const { FrpcTunnel } = await import('./frpc-Ckiiq9Lw.mjs');
557
- this.frpcTunnel = new FrpcTunnel({
558
- name: this.serviceName,
559
- ports: [this.port],
560
- onError: (err) => this.log(`frpc error: ${err.message}`),
561
- onConnect: () => {
562
- const url = this.frpcTunnel?.getUrls().get(this.port);
563
- if (url) {
564
- this.serviceUrl = url;
565
- this.log(`frpc tunnel connected. URL: ${this.serviceUrl}`);
566
- }
567
- },
568
- onDisconnect: () => this.log("frpc tunnel disconnected, will auto-reconnect...")
569
- });
570
- await this.frpcTunnel.connect();
571
- this.serviceUrl = this.frpcTunnel.getUrls().get(this.port) || null;
572
- this.log(`frpc tunnel started. URL: ${this.serviceUrl}`);
573
- }
547
+ },
548
+ onDisconnect: () => this.log("frpc tunnel disconnected, will auto-reconnect...")
549
+ });
550
+ await this.frpcTunnel.connect();
551
+ this.serviceUrl = this.frpcTunnel.getUrls().get(this.port) || null;
552
+ this.log(`frpc tunnel started. URL: ${this.serviceUrl}`);
574
553
  } catch (err) {
575
554
  this.log(`Warning: could not expose server externally: ${err.message}`);
576
555
  this.log(`Server available locally at http://127.0.0.1:${this.port}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svamp-cli",
3
- "version": "0.2.21",
3
+ "version": "0.2.22",
4
4
  "description": "Svamp CLI — AI workspace daemon on Hypha Cloud",
5
5
  "author": "Amun AI AB",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -20,11 +20,12 @@
20
20
  "scripts": {
21
21
  "build": "rm -rf dist && tsc --noEmit && pkgroll",
22
22
  "typecheck": "tsc --noEmit",
23
- "test": "npx tsx test/test-authorize.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-ralph-loop.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-output-formatters.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-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-ralph-loop-integration.mjs && npx tsx test/test-ralph-loop-modes.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-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox.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-service-stability.mjs && npx tsx test/test-serve-stability.mjs",
23
+ "test": "npx tsx test/test-authorize.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-ralph-loop.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-output-formatters.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-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-ralph-loop-integration.mjs && npx tsx test/test-ralph-loop-modes.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-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox.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",
24
24
  "test:hypha": "node --no-warnings test/test-hypha-service.mjs",
25
25
  "dev": "tsx src/cli.ts",
26
26
  "dev:daemon": "tsx src/cli.ts daemon start-sync",
27
- "test:e2e": "node --no-warnings test/e2e-session-tests.mjs"
27
+ "test:e2e": "node --no-warnings test/e2e-session-tests.mjs",
28
+ "test:frpc": "npx tsx test/test-frpc-e2e.mjs"
28
29
  },
29
30
  "dependencies": {
30
31
  "@agentclientprotocol/sdk": "^0.14.1",
@@ -1,147 +0,0 @@
1
- function getSandboxEnv() {
2
- return {
3
- apiUrl: process.env.SANDBOX_API_URL || "https://agent-sandbox.aicell.io",
4
- apiKey: process.env.SANDBOX_API_KEY || process.env.HYPHA_TOKEN || "",
5
- namespace: process.env.SANDBOX_NAMESPACE || process.env.HYPHA_WORKSPACE || "",
6
- sandboxId: process.env.SANDBOX_ID || ""
7
- };
8
- }
9
- function requireSandboxEnv() {
10
- const env = getSandboxEnv();
11
- if (!env.apiKey) {
12
- throw new Error(
13
- 'No API credentials found.\nRun "svamp login" to authenticate with Hypha, or set SANDBOX_API_KEY directly.'
14
- );
15
- }
16
- if (!env.namespace) {
17
- throw new Error(
18
- 'No namespace/workspace found.\nRun "svamp login" to set HYPHA_WORKSPACE, or set SANDBOX_NAMESPACE directly.'
19
- );
20
- }
21
- return env;
22
- }
23
- function requireSandboxApiEnv() {
24
- const env = getSandboxEnv();
25
- if (!env.apiKey) {
26
- throw new Error(
27
- 'No API credentials found.\nRun "svamp login" to authenticate with Hypha, or set SANDBOX_API_KEY directly.'
28
- );
29
- }
30
- return env;
31
- }
32
- async function sandboxFetch(env, path, init, timeoutMs = 3e4) {
33
- const url = `${env.apiUrl.replace(/\/+$/, "")}${path}`;
34
- const headers = {
35
- "Authorization": `Bearer ${env.apiKey}`,
36
- "Content-Type": "application/json",
37
- ...init?.headers || {}
38
- };
39
- const controller = new AbortController();
40
- const timer = setTimeout(() => controller.abort(), timeoutMs);
41
- let res;
42
- try {
43
- res = await fetch(url, { ...init, headers, signal: controller.signal });
44
- } finally {
45
- clearTimeout(timer);
46
- }
47
- if (!res.ok) {
48
- const body = await res.text().catch(() => "");
49
- let detail = body;
50
- try {
51
- detail = JSON.parse(body).detail || body;
52
- } catch {
53
- }
54
- throw new Error(`${res.status} ${res.statusText}: ${detail}`);
55
- }
56
- return res;
57
- }
58
- async function createServiceGroup(name, ports, options) {
59
- const env = requireSandboxEnv();
60
- const body = {};
61
- if (ports.length === 1 && options?.subdomain) {
62
- body.port = ports[0];
63
- body.subdomain = options.subdomain;
64
- } else {
65
- body.ports = ports.map((p) => ({ port: p }));
66
- }
67
- if (options?.healthPath) {
68
- body.health_path = options.healthPath;
69
- if (options.healthInterval) {
70
- body.health_interval = options.healthInterval;
71
- }
72
- }
73
- const res = await sandboxFetch(env, `/services/${env.namespace}/${name}`, {
74
- method: "POST",
75
- body: JSON.stringify(body)
76
- });
77
- return res.json();
78
- }
79
- async function listServiceGroups() {
80
- const env = requireSandboxEnv();
81
- const res = await sandboxFetch(env, `/services/${env.namespace}`);
82
- return res.json();
83
- }
84
- async function getServiceGroup(name) {
85
- const env = requireSandboxEnv();
86
- const res = await sandboxFetch(env, `/services/${env.namespace}/${name}`);
87
- return res.json();
88
- }
89
- async function deleteServiceGroup(name) {
90
- const env = requireSandboxEnv();
91
- const res = await sandboxFetch(env, `/services/${env.namespace}/${name}`, {
92
- method: "DELETE"
93
- });
94
- return res.json();
95
- }
96
- async function addPort(name, port, subdomain) {
97
- const env = requireSandboxEnv();
98
- const res = await sandboxFetch(env, `/services/${env.namespace}/${name}/ports`, {
99
- method: "POST",
100
- body: JSON.stringify({ port, subdomain })
101
- });
102
- return res.json();
103
- }
104
- async function removePort(name, port) {
105
- const env = requireSandboxEnv();
106
- const res = await sandboxFetch(env, `/services/${env.namespace}/${name}/ports/${port}`, {
107
- method: "DELETE"
108
- });
109
- return res.json();
110
- }
111
- async function renameSubdomain(name, port, subdomain) {
112
- const env = requireSandboxEnv();
113
- const res = await sandboxFetch(env, `/services/${env.namespace}/${name}/subdomain`, {
114
- method: "PUT",
115
- body: JSON.stringify({ port, subdomain })
116
- });
117
- return res.json();
118
- }
119
- async function addBackend(name, sandboxId) {
120
- const env = requireSandboxEnv();
121
- const sid = sandboxId || env.sandboxId;
122
- if (!sid) {
123
- throw new Error(
124
- "No sandbox ID provided and SANDBOX_ID is not set.\nUse --sandbox-id <id> to specify which sandbox to add."
125
- );
126
- }
127
- const res = await sandboxFetch(env, `/services/${env.namespace}/${name}/backends`, {
128
- method: "POST",
129
- body: JSON.stringify({ sandbox_id: sid })
130
- });
131
- return res.json();
132
- }
133
- async function removeBackend(name, sandboxId) {
134
- const env = requireSandboxEnv();
135
- const sid = sandboxId || env.sandboxId;
136
- if (!sid) {
137
- throw new Error(
138
- "No sandbox ID provided and SANDBOX_ID is not set.\nUse --sandbox-id <id> to specify which sandbox to remove."
139
- );
140
- }
141
- const res = await sandboxFetch(env, `/services/${env.namespace}/${name}/backends/${sid}`, {
142
- method: "DELETE"
143
- });
144
- return res.json();
145
- }
146
-
147
- export { addBackend, addPort, createServiceGroup, deleteServiceGroup, getSandboxEnv, getServiceGroup, listServiceGroups, removeBackend, removePort, renameSubdomain, requireSandboxApiEnv, requireSandboxEnv };