svamp-cli 0.1.69 → 0.1.71
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +19 -19
- package/dist/{commands-CF32XIau.mjs → commands-BLjcT1Vl.mjs} +2 -2
- package/dist/{commands-CNWZF0B9.mjs → commands-CheZ8rae.mjs} +2 -2
- package/dist/{commands-CgWkG45c.mjs → commands-DDqf8dQ_.mjs} +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{package-D2QVDgm_.mjs → package-CxTZatXO.mjs} +2 -2
- package/dist/{run-DqPEyYsf.mjs → run-6vD6-456.mjs} +2 -2
- package/dist/{run-DxmtlxnM.mjs → run-DGKMT1Af.mjs} +550 -363
- package/dist/{tunnel-C3UsqTxi.mjs → tunnel-C2kqST5d.mjs} +65 -31
- package/package.json +2 -2
|
@@ -14,10 +14,12 @@ class TunnelClient {
|
|
|
14
14
|
requestCount = 0;
|
|
15
15
|
localWebSockets = /* @__PURE__ */ new Map();
|
|
16
16
|
// request_id → local WS connection
|
|
17
|
+
pendingBinaryBody = null;
|
|
18
|
+
// awaiting binary body frame
|
|
17
19
|
constructor(options) {
|
|
18
20
|
this.options = {
|
|
19
21
|
localHost: "localhost",
|
|
20
|
-
requestTimeout:
|
|
22
|
+
requestTimeout: 12e4,
|
|
21
23
|
...options
|
|
22
24
|
};
|
|
23
25
|
this.env = options.env || requireSandboxApiEnv();
|
|
@@ -40,7 +42,10 @@ class TunnelClient {
|
|
|
40
42
|
const url = this.buildWsUrl();
|
|
41
43
|
return new Promise((resolve, reject) => {
|
|
42
44
|
try {
|
|
43
|
-
this.ws = new WebSocket(url
|
|
45
|
+
this.ws = new WebSocket(url, {
|
|
46
|
+
maxPayload: 100 * 1024 * 1024
|
|
47
|
+
// 100MB for large binary bodies
|
|
48
|
+
});
|
|
44
49
|
} catch (err) {
|
|
45
50
|
reject(new Error(`Failed to create WebSocket: ${err.message}`));
|
|
46
51
|
return;
|
|
@@ -51,13 +56,18 @@ class TunnelClient {
|
|
|
51
56
|
this.options.onConnect?.();
|
|
52
57
|
resolve();
|
|
53
58
|
});
|
|
54
|
-
this.ws.on("message", (data) => {
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
this.ws.on("message", (data, isBinary) => {
|
|
60
|
+
if (isBinary) {
|
|
61
|
+
this.handleBinaryBody(data);
|
|
62
|
+
} else {
|
|
63
|
+
const raw = typeof data === "string" ? data : data.toString("utf8");
|
|
64
|
+
this.handleMessage(raw);
|
|
65
|
+
}
|
|
57
66
|
});
|
|
58
67
|
this.ws.on("close", () => {
|
|
59
68
|
this.stopPingInterval();
|
|
60
69
|
this.cleanupLocalWebSockets();
|
|
70
|
+
this.pendingBinaryBody = null;
|
|
61
71
|
this.options.onDisconnect?.();
|
|
62
72
|
if (!this.destroyed) {
|
|
63
73
|
this.scheduleReconnect();
|
|
@@ -104,9 +114,13 @@ class TunnelClient {
|
|
|
104
114
|
break;
|
|
105
115
|
case "request":
|
|
106
116
|
this.options.onRequest?.(msg);
|
|
107
|
-
|
|
108
|
-
this.
|
|
109
|
-
}
|
|
117
|
+
if (msg.has_body) {
|
|
118
|
+
this.pendingBinaryBody = msg;
|
|
119
|
+
} else {
|
|
120
|
+
this.proxyRequest(msg, Buffer.alloc(0)).catch((err) => {
|
|
121
|
+
this.options.onError?.(err);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
110
124
|
break;
|
|
111
125
|
case "ws_open":
|
|
112
126
|
this.handleWsOpen(msg).catch((err) => {
|
|
@@ -121,7 +135,15 @@ class TunnelClient {
|
|
|
121
135
|
break;
|
|
122
136
|
}
|
|
123
137
|
}
|
|
124
|
-
|
|
138
|
+
handleBinaryBody(data) {
|
|
139
|
+
const req = this.pendingBinaryBody;
|
|
140
|
+
this.pendingBinaryBody = null;
|
|
141
|
+
if (!req) return;
|
|
142
|
+
this.proxyRequest(req, data).catch((err) => {
|
|
143
|
+
this.options.onError?.(err);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
async proxyRequest(req, bodyBuffer) {
|
|
125
147
|
this.requestCount++;
|
|
126
148
|
const port = req.port || this.options.ports[0];
|
|
127
149
|
const url = `http://${this.options.localHost}:${port}${req.path}`;
|
|
@@ -135,14 +157,12 @@ class TunnelClient {
|
|
|
135
157
|
headers: forwardHeaders,
|
|
136
158
|
signal: controller.signal
|
|
137
159
|
};
|
|
138
|
-
if (
|
|
139
|
-
init.body =
|
|
160
|
+
if (bodyBuffer.byteLength > 0 && !["GET", "HEAD"].includes(req.method.toUpperCase())) {
|
|
161
|
+
init.body = bodyBuffer;
|
|
140
162
|
}
|
|
141
163
|
try {
|
|
142
164
|
const res = await fetch(url, init);
|
|
143
165
|
clearTimeout(timeout);
|
|
144
|
-
const bodyBuffer = await res.arrayBuffer();
|
|
145
|
-
const bodyBase64 = bodyBuffer.byteLength > 0 ? Buffer.from(bodyBuffer).toString("base64") : void 0;
|
|
146
166
|
const headers = {};
|
|
147
167
|
res.headers.forEach((value, key) => {
|
|
148
168
|
headers[key] = value;
|
|
@@ -152,27 +172,36 @@ class TunnelClient {
|
|
|
152
172
|
id: req.id,
|
|
153
173
|
status: res.status,
|
|
154
174
|
headers,
|
|
155
|
-
|
|
175
|
+
streaming: true
|
|
156
176
|
});
|
|
177
|
+
if (res.body) {
|
|
178
|
+
const reader = res.body.getReader();
|
|
179
|
+
try {
|
|
180
|
+
while (true) {
|
|
181
|
+
const { done, value } = await reader.read();
|
|
182
|
+
if (done) break;
|
|
183
|
+
this.send({ type: "response_chunk", id: req.id });
|
|
184
|
+
this.sendBinary(Buffer.from(value));
|
|
185
|
+
}
|
|
186
|
+
} finally {
|
|
187
|
+
reader.releaseLock();
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
this.send({ type: "response_end", id: req.id });
|
|
157
191
|
} catch (err) {
|
|
158
192
|
clearTimeout(timeout);
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
status: 502,
|
|
172
|
-
headers: { "content-type": "text/plain" },
|
|
173
|
-
body: Buffer.from(`Tunnel: local service error: ${err.message}`).toString("base64")
|
|
174
|
-
});
|
|
175
|
-
}
|
|
193
|
+
const status = err.name === "AbortError" ? 504 : 502;
|
|
194
|
+
const message = err.name === "AbortError" ? "Tunnel: request timeout" : `Tunnel: local service error: ${err.message}`;
|
|
195
|
+
this.send({
|
|
196
|
+
type: "response",
|
|
197
|
+
id: req.id,
|
|
198
|
+
status,
|
|
199
|
+
headers: { "content-type": "text/plain" },
|
|
200
|
+
streaming: true
|
|
201
|
+
});
|
|
202
|
+
this.send({ type: "response_chunk", id: req.id });
|
|
203
|
+
this.sendBinary(Buffer.from(message));
|
|
204
|
+
this.send({ type: "response_end", id: req.id });
|
|
176
205
|
}
|
|
177
206
|
}
|
|
178
207
|
// ── WebSocket proxying ───────────────────────────────────────────────
|
|
@@ -238,6 +267,11 @@ class TunnelClient {
|
|
|
238
267
|
this.ws.send(JSON.stringify(msg));
|
|
239
268
|
}
|
|
240
269
|
}
|
|
270
|
+
sendBinary(data) {
|
|
271
|
+
if (this.ws?.readyState === WebSocket.OPEN) {
|
|
272
|
+
this.ws.send(data);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
241
275
|
startPingInterval() {
|
|
242
276
|
this.stopPingInterval();
|
|
243
277
|
this.pingInterval = setInterval(() => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svamp-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.71",
|
|
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,7 +20,7 @@
|
|
|
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",
|
|
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",
|
|
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",
|