@arker-ai/sdk 0.5.2 → 0.6.3
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/README.md +154 -0
- package/dist/arker-provider-BNIL8NdM.d.ts +7 -0
- package/dist/arker-provider-DwUib5ZW.d.cts +7 -0
- package/dist/chunk-35IEV6BU.js +286 -0
- package/dist/{chunk-YGZOUXII.js → chunk-7BHPVQNG.js} +232 -24
- package/dist/cli.cjs +464 -185
- package/dist/cli.js +231 -161
- package/dist/common-C5zJ-LkS.d.cts +9 -0
- package/dist/common-C5zJ-LkS.d.ts +9 -0
- package/dist/daytona.cjs +1274 -0
- package/dist/daytona.d.cts +37 -0
- package/dist/daytona.d.ts +37 -0
- package/dist/daytona.js +65 -0
- package/dist/e2b.cjs +1288 -0
- package/dist/e2b.d.cts +29 -0
- package/dist/e2b.d.ts +29 -0
- package/dist/e2b.js +75 -0
- package/dist/index.cjs +242 -24
- package/dist/index.d.cts +132 -108
- package/dist/index.d.ts +132 -108
- package/dist/index.js +1 -1
- package/dist/modal.cjs +1356 -0
- package/dist/modal.d.cts +49 -0
- package/dist/modal.d.ts +49 -0
- package/dist/modal.js +130 -0
- package/package.json +30 -4
package/dist/cli.js
CHANGED
|
@@ -3,14 +3,22 @@ import {
|
|
|
3
3
|
ARKER_ORG_ID,
|
|
4
4
|
Arker,
|
|
5
5
|
ArkerError
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-7BHPVQNG.js";
|
|
7
7
|
|
|
8
8
|
// src/cli.ts
|
|
9
9
|
import { readFileSync, existsSync } from "fs";
|
|
10
|
+
import { spawnSync } from "child_process";
|
|
11
|
+
import { createRequire } from "module";
|
|
10
12
|
import { homedir } from "os";
|
|
11
13
|
import { join } from "path";
|
|
12
|
-
import * as readline from "readline/promises";
|
|
13
14
|
import { stdin as input, stdout as output } from "process";
|
|
15
|
+
var VERSION = (() => {
|
|
16
|
+
try {
|
|
17
|
+
return createRequire(import.meta.url)("../package.json").version;
|
|
18
|
+
} catch {
|
|
19
|
+
return "unknown";
|
|
20
|
+
}
|
|
21
|
+
})();
|
|
14
22
|
function parseArgs(argv) {
|
|
15
23
|
const positional = [];
|
|
16
24
|
const flags = {};
|
|
@@ -38,27 +46,30 @@ function parseArgs(argv) {
|
|
|
38
46
|
return { positional, flags };
|
|
39
47
|
}
|
|
40
48
|
function readFileConfig() {
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
for (const name of ["config.json", "config"]) {
|
|
50
|
+
const path = join(homedir(), ".arker", name);
|
|
51
|
+
if (!existsSync(path)) continue;
|
|
52
|
+
try {
|
|
53
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
54
|
+
} catch {
|
|
55
|
+
return {};
|
|
56
|
+
}
|
|
47
57
|
}
|
|
58
|
+
return {};
|
|
48
59
|
}
|
|
60
|
+
var DEFAULT_REGION = "us-west-2";
|
|
49
61
|
function clientFromArgs(args) {
|
|
50
62
|
const file = readFileConfig();
|
|
63
|
+
const explicitBaseUrl = args.flags["base-url"] ?? process.env.ARKER_BASE_URL;
|
|
64
|
+
const explicitRegion = args.flags.region ?? process.env.ARKER_REGION;
|
|
51
65
|
const apiKey = args.flags["api-key"] ?? process.env.ARKER_API_KEY ?? file.apiKey;
|
|
52
|
-
const baseUrl =
|
|
66
|
+
const baseUrl = explicitBaseUrl ?? (explicitRegion ? void 0 : file.baseUrl);
|
|
53
67
|
const controlBaseUrl = args.flags["control-base-url"] ?? process.env.ARKER_CONTROL_BASE_URL;
|
|
54
|
-
const region =
|
|
68
|
+
const region = explicitRegion ?? file.region ?? (baseUrl ? void 0 : DEFAULT_REGION);
|
|
55
69
|
const provider = args.flags.provider ?? process.env.ARKER_PROVIDER;
|
|
56
70
|
if (!apiKey) {
|
|
57
71
|
die("Missing API key. Set ARKER_API_KEY or pass --api-key.");
|
|
58
72
|
}
|
|
59
|
-
if (!baseUrl && !region) {
|
|
60
|
-
die("Missing region. Set ARKER_REGION or pass --region (e.g. us-west-2). --provider (aws|aws-burst) defaults to aws.");
|
|
61
|
-
}
|
|
62
73
|
return new Arker({ apiKey, baseUrl, region, provider, controlBaseUrl });
|
|
63
74
|
}
|
|
64
75
|
function out(value) {
|
|
@@ -81,7 +92,8 @@ function fmtVm(vm) {
|
|
|
81
92
|
const region = vm.region ?? "?";
|
|
82
93
|
const name = vm.name ?? "\u2014";
|
|
83
94
|
const state = vm.state ?? "?";
|
|
84
|
-
|
|
95
|
+
const id = vm.vm_id ?? vm.id;
|
|
96
|
+
return `${id} ${provider}-${region} ${state} ${name}`;
|
|
85
97
|
}
|
|
86
98
|
async function cmdVms(args, client) {
|
|
87
99
|
const sub = args.positional[0];
|
|
@@ -126,6 +138,10 @@ async function cmdVms(args, client) {
|
|
|
126
138
|
await cmdRun({ ...args, positional: rest }, client);
|
|
127
139
|
return;
|
|
128
140
|
}
|
|
141
|
+
case "resize": {
|
|
142
|
+
await cmdResize({ ...args, positional: rest }, client);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
129
145
|
default:
|
|
130
146
|
die(`unknown vms subcommand: ${sub}`);
|
|
131
147
|
}
|
|
@@ -144,14 +160,22 @@ async function cmdFork(args, client) {
|
|
|
144
160
|
sourceVmName = refPositional;
|
|
145
161
|
}
|
|
146
162
|
if (!sourceVmId && !sourceVmName) {
|
|
147
|
-
die("usage: arker fork <vm_name> | --source-vm-id <id> | --source-vm-name <name> [--source-org-id <org>]");
|
|
163
|
+
die("usage: arker fork <vm_name> | --source-vm-id <id> | --source-vm-name <name> [--source-org-id <org>]\n [--vcpu N] [--memory-mib N] [--disk-mib N] [--no-disk]");
|
|
148
164
|
}
|
|
165
|
+
const vcpu = numFlag(args, "vcpu");
|
|
166
|
+
const memoryMib = numFlag(args, "memory-mib");
|
|
167
|
+
const diskMib = numFlag(args, "disk-mib");
|
|
168
|
+
const hasResources = vcpu !== void 0 || memoryMib !== void 0 || diskMib !== void 0;
|
|
169
|
+
const resources = hasResources ? { vcpu: vcpu ?? null, memory_mib: memoryMib ?? null, disk_mib: diskMib ?? null } : void 0;
|
|
170
|
+
const disk = boolFlag(args, "no-disk") ? false : void 0;
|
|
149
171
|
const computer = await client.fork({
|
|
150
172
|
sourceVmId,
|
|
151
173
|
sourceVmName,
|
|
152
174
|
sourceOrgId,
|
|
153
175
|
name,
|
|
154
|
-
public: publicFlag
|
|
176
|
+
public: publicFlag,
|
|
177
|
+
...resources ? { resources } : {},
|
|
178
|
+
...disk !== void 0 ? { disk } : {}
|
|
155
179
|
});
|
|
156
180
|
out({ vm_id: computer.id });
|
|
157
181
|
}
|
|
@@ -159,13 +183,24 @@ async function cmdRun(args, client) {
|
|
|
159
183
|
const vmId = args.positional[0] ?? die("usage: arker run <vm_id> <command...>");
|
|
160
184
|
const command = args.positional.slice(1).join(" ");
|
|
161
185
|
if (!command) die("missing command to run");
|
|
186
|
+
const sessionIdx = numFlag(args, "session-idx");
|
|
162
187
|
const result = await client.vm(vmId).run(command, {
|
|
163
188
|
background: boolFlag(args, "background"),
|
|
164
189
|
timeout: numFlag(args, "timeout"),
|
|
165
190
|
acquire: args.flags.acquire,
|
|
166
|
-
release: args.flags.release
|
|
191
|
+
release: args.flags.release,
|
|
192
|
+
session_id: args.flags["session-id"],
|
|
193
|
+
...sessionIdx !== void 0 ? { session_idx: sessionIdx } : {}
|
|
167
194
|
});
|
|
195
|
+
if (args.flags.json) {
|
|
196
|
+
out(runResultForJson(result));
|
|
197
|
+
if (result.type === "completed") process.exitCode = result.exitCode === 0 ? 0 : result.exitCode;
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
168
200
|
if (result.type === "completed") {
|
|
201
|
+
if (result.memoryPartial) {
|
|
202
|
+
err(`Memory target partially applied: requested ${formatMib(result.memoryRequestedMib)}, achieved ${formatMib(result.memoryAchievedMib)}.`);
|
|
203
|
+
}
|
|
169
204
|
process.stdout.write(new TextDecoder().decode(result.stdout));
|
|
170
205
|
if (result.stderr.length) process.stderr.write(new TextDecoder().decode(result.stderr));
|
|
171
206
|
process.exitCode = result.exitCode === 0 ? 0 : result.exitCode;
|
|
@@ -173,6 +208,30 @@ async function cmdRun(args, client) {
|
|
|
173
208
|
}
|
|
174
209
|
out({ run_id: result.runId, state: result.state });
|
|
175
210
|
}
|
|
211
|
+
function formatMib(value) {
|
|
212
|
+
return typeof value === "number" ? `${value} MiB` : "unknown";
|
|
213
|
+
}
|
|
214
|
+
function runResultForJson(result) {
|
|
215
|
+
switch (result.type) {
|
|
216
|
+
case "completed":
|
|
217
|
+
return {
|
|
218
|
+
type: result.type,
|
|
219
|
+
runId: result.runId,
|
|
220
|
+
state: result.state,
|
|
221
|
+
stdout: new TextDecoder().decode(result.stdout),
|
|
222
|
+
stdoutEncoding: result.stdoutEncoding,
|
|
223
|
+
stderr: new TextDecoder().decode(result.stderr),
|
|
224
|
+
stderrEncoding: result.stderrEncoding,
|
|
225
|
+
exitCode: result.exitCode,
|
|
226
|
+
failReason: result.failReason,
|
|
227
|
+
memoryRequestedMib: result.memoryRequestedMib,
|
|
228
|
+
memoryAchievedMib: result.memoryAchievedMib,
|
|
229
|
+
memoryPartial: result.memoryPartial
|
|
230
|
+
};
|
|
231
|
+
case "background":
|
|
232
|
+
return result;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
176
235
|
async function cmdRuns(args, client) {
|
|
177
236
|
const sub = args.positional[0];
|
|
178
237
|
const rest = args.positional.slice(1);
|
|
@@ -314,51 +373,24 @@ async function cmdSync(args, client) {
|
|
|
314
373
|
}
|
|
315
374
|
output.write(await client.vm(vm).sync(path));
|
|
316
375
|
}
|
|
317
|
-
async function
|
|
318
|
-
const
|
|
319
|
-
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
const res = await client.vm(vm).listTunnels({
|
|
326
|
-
state: args.flags.state,
|
|
327
|
-
cursor: args.flags.cursor,
|
|
328
|
-
limit: numFlag(args, "limit")
|
|
329
|
-
});
|
|
330
|
-
if (args.flags.json) return out(res);
|
|
331
|
-
for (const t of res.tunnels) {
|
|
332
|
-
out(`${t.tunnel_key ?? "-"} ${t.port} ${t.state} ${t.protocol} ${t.url ?? "-"}`);
|
|
333
|
-
}
|
|
334
|
-
if (res.next_cursor) out(`# next_cursor=${res.next_cursor}`);
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
|
-
case "create": {
|
|
338
|
-
if (!vm) die("usage: arker tunnels create <vm_id> [--ports 80,8080] [--auth-mode open|authenticated]");
|
|
339
|
-
const tunnel = await client.vm(vm).createTunnel({
|
|
340
|
-
ports: parsePorts(args.flags.ports),
|
|
341
|
-
auth_mode: args.flags["auth-mode"]
|
|
342
|
-
});
|
|
343
|
-
return out(tunnel);
|
|
344
|
-
}
|
|
345
|
-
case "get": {
|
|
346
|
-
if (!vm) die("usage: arker tunnels get <vm_id> <key>");
|
|
347
|
-
const key = rest[1] ?? die("missing key");
|
|
348
|
-
out(await client.vm(vm).getTunnel(key));
|
|
349
|
-
return;
|
|
350
|
-
}
|
|
351
|
-
case "rm":
|
|
352
|
-
case "delete": {
|
|
353
|
-
if (!vm) die("usage: arker tunnels rm <vm_id> <key>");
|
|
354
|
-
const key = rest[1] ?? die("missing key");
|
|
355
|
-
const r = await client.vm(vm).deleteTunnel(key);
|
|
356
|
-
out(r.deleted ? `deleted tunnel ${key}` : "delete failed");
|
|
357
|
-
return;
|
|
358
|
-
}
|
|
359
|
-
default:
|
|
360
|
-
die(`usage: arker tunnels <ls|create|get|rm> ...`);
|
|
376
|
+
async function cmdResize(args, client) {
|
|
377
|
+
const vm = args.positional[0];
|
|
378
|
+
if (!vm) die("usage: arker resize <vm_id> [--memory-mib N] [--vcpu N] [--disk-mib N]");
|
|
379
|
+
const memoryMib = numFlag(args, "memory-mib");
|
|
380
|
+
const vcpu = numFlag(args, "vcpu");
|
|
381
|
+
const diskMib = numFlag(args, "disk-mib");
|
|
382
|
+
if (memoryMib === void 0 && vcpu === void 0 && diskMib === void 0) {
|
|
383
|
+
die("resize: pass at least one of --memory-mib, --vcpu, --disk-mib");
|
|
361
384
|
}
|
|
385
|
+
const updated = await client.vm(vm).resize({
|
|
386
|
+
resources: {
|
|
387
|
+
vcpu: vcpu ?? null,
|
|
388
|
+
memory_mib: memoryMib ?? null,
|
|
389
|
+
disk_mib: diskMib ?? null
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
if (args.flags.json) return out(updated);
|
|
393
|
+
out(fmtVm(updated));
|
|
362
394
|
}
|
|
363
395
|
async function cmdFilesystems(args, client) {
|
|
364
396
|
const sub = args.positional[0];
|
|
@@ -404,6 +436,10 @@ async function cmdFilesystems(args, client) {
|
|
|
404
436
|
async function cmdShell(args, client) {
|
|
405
437
|
let computer;
|
|
406
438
|
const vmIdArg = args.flags["vm-id"] ?? args.positional[0];
|
|
439
|
+
const explicitSessionId = args.flags["session-id"];
|
|
440
|
+
if (!vmIdArg && explicitSessionId) {
|
|
441
|
+
die("usage: arker shell <vm_id> --session-id <session_id>");
|
|
442
|
+
}
|
|
407
443
|
if (vmIdArg) {
|
|
408
444
|
computer = await client.vm(vmIdArg).refresh();
|
|
409
445
|
} else {
|
|
@@ -412,100 +448,114 @@ async function cmdShell(args, client) {
|
|
|
412
448
|
sourceVmName,
|
|
413
449
|
sourceOrgId: ARKER_ORG_ID
|
|
414
450
|
});
|
|
451
|
+
err(`forked ${computer.id}`);
|
|
452
|
+
}
|
|
453
|
+
let sessionId = explicitSessionId;
|
|
454
|
+
if (!sessionId) {
|
|
455
|
+
const session = await computer.createSession({
|
|
456
|
+
cwd: args.flags.cwd
|
|
457
|
+
});
|
|
458
|
+
sessionId = session.session_id ?? session.id;
|
|
459
|
+
if (!sessionId) die("createSession response missing session_id");
|
|
415
460
|
}
|
|
416
|
-
const
|
|
417
|
-
const
|
|
418
|
-
|
|
461
|
+
const persist = args.flags["no-persist"] === true ? false : boolFlag(args, "persist");
|
|
462
|
+
const colsFlag = numFlag(args, "cols");
|
|
463
|
+
const rowsFlag = numFlag(args, "rows");
|
|
464
|
+
const cols = colsFlag ?? output.columns ?? 80;
|
|
465
|
+
const rows = rowsFlag ?? output.rows ?? 24;
|
|
466
|
+
const cancelTtlSecs = numFlag(args, "cancel-ttl");
|
|
467
|
+
const pty = await computer.connectPty({
|
|
468
|
+
sessionId,
|
|
469
|
+
cols,
|
|
470
|
+
rows,
|
|
471
|
+
command: args.flags.command,
|
|
472
|
+
persist,
|
|
473
|
+
cancelTtlSecs
|
|
419
474
|
});
|
|
420
|
-
|
|
421
|
-
const
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
if (
|
|
435
|
-
|
|
436
|
-
exitCode = 1;
|
|
437
|
-
} else {
|
|
438
|
-
exitCode = step.exitCode;
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
if (exitAfter || preload === "exit") {
|
|
442
|
-
process.exit(exitCode);
|
|
443
|
-
}
|
|
444
|
-
const rl = readline.createInterface({ input, output, prompt: "> " });
|
|
445
|
-
rl.on("SIGINT", () => {
|
|
446
|
-
if (inFlight) {
|
|
447
|
-
process.stderr.write("^C\n");
|
|
448
|
-
return;
|
|
475
|
+
err(`connected ${computer.id} session ${sessionId}`);
|
|
476
|
+
const exitCode = await bridgePty(pty, {
|
|
477
|
+
fallbackCols: cols,
|
|
478
|
+
fallbackRows: rows,
|
|
479
|
+
autoResize: colsFlag === void 0 && rowsFlag === void 0 && Boolean(output.isTTY)
|
|
480
|
+
});
|
|
481
|
+
if (exitCode !== 0) process.exit(exitCode);
|
|
482
|
+
}
|
|
483
|
+
function bridgePty(pty, options) {
|
|
484
|
+
return new Promise((resolve) => {
|
|
485
|
+
let settled = false;
|
|
486
|
+
let rawEnabled = false;
|
|
487
|
+
const wasRaw = Boolean(input.isTTY && input.isRaw);
|
|
488
|
+
const restoreTerminal = () => {
|
|
489
|
+
if (rawEnabled && input.isTTY && typeof input.setRawMode === "function") {
|
|
490
|
+
input.setRawMode(wasRaw);
|
|
449
491
|
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
492
|
+
rawEnabled = false;
|
|
493
|
+
};
|
|
494
|
+
const finish = (code) => {
|
|
495
|
+
if (settled) return;
|
|
496
|
+
settled = true;
|
|
497
|
+
restoreTerminal();
|
|
498
|
+
input.off("data", onInput);
|
|
499
|
+
input.off("end", onInputEnd);
|
|
500
|
+
process.off("SIGWINCH", onResize);
|
|
501
|
+
process.off("SIGINT", onSigint);
|
|
502
|
+
process.off("SIGTERM", onSigterm);
|
|
503
|
+
process.off("SIGHUP", onSighup);
|
|
504
|
+
process.off("exit", restoreTerminal);
|
|
505
|
+
offData();
|
|
506
|
+
offClose();
|
|
507
|
+
offError();
|
|
508
|
+
resolve(code);
|
|
509
|
+
};
|
|
510
|
+
const onInput = (chunk) => {
|
|
511
|
+
pty.send(chunk);
|
|
512
|
+
};
|
|
513
|
+
const onInputEnd = () => {
|
|
514
|
+
pty.close();
|
|
515
|
+
};
|
|
516
|
+
const onResize = () => {
|
|
517
|
+
pty.resize(output.columns ?? options.fallbackCols, output.rows ?? options.fallbackRows);
|
|
518
|
+
};
|
|
519
|
+
const onSigint = () => {
|
|
520
|
+
pty.send(new Uint8Array([3]));
|
|
521
|
+
};
|
|
522
|
+
const onSigterm = () => {
|
|
523
|
+
pty.close();
|
|
524
|
+
finish(143);
|
|
525
|
+
};
|
|
526
|
+
const onSighup = () => {
|
|
527
|
+
pty.close();
|
|
528
|
+
finish(129);
|
|
529
|
+
};
|
|
530
|
+
const offData = pty.onData((data) => {
|
|
531
|
+
output.write(data);
|
|
453
532
|
});
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
const
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
if (
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
if (step.kind === "fatal") {
|
|
466
|
-
err(`shell ended: ${step.message}`);
|
|
467
|
-
exitCode = 1;
|
|
468
|
-
break;
|
|
469
|
-
}
|
|
470
|
-
if (step.kind === "recoverable") {
|
|
471
|
-
err(`error: ${step.message}`);
|
|
533
|
+
const offClose = pty.onClose(() => finish(0));
|
|
534
|
+
const offError = pty.onError((error) => {
|
|
535
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
536
|
+
err(`pty error: ${message}`);
|
|
537
|
+
});
|
|
538
|
+
process.once("exit", restoreTerminal);
|
|
539
|
+
pty.ready.then(() => {
|
|
540
|
+
if (settled) return;
|
|
541
|
+
if (input.isTTY && typeof input.setRawMode === "function") {
|
|
542
|
+
input.setRawMode(true);
|
|
543
|
+
rawEnabled = true;
|
|
472
544
|
}
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
545
|
+
input.resume();
|
|
546
|
+
input.on("data", onInput);
|
|
547
|
+
input.on("end", onInputEnd);
|
|
548
|
+
if (options.autoResize) process.on("SIGWINCH", onResize);
|
|
549
|
+
process.on("SIGINT", onSigint);
|
|
550
|
+
process.on("SIGTERM", onSigterm);
|
|
551
|
+
process.on("SIGHUP", onSighup);
|
|
552
|
+
if (options.autoResize) onResize();
|
|
553
|
+
}).catch((error) => {
|
|
554
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
555
|
+
err(`pty failed to open: ${message}`);
|
|
556
|
+
finish(1);
|
|
478
557
|
});
|
|
479
|
-
}
|
|
480
|
-
if (exitCode !== 0) process.exit(exitCode);
|
|
481
|
-
}
|
|
482
|
-
async function runShellLine(computer, sessionId, cmd, timeout) {
|
|
483
|
-
try {
|
|
484
|
-
const result = await computer.run(cmd, { session_id: sessionId, timeout });
|
|
485
|
-
if (result.type === "completed") {
|
|
486
|
-
if (result.stdout.length) process.stdout.write(new TextDecoder().decode(result.stdout));
|
|
487
|
-
if (result.stderr.length) process.stderr.write(new TextDecoder().decode(result.stderr));
|
|
488
|
-
const tail = result.stderr.length > 0 ? result.stderr[result.stderr.length - 1] : result.stdout.length > 0 ? result.stdout[result.stdout.length - 1] : void 0;
|
|
489
|
-
if (tail !== void 0 && tail !== 10) process.stdout.write("\n");
|
|
490
|
-
return { kind: "ok", exitCode: result.exitCode };
|
|
491
|
-
}
|
|
492
|
-
out({ run_id: result.runId });
|
|
493
|
-
return { kind: "ok", exitCode: 0 };
|
|
494
|
-
} catch (e) {
|
|
495
|
-
const message = e instanceof Error ? e.message : String(e);
|
|
496
|
-
const kind = classifyShellError(message, computer.id);
|
|
497
|
-
return { kind, message };
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
function classifyShellError(message, vmId) {
|
|
501
|
-
const msg = message.toLowerCase();
|
|
502
|
-
if (msg.includes("unauthor") || msg.includes("forbidden") || msg.includes("invalid api key")) {
|
|
503
|
-
return "fatal";
|
|
504
|
-
}
|
|
505
|
-
if ((msg.includes("not_found") || msg.includes("not found")) && msg.includes(vmId.toLowerCase())) {
|
|
506
|
-
return "fatal";
|
|
507
|
-
}
|
|
508
|
-
return "recoverable";
|
|
558
|
+
});
|
|
509
559
|
}
|
|
510
560
|
function numFlag(args, name) {
|
|
511
561
|
const v = args.flags[name];
|
|
@@ -519,10 +569,6 @@ function boolFlag(args, name) {
|
|
|
519
569
|
if (v === "false" || v === "0") return false;
|
|
520
570
|
return true;
|
|
521
571
|
}
|
|
522
|
-
function parsePorts(value) {
|
|
523
|
-
if (typeof value !== "string" || value.trim() === "") return void 0;
|
|
524
|
-
return value.split(",").map((part) => Number(part.trim())).filter((port) => Number.isFinite(port));
|
|
525
|
-
}
|
|
526
572
|
async function readAllStdin() {
|
|
527
573
|
const chunks = [];
|
|
528
574
|
for await (const chunk of input) chunks.push(chunk);
|
|
@@ -531,7 +577,7 @@ async function readAllStdin() {
|
|
|
531
577
|
function usage() {
|
|
532
578
|
out(
|
|
533
579
|
[
|
|
534
|
-
|
|
580
|
+
`arker v${VERSION}`,
|
|
535
581
|
"",
|
|
536
582
|
"Usage:",
|
|
537
583
|
" arker <command> [args]",
|
|
@@ -543,26 +589,46 @@ function usage() {
|
|
|
543
589
|
" arker fork --source-vm-id <id> fork by global id",
|
|
544
590
|
" arker fork --source-vm-name <n> --source-org-id <org>",
|
|
545
591
|
" fork by name in another org",
|
|
546
|
-
" arker
|
|
547
|
-
"
|
|
592
|
+
" arker fork <vm> [--vcpu N] [--memory-mib N] [--disk-mib N] [--no-disk]",
|
|
593
|
+
" fork with resource/network overrides",
|
|
594
|
+
" arker run <vm> <command> [--session-id <id>] [--session-idx N] run a command",
|
|
595
|
+
" arker resize <vm> [--memory-mib N] [--vcpu N] [--disk-mib N] resize a VM (PATCH)",
|
|
596
|
+
" arker shell [vm_id] native PTY shell (forks ubuntu-full if no vm)",
|
|
548
597
|
"",
|
|
549
598
|
"Resources:",
|
|
550
599
|
" arker vms <ls|get|rm|fork|run> ...",
|
|
551
600
|
" arker runs <ls|get|rm> <vm_id> ...",
|
|
552
601
|
" arker sessions <ls|get|create|rm> <vm_id> ...",
|
|
553
602
|
" arker syncs <ls|create|rm> <vm_id> ...",
|
|
554
|
-
" arker tunnels <ls|get|rm> <vm_id> ...",
|
|
555
603
|
" arker filesystems <ls|create|get|rm> ... (alias: fs)",
|
|
556
604
|
"",
|
|
557
605
|
"Flags:",
|
|
558
606
|
" --api-key <key> (or env ARKER_API_KEY)",
|
|
559
607
|
" --region <region> (or env ARKER_REGION; e.g. us-west-2)",
|
|
560
|
-
" --provider <aws
|
|
608
|
+
" --provider <aws> (or env ARKER_PROVIDER; default aws)",
|
|
561
609
|
" --base-url <url> override compute URL (env ARKER_BASE_URL)",
|
|
562
610
|
" --control-base-url <url> override CF Worker URL (env ARKER_CONTROL_BASE_URL)",
|
|
563
611
|
" --json emit JSON instead of tabular output",
|
|
564
612
|
"",
|
|
565
|
-
|
|
613
|
+
"Fork flags:",
|
|
614
|
+
" --vcpu <n> vCPU count for the new VM (capped by source max_vcpus)",
|
|
615
|
+
" --memory-mib <n> memory (MiB) for the new VM",
|
|
616
|
+
" --disk-mib <n> disk size (MiB) for the new VM",
|
|
617
|
+
" --no-disk fork a memory-backed (nodisk) VM",
|
|
618
|
+
"",
|
|
619
|
+
"Run flags:",
|
|
620
|
+
" --session-id <ulid> run in a specific existing session",
|
|
621
|
+
" --session-idx <n> run in the session at this index (default 0)",
|
|
622
|
+
" --background return a run id instead of blocking",
|
|
623
|
+
" --timeout <secs> per-run timeout",
|
|
624
|
+
" --acquire <list> warm resources before the run (cpu,memory,disk)",
|
|
625
|
+
" --release <list> release resources after the run (cpu,memory,disk)",
|
|
626
|
+
"",
|
|
627
|
+
"Shell flags:",
|
|
628
|
+
" --session-id <id> reconnect to an existing PTY session",
|
|
629
|
+
" --command <path> shell executable path (default: /bin/bash)",
|
|
630
|
+
" --cols <n> --rows <n> initial terminal size",
|
|
631
|
+
" --no-persist close the remote PTY process on disconnect"
|
|
566
632
|
].join("\n")
|
|
567
633
|
);
|
|
568
634
|
process.exit(2);
|
|
@@ -592,6 +658,10 @@ async function main() {
|
|
|
592
658
|
return await cmdSyncs(args, client);
|
|
593
659
|
case "shell":
|
|
594
660
|
return await cmdShell(args, client);
|
|
661
|
+
// SSH is descoped/unsupported and hidden from the interface. The
|
|
662
|
+
// implementation below (cmdSsh / cmdSshKeys) is kept intact; re-add
|
|
663
|
+
// the `ssh` / `ssh-keys` cases here and their help entries to expose
|
|
664
|
+
// it once the server-side SSH path is supported.
|
|
595
665
|
// Resources.
|
|
596
666
|
case "vms":
|
|
597
667
|
return await cmdVms(args, client);
|
|
@@ -599,8 +669,8 @@ async function main() {
|
|
|
599
669
|
return await cmdRuns(args, client);
|
|
600
670
|
case "sessions":
|
|
601
671
|
return await cmdSessions(args, client);
|
|
602
|
-
case "
|
|
603
|
-
return await
|
|
672
|
+
case "resize":
|
|
673
|
+
return await cmdResize(args, client);
|
|
604
674
|
case "filesystems":
|
|
605
675
|
case "fs":
|
|
606
676
|
return await cmdFilesystems(args, client);
|