@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.cjs
CHANGED
|
@@ -25,9 +25,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
25
25
|
|
|
26
26
|
// src/cli.ts
|
|
27
27
|
var import_node_fs = require("fs");
|
|
28
|
+
var import_node_child_process = require("child_process");
|
|
29
|
+
var import_node_module = require("module");
|
|
28
30
|
var import_node_os = require("os");
|
|
29
31
|
var import_node_path = require("path");
|
|
30
|
-
var readline = __toESM(require("readline/promises"), 1);
|
|
31
32
|
var import_node_process = require("process");
|
|
32
33
|
|
|
33
34
|
// src/index.ts
|
|
@@ -153,6 +154,12 @@ var Arker = class {
|
|
|
153
154
|
);
|
|
154
155
|
}
|
|
155
156
|
const sourceOrgId = src.sourceOrgId ?? (src.sourceVmName !== void 0 && GOLDEN_NAMES.has(src.sourceVmName) ? ARKER_ORG_ID : void 0);
|
|
157
|
+
const legacy = src;
|
|
158
|
+
const resources = src.resources ?? (legacy.vcpu_count != null || legacy.memory_mib != null || legacy.disk_mib != null ? {
|
|
159
|
+
vcpu: legacy.vcpu_count ?? null,
|
|
160
|
+
memory_mib: legacy.memory_mib ?? null,
|
|
161
|
+
disk_mib: legacy.disk_mib ?? null
|
|
162
|
+
} : null);
|
|
156
163
|
const body = {
|
|
157
164
|
source_vm_id: src.sourceVmId ?? null,
|
|
158
165
|
source_vm_name: src.sourceVmName ?? null,
|
|
@@ -160,13 +167,10 @@ var Arker = class {
|
|
|
160
167
|
name: src.name ?? null,
|
|
161
168
|
public: src.public ?? null,
|
|
162
169
|
network: src.network ?? null,
|
|
170
|
+
egress: src.egress ?? null,
|
|
163
171
|
disk: src.disk ?? true,
|
|
164
|
-
vcpu_count: src.vcpu_count ?? null,
|
|
165
|
-
memory_mib: src.memory_mib ?? null,
|
|
166
|
-
max_memory_mib: src.max_memory_mib ?? null,
|
|
167
|
-
disk_mib: src.disk_mib ?? null,
|
|
168
172
|
durable: src.durable ?? null,
|
|
169
|
-
|
|
173
|
+
resources
|
|
170
174
|
};
|
|
171
175
|
const useBurst = sourceOrgId === ARKER_ORG_ID && src.sourceVmName !== void 0 && isBurstRef(src.sourceVmName);
|
|
172
176
|
const baseUrl = useBurst && this.burstBaseUrl ? this.burstBaseUrl : this.baseUrl;
|
|
@@ -313,6 +317,10 @@ var Arker = class {
|
|
|
313
317
|
return retryDelay(this.retry, attempt);
|
|
314
318
|
}
|
|
315
319
|
/** @internal */
|
|
320
|
+
_authHeaders() {
|
|
321
|
+
return { authorization: `Bearer ${this.apiKey}` };
|
|
322
|
+
}
|
|
323
|
+
/** @internal */
|
|
316
324
|
_baseUrlFor(ref) {
|
|
317
325
|
if (isBurstRef(ref) && this.burstBaseUrl) return this.burstBaseUrl;
|
|
318
326
|
return this.baseUrl;
|
|
@@ -347,7 +355,6 @@ var VM = class _VM {
|
|
|
347
355
|
root_source_vm_name;
|
|
348
356
|
worker_id;
|
|
349
357
|
sessions;
|
|
350
|
-
tunnels;
|
|
351
358
|
constructor(client, vmId, baseUrl = client._baseUrlFor(vmId), data) {
|
|
352
359
|
this._client = client;
|
|
353
360
|
this.id = vmId;
|
|
@@ -470,8 +477,25 @@ var VM = class _VM {
|
|
|
470
477
|
}
|
|
471
478
|
throw new ArkerError(lastError?.code ?? "internal", lastError?.message ?? "write failed", 200);
|
|
472
479
|
}
|
|
480
|
+
/**
|
|
481
|
+
* Update this VM's resource allocation and/or network settings via
|
|
482
|
+
* `PATCH /v1/vms/{id}`. Returns the updated `Vm`.
|
|
483
|
+
*
|
|
484
|
+
* Accepts either a `PatchVmRequest` (`{ resources, network }`) or, for
|
|
485
|
+
* convenience, flat resource fields (`{ vcpu, memory_mib, disk_mib }`)
|
|
486
|
+
* which are folded into `resources`.
|
|
487
|
+
*/
|
|
473
488
|
async resize(request) {
|
|
474
|
-
|
|
489
|
+
const r = request;
|
|
490
|
+
const body = r.resources !== void 0 || r.vcpu === void 0 && r.memory_mib === void 0 && r.disk_mib === void 0 ? { resources: r.resources ?? null, network: r.network ?? null } : {
|
|
491
|
+
resources: {
|
|
492
|
+
vcpu: r.vcpu ?? null,
|
|
493
|
+
memory_mib: r.memory_mib ?? null,
|
|
494
|
+
disk_mib: r.disk_mib ?? null
|
|
495
|
+
},
|
|
496
|
+
network: r.network ?? null
|
|
497
|
+
};
|
|
498
|
+
return this._client._request("PATCH", vmPath(this.id), body, this.baseUrl);
|
|
475
499
|
}
|
|
476
500
|
async delete() {
|
|
477
501
|
return this._client._request("DELETE", vmPath(this.id), void 0, this.baseUrl);
|
|
@@ -527,22 +551,30 @@ var VM = class _VM {
|
|
|
527
551
|
async deleteSession(sessionId) {
|
|
528
552
|
return this._client._request("DELETE", `${vmPath(this.id)}/sessions/${pathSegment(sessionId)}`, void 0, this.baseUrl);
|
|
529
553
|
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
554
|
+
async connectPty(options = {}) {
|
|
555
|
+
const sessionId = options.sessionId ?? sessionIdFrom(await this.createSession());
|
|
556
|
+
const useTicket = options.useTicket ?? !isNodeRuntime();
|
|
557
|
+
const params = {
|
|
558
|
+
cols: options.cols,
|
|
559
|
+
rows: options.rows,
|
|
560
|
+
command: options.command,
|
|
561
|
+
persist: options.persist,
|
|
562
|
+
cancel_ttl_secs: options.cancelTtlSecs && options.cancelTtlSecs > 0 ? Math.floor(options.cancelTtlSecs) : void 0
|
|
563
|
+
};
|
|
564
|
+
let ticket;
|
|
565
|
+
if (useTicket) {
|
|
566
|
+
const response = await this._client._request(
|
|
567
|
+
"POST",
|
|
568
|
+
`${vmPath(this.id)}/sessions/${pathSegment(sessionId)}/pty-ticket`,
|
|
569
|
+
{},
|
|
570
|
+
this.baseUrl
|
|
571
|
+
);
|
|
572
|
+
ticket = response.ticket;
|
|
573
|
+
}
|
|
574
|
+
const url = buildPtyWebSocketUrl(this.baseUrl, this.id, sessionId, { ...params, ticket });
|
|
575
|
+
const factory = options.webSocketFactory ?? (useTicket ? browserPtyWebSocketFactory : nodePtyWebSocketFactory);
|
|
576
|
+
const socket = await factory(url, useTicket ? {} : { headers: this._client._authHeaders() });
|
|
577
|
+
return new PtyConnectionImpl(sessionId, socket);
|
|
546
578
|
}
|
|
547
579
|
};
|
|
548
580
|
function buildQuery(path, params) {
|
|
@@ -554,6 +586,176 @@ function buildQuery(path, params) {
|
|
|
554
586
|
const qs = usp.toString();
|
|
555
587
|
return qs ? `${path}?${qs}` : path;
|
|
556
588
|
}
|
|
589
|
+
function buildPtyWebSocketUrl(baseUrl, vmId, sessionId, params) {
|
|
590
|
+
const url = new URL(`${normalizeBaseUrl(baseUrl)}${vmPath(vmId)}/sessions/${pathSegment(sessionId)}/pty`);
|
|
591
|
+
if (url.protocol === "https:") url.protocol = "wss:";
|
|
592
|
+
else if (url.protocol === "http:") url.protocol = "ws:";
|
|
593
|
+
else throw new Error(`unsupported PTY WebSocket protocol: ${url.protocol}`);
|
|
594
|
+
for (const [key, value] of Object.entries(params)) {
|
|
595
|
+
if (value === void 0 || value === null) continue;
|
|
596
|
+
url.searchParams.set(key, String(value));
|
|
597
|
+
}
|
|
598
|
+
return url.toString();
|
|
599
|
+
}
|
|
600
|
+
function sessionIdFrom(session) {
|
|
601
|
+
const id = session.session_id ?? session.id;
|
|
602
|
+
if (!id) throw new ArkerError("internal", "createSession response missing session_id", 200);
|
|
603
|
+
return id;
|
|
604
|
+
}
|
|
605
|
+
function isNodeRuntime() {
|
|
606
|
+
return typeof process !== "undefined" && Boolean(process.versions?.node);
|
|
607
|
+
}
|
|
608
|
+
async function nodePtyWebSocketFactory(url, init) {
|
|
609
|
+
const ws = await import("ws");
|
|
610
|
+
return new ws.default(url, { headers: init.headers });
|
|
611
|
+
}
|
|
612
|
+
function browserPtyWebSocketFactory(url) {
|
|
613
|
+
if (typeof globalThis.WebSocket !== "function") {
|
|
614
|
+
throw new Error("WebSocket is not available in this runtime");
|
|
615
|
+
}
|
|
616
|
+
return new globalThis.WebSocket(url);
|
|
617
|
+
}
|
|
618
|
+
var PtyConnectionImpl = class {
|
|
619
|
+
constructor(sessionId, socket) {
|
|
620
|
+
this.sessionId = sessionId;
|
|
621
|
+
this.socket = socket;
|
|
622
|
+
try {
|
|
623
|
+
socket.binaryType = "arraybuffer";
|
|
624
|
+
} catch {
|
|
625
|
+
}
|
|
626
|
+
this.ready = waitForSocketOpen(socket);
|
|
627
|
+
addSocketListener(socket, "message", (event) => {
|
|
628
|
+
const data = messageData(event);
|
|
629
|
+
if (data !== void 0) this.emitData(bytesFromMessageData(data));
|
|
630
|
+
});
|
|
631
|
+
addSocketListener(socket, "close", (event) => this.emitClose(closeEvent(event)));
|
|
632
|
+
addSocketListener(socket, "error", (event) => this.emitError(event));
|
|
633
|
+
}
|
|
634
|
+
sessionId;
|
|
635
|
+
socket;
|
|
636
|
+
ready;
|
|
637
|
+
dataListeners = /* @__PURE__ */ new Set();
|
|
638
|
+
closeListeners = /* @__PURE__ */ new Set();
|
|
639
|
+
errorListeners = /* @__PURE__ */ new Set();
|
|
640
|
+
onData(listener) {
|
|
641
|
+
this.dataListeners.add(listener);
|
|
642
|
+
return () => this.dataListeners.delete(listener);
|
|
643
|
+
}
|
|
644
|
+
onClose(listener) {
|
|
645
|
+
this.closeListeners.add(listener);
|
|
646
|
+
return () => this.closeListeners.delete(listener);
|
|
647
|
+
}
|
|
648
|
+
onError(listener) {
|
|
649
|
+
this.errorListeners.add(listener);
|
|
650
|
+
return () => this.errorListeners.delete(listener);
|
|
651
|
+
}
|
|
652
|
+
send(data) {
|
|
653
|
+
this.socket.send(ptyInputBytes(data));
|
|
654
|
+
}
|
|
655
|
+
resize(cols, rows) {
|
|
656
|
+
this.socket.send(JSON.stringify({ type: "resize", cols: clampPtyDimension(cols), rows: clampPtyDimension(rows) }));
|
|
657
|
+
}
|
|
658
|
+
kill() {
|
|
659
|
+
this.socket.send(JSON.stringify({ type: "kill" }));
|
|
660
|
+
}
|
|
661
|
+
close(code, reason) {
|
|
662
|
+
this.socket.close(code, reason);
|
|
663
|
+
}
|
|
664
|
+
emitData(data) {
|
|
665
|
+
for (const listener of this.dataListeners) listener(data);
|
|
666
|
+
}
|
|
667
|
+
emitClose(event) {
|
|
668
|
+
for (const listener of this.closeListeners) listener(event);
|
|
669
|
+
}
|
|
670
|
+
emitError(error) {
|
|
671
|
+
for (const listener of this.errorListeners) listener(error);
|
|
672
|
+
}
|
|
673
|
+
};
|
|
674
|
+
function waitForSocketOpen(socket) {
|
|
675
|
+
if (socket.readyState === 1) return Promise.resolve();
|
|
676
|
+
return new Promise((resolve, reject) => {
|
|
677
|
+
let removeOpen;
|
|
678
|
+
let removeError;
|
|
679
|
+
let removeClose;
|
|
680
|
+
const cleanup = () => {
|
|
681
|
+
removeOpen?.();
|
|
682
|
+
removeError?.();
|
|
683
|
+
removeClose?.();
|
|
684
|
+
};
|
|
685
|
+
removeOpen = addSocketListener(socket, "open", () => {
|
|
686
|
+
cleanup();
|
|
687
|
+
resolve();
|
|
688
|
+
});
|
|
689
|
+
removeError = addSocketListener(socket, "error", (event) => {
|
|
690
|
+
cleanup();
|
|
691
|
+
reject(event instanceof Error ? event : new Error("PTY WebSocket failed to open"));
|
|
692
|
+
});
|
|
693
|
+
removeClose = addSocketListener(socket, "close", (event) => {
|
|
694
|
+
cleanup();
|
|
695
|
+
const ev = closeEvent(event);
|
|
696
|
+
reject(new Error(`PTY WebSocket closed before opening${ev.code ? ` (${ev.code})` : ""}`));
|
|
697
|
+
});
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
function addSocketListener(socket, type, listener) {
|
|
701
|
+
if (socket.addEventListener) {
|
|
702
|
+
socket.addEventListener(type, listener);
|
|
703
|
+
return () => socket.removeEventListener?.(type, listener);
|
|
704
|
+
}
|
|
705
|
+
if (socket.on) {
|
|
706
|
+
const nodeListener = (...args) => {
|
|
707
|
+
if (type === "message") listener({ data: args[0] });
|
|
708
|
+
else if (type === "close") listener({ code: args[0], reason: args[1] });
|
|
709
|
+
else listener(args[0]);
|
|
710
|
+
};
|
|
711
|
+
socket.on(type, nodeListener);
|
|
712
|
+
return () => socket.off?.(type, nodeListener);
|
|
713
|
+
}
|
|
714
|
+
return () => {
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
function messageData(event) {
|
|
718
|
+
if (event && typeof event === "object" && "data" in event) {
|
|
719
|
+
return event.data;
|
|
720
|
+
}
|
|
721
|
+
return void 0;
|
|
722
|
+
}
|
|
723
|
+
function closeEvent(event) {
|
|
724
|
+
if (!event || typeof event !== "object") return {};
|
|
725
|
+
const raw = event;
|
|
726
|
+
return {
|
|
727
|
+
code: typeof raw.code === "number" ? raw.code : void 0,
|
|
728
|
+
reason: typeof raw.reason === "string" ? raw.reason : void 0
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
function bytesFromMessageData(data) {
|
|
732
|
+
if (typeof data === "string") return new TextEncoder().encode(data);
|
|
733
|
+
if (data instanceof Uint8Array) return data;
|
|
734
|
+
if (data instanceof ArrayBuffer) return new Uint8Array(data);
|
|
735
|
+
if (ArrayBuffer.isView(data)) {
|
|
736
|
+
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
737
|
+
}
|
|
738
|
+
if (Array.isArray(data)) {
|
|
739
|
+
const chunks = data.map(bytesFromMessageData);
|
|
740
|
+
const total = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
741
|
+
const out2 = new Uint8Array(total);
|
|
742
|
+
let offset = 0;
|
|
743
|
+
for (const chunk of chunks) {
|
|
744
|
+
out2.set(chunk, offset);
|
|
745
|
+
offset += chunk.length;
|
|
746
|
+
}
|
|
747
|
+
return out2;
|
|
748
|
+
}
|
|
749
|
+
return new Uint8Array();
|
|
750
|
+
}
|
|
751
|
+
function ptyInputBytes(data) {
|
|
752
|
+
if (typeof data === "string") return new TextEncoder().encode(data);
|
|
753
|
+
return data;
|
|
754
|
+
}
|
|
755
|
+
function clampPtyDimension(value) {
|
|
756
|
+
if (!Number.isFinite(value)) return 1;
|
|
757
|
+
return Math.max(1, Math.min(1e3, Math.trunc(value)));
|
|
758
|
+
}
|
|
557
759
|
function normalizeBaseUrl(baseUrl) {
|
|
558
760
|
const trimmed = baseUrl.trim().replace(/\/+$/, "");
|
|
559
761
|
if (!trimmed) throw new Error("baseUrl must not be empty");
|
|
@@ -636,7 +838,10 @@ function parseRunResponse(payload) {
|
|
|
636
838
|
stderr: decodeBytes(stderr, stderrEncoding),
|
|
637
839
|
stderrEncoding,
|
|
638
840
|
exitCode: numberField(body.exit_code, "run response.exit_code"),
|
|
639
|
-
failReason: typeof body.fail_reason === "string" ? body.fail_reason : null
|
|
841
|
+
failReason: typeof body.fail_reason === "string" ? body.fail_reason : null,
|
|
842
|
+
memoryRequestedMib: optionalNumberOrNull(body.memory_requested_mib),
|
|
843
|
+
memoryAchievedMib: optionalNumberOrNull(body.memory_achieved_mib),
|
|
844
|
+
memoryPartial: typeof body.memory_partial === "boolean" ? body.memory_partial : void 0
|
|
640
845
|
};
|
|
641
846
|
}
|
|
642
847
|
if (typeof body.run_id === "string") {
|
|
@@ -707,6 +912,10 @@ function numberField(value, context) {
|
|
|
707
912
|
if (typeof value !== "number") throw new ArkerError("internal", `${context} must be a number`, 200);
|
|
708
913
|
return value;
|
|
709
914
|
}
|
|
915
|
+
function optionalNumberOrNull(value) {
|
|
916
|
+
if (value === null || typeof value === "number") return value;
|
|
917
|
+
return void 0;
|
|
918
|
+
}
|
|
710
919
|
function assertWriteComplete(result, context) {
|
|
711
920
|
if (result.complete && result.written) return;
|
|
712
921
|
throw new ArkerError("internal", `${context} did not complete`, 200);
|
|
@@ -755,6 +964,14 @@ function bufferConstructor() {
|
|
|
755
964
|
}
|
|
756
965
|
|
|
757
966
|
// src/cli.ts
|
|
967
|
+
var import_meta = {};
|
|
968
|
+
var VERSION = (() => {
|
|
969
|
+
try {
|
|
970
|
+
return (0, import_node_module.createRequire)(import_meta.url)("../package.json").version;
|
|
971
|
+
} catch {
|
|
972
|
+
return "unknown";
|
|
973
|
+
}
|
|
974
|
+
})();
|
|
758
975
|
function parseArgs(argv) {
|
|
759
976
|
const positional = [];
|
|
760
977
|
const flags = {};
|
|
@@ -782,27 +999,30 @@ function parseArgs(argv) {
|
|
|
782
999
|
return { positional, flags };
|
|
783
1000
|
}
|
|
784
1001
|
function readFileConfig() {
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
1002
|
+
for (const name of ["config.json", "config"]) {
|
|
1003
|
+
const path = (0, import_node_path.join)((0, import_node_os.homedir)(), ".arker", name);
|
|
1004
|
+
if (!(0, import_node_fs.existsSync)(path)) continue;
|
|
1005
|
+
try {
|
|
1006
|
+
return JSON.parse((0, import_node_fs.readFileSync)(path, "utf8"));
|
|
1007
|
+
} catch {
|
|
1008
|
+
return {};
|
|
1009
|
+
}
|
|
791
1010
|
}
|
|
1011
|
+
return {};
|
|
792
1012
|
}
|
|
1013
|
+
var DEFAULT_REGION = "us-west-2";
|
|
793
1014
|
function clientFromArgs(args) {
|
|
794
1015
|
const file = readFileConfig();
|
|
1016
|
+
const explicitBaseUrl = args.flags["base-url"] ?? process.env.ARKER_BASE_URL;
|
|
1017
|
+
const explicitRegion = args.flags.region ?? process.env.ARKER_REGION;
|
|
795
1018
|
const apiKey = args.flags["api-key"] ?? process.env.ARKER_API_KEY ?? file.apiKey;
|
|
796
|
-
const baseUrl =
|
|
1019
|
+
const baseUrl = explicitBaseUrl ?? (explicitRegion ? void 0 : file.baseUrl);
|
|
797
1020
|
const controlBaseUrl = args.flags["control-base-url"] ?? process.env.ARKER_CONTROL_BASE_URL;
|
|
798
|
-
const region =
|
|
1021
|
+
const region = explicitRegion ?? file.region ?? (baseUrl ? void 0 : DEFAULT_REGION);
|
|
799
1022
|
const provider = args.flags.provider ?? process.env.ARKER_PROVIDER;
|
|
800
1023
|
if (!apiKey) {
|
|
801
1024
|
die("Missing API key. Set ARKER_API_KEY or pass --api-key.");
|
|
802
1025
|
}
|
|
803
|
-
if (!baseUrl && !region) {
|
|
804
|
-
die("Missing region. Set ARKER_REGION or pass --region (e.g. us-west-2). --provider (aws|aws-burst) defaults to aws.");
|
|
805
|
-
}
|
|
806
1026
|
return new Arker({ apiKey, baseUrl, region, provider, controlBaseUrl });
|
|
807
1027
|
}
|
|
808
1028
|
function out(value) {
|
|
@@ -825,7 +1045,8 @@ function fmtVm(vm) {
|
|
|
825
1045
|
const region = vm.region ?? "?";
|
|
826
1046
|
const name = vm.name ?? "\u2014";
|
|
827
1047
|
const state = vm.state ?? "?";
|
|
828
|
-
|
|
1048
|
+
const id = vm.vm_id ?? vm.id;
|
|
1049
|
+
return `${id} ${provider}-${region} ${state} ${name}`;
|
|
829
1050
|
}
|
|
830
1051
|
async function cmdVms(args, client) {
|
|
831
1052
|
const sub = args.positional[0];
|
|
@@ -870,6 +1091,10 @@ async function cmdVms(args, client) {
|
|
|
870
1091
|
await cmdRun({ ...args, positional: rest }, client);
|
|
871
1092
|
return;
|
|
872
1093
|
}
|
|
1094
|
+
case "resize": {
|
|
1095
|
+
await cmdResize({ ...args, positional: rest }, client);
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
873
1098
|
default:
|
|
874
1099
|
die(`unknown vms subcommand: ${sub}`);
|
|
875
1100
|
}
|
|
@@ -888,14 +1113,22 @@ async function cmdFork(args, client) {
|
|
|
888
1113
|
sourceVmName = refPositional;
|
|
889
1114
|
}
|
|
890
1115
|
if (!sourceVmId && !sourceVmName) {
|
|
891
|
-
die("usage: arker fork <vm_name> | --source-vm-id <id> | --source-vm-name <name> [--source-org-id <org>]");
|
|
892
|
-
}
|
|
1116
|
+
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]");
|
|
1117
|
+
}
|
|
1118
|
+
const vcpu = numFlag(args, "vcpu");
|
|
1119
|
+
const memoryMib = numFlag(args, "memory-mib");
|
|
1120
|
+
const diskMib = numFlag(args, "disk-mib");
|
|
1121
|
+
const hasResources = vcpu !== void 0 || memoryMib !== void 0 || diskMib !== void 0;
|
|
1122
|
+
const resources = hasResources ? { vcpu: vcpu ?? null, memory_mib: memoryMib ?? null, disk_mib: diskMib ?? null } : void 0;
|
|
1123
|
+
const disk = boolFlag(args, "no-disk") ? false : void 0;
|
|
893
1124
|
const computer = await client.fork({
|
|
894
1125
|
sourceVmId,
|
|
895
1126
|
sourceVmName,
|
|
896
1127
|
sourceOrgId,
|
|
897
1128
|
name,
|
|
898
|
-
public: publicFlag
|
|
1129
|
+
public: publicFlag,
|
|
1130
|
+
...resources ? { resources } : {},
|
|
1131
|
+
...disk !== void 0 ? { disk } : {}
|
|
899
1132
|
});
|
|
900
1133
|
out({ vm_id: computer.id });
|
|
901
1134
|
}
|
|
@@ -903,13 +1136,24 @@ async function cmdRun(args, client) {
|
|
|
903
1136
|
const vmId = args.positional[0] ?? die("usage: arker run <vm_id> <command...>");
|
|
904
1137
|
const command = args.positional.slice(1).join(" ");
|
|
905
1138
|
if (!command) die("missing command to run");
|
|
1139
|
+
const sessionIdx = numFlag(args, "session-idx");
|
|
906
1140
|
const result = await client.vm(vmId).run(command, {
|
|
907
1141
|
background: boolFlag(args, "background"),
|
|
908
1142
|
timeout: numFlag(args, "timeout"),
|
|
909
1143
|
acquire: args.flags.acquire,
|
|
910
|
-
release: args.flags.release
|
|
1144
|
+
release: args.flags.release,
|
|
1145
|
+
session_id: args.flags["session-id"],
|
|
1146
|
+
...sessionIdx !== void 0 ? { session_idx: sessionIdx } : {}
|
|
911
1147
|
});
|
|
1148
|
+
if (args.flags.json) {
|
|
1149
|
+
out(runResultForJson(result));
|
|
1150
|
+
if (result.type === "completed") process.exitCode = result.exitCode === 0 ? 0 : result.exitCode;
|
|
1151
|
+
return;
|
|
1152
|
+
}
|
|
912
1153
|
if (result.type === "completed") {
|
|
1154
|
+
if (result.memoryPartial) {
|
|
1155
|
+
err(`Memory target partially applied: requested ${formatMib(result.memoryRequestedMib)}, achieved ${formatMib(result.memoryAchievedMib)}.`);
|
|
1156
|
+
}
|
|
913
1157
|
process.stdout.write(new TextDecoder().decode(result.stdout));
|
|
914
1158
|
if (result.stderr.length) process.stderr.write(new TextDecoder().decode(result.stderr));
|
|
915
1159
|
process.exitCode = result.exitCode === 0 ? 0 : result.exitCode;
|
|
@@ -917,6 +1161,30 @@ async function cmdRun(args, client) {
|
|
|
917
1161
|
}
|
|
918
1162
|
out({ run_id: result.runId, state: result.state });
|
|
919
1163
|
}
|
|
1164
|
+
function formatMib(value) {
|
|
1165
|
+
return typeof value === "number" ? `${value} MiB` : "unknown";
|
|
1166
|
+
}
|
|
1167
|
+
function runResultForJson(result) {
|
|
1168
|
+
switch (result.type) {
|
|
1169
|
+
case "completed":
|
|
1170
|
+
return {
|
|
1171
|
+
type: result.type,
|
|
1172
|
+
runId: result.runId,
|
|
1173
|
+
state: result.state,
|
|
1174
|
+
stdout: new TextDecoder().decode(result.stdout),
|
|
1175
|
+
stdoutEncoding: result.stdoutEncoding,
|
|
1176
|
+
stderr: new TextDecoder().decode(result.stderr),
|
|
1177
|
+
stderrEncoding: result.stderrEncoding,
|
|
1178
|
+
exitCode: result.exitCode,
|
|
1179
|
+
failReason: result.failReason,
|
|
1180
|
+
memoryRequestedMib: result.memoryRequestedMib,
|
|
1181
|
+
memoryAchievedMib: result.memoryAchievedMib,
|
|
1182
|
+
memoryPartial: result.memoryPartial
|
|
1183
|
+
};
|
|
1184
|
+
case "background":
|
|
1185
|
+
return result;
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
920
1188
|
async function cmdRuns(args, client) {
|
|
921
1189
|
const sub = args.positional[0];
|
|
922
1190
|
const rest = args.positional.slice(1);
|
|
@@ -1058,51 +1326,24 @@ async function cmdSync(args, client) {
|
|
|
1058
1326
|
}
|
|
1059
1327
|
import_node_process.stdout.write(await client.vm(vm).sync(path));
|
|
1060
1328
|
}
|
|
1061
|
-
async function
|
|
1062
|
-
const
|
|
1063
|
-
|
|
1064
|
-
const
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
for (const t of res.tunnels) {
|
|
1076
|
-
out(`${t.tunnel_key ?? "-"} ${t.port} ${t.state} ${t.protocol} ${t.url ?? "-"}`);
|
|
1077
|
-
}
|
|
1078
|
-
if (res.next_cursor) out(`# next_cursor=${res.next_cursor}`);
|
|
1079
|
-
return;
|
|
1080
|
-
}
|
|
1081
|
-
case "create": {
|
|
1082
|
-
if (!vm) die("usage: arker tunnels create <vm_id> [--ports 80,8080] [--auth-mode open|authenticated]");
|
|
1083
|
-
const tunnel = await client.vm(vm).createTunnel({
|
|
1084
|
-
ports: parsePorts(args.flags.ports),
|
|
1085
|
-
auth_mode: args.flags["auth-mode"]
|
|
1086
|
-
});
|
|
1087
|
-
return out(tunnel);
|
|
1088
|
-
}
|
|
1089
|
-
case "get": {
|
|
1090
|
-
if (!vm) die("usage: arker tunnels get <vm_id> <key>");
|
|
1091
|
-
const key = rest[1] ?? die("missing key");
|
|
1092
|
-
out(await client.vm(vm).getTunnel(key));
|
|
1093
|
-
return;
|
|
1329
|
+
async function cmdResize(args, client) {
|
|
1330
|
+
const vm = args.positional[0];
|
|
1331
|
+
if (!vm) die("usage: arker resize <vm_id> [--memory-mib N] [--vcpu N] [--disk-mib N]");
|
|
1332
|
+
const memoryMib = numFlag(args, "memory-mib");
|
|
1333
|
+
const vcpu = numFlag(args, "vcpu");
|
|
1334
|
+
const diskMib = numFlag(args, "disk-mib");
|
|
1335
|
+
if (memoryMib === void 0 && vcpu === void 0 && diskMib === void 0) {
|
|
1336
|
+
die("resize: pass at least one of --memory-mib, --vcpu, --disk-mib");
|
|
1337
|
+
}
|
|
1338
|
+
const updated = await client.vm(vm).resize({
|
|
1339
|
+
resources: {
|
|
1340
|
+
vcpu: vcpu ?? null,
|
|
1341
|
+
memory_mib: memoryMib ?? null,
|
|
1342
|
+
disk_mib: diskMib ?? null
|
|
1094
1343
|
}
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
const key = rest[1] ?? die("missing key");
|
|
1099
|
-
const r = await client.vm(vm).deleteTunnel(key);
|
|
1100
|
-
out(r.deleted ? `deleted tunnel ${key}` : "delete failed");
|
|
1101
|
-
return;
|
|
1102
|
-
}
|
|
1103
|
-
default:
|
|
1104
|
-
die(`usage: arker tunnels <ls|create|get|rm> ...`);
|
|
1105
|
-
}
|
|
1344
|
+
});
|
|
1345
|
+
if (args.flags.json) return out(updated);
|
|
1346
|
+
out(fmtVm(updated));
|
|
1106
1347
|
}
|
|
1107
1348
|
async function cmdFilesystems(args, client) {
|
|
1108
1349
|
const sub = args.positional[0];
|
|
@@ -1148,6 +1389,10 @@ async function cmdFilesystems(args, client) {
|
|
|
1148
1389
|
async function cmdShell(args, client) {
|
|
1149
1390
|
let computer;
|
|
1150
1391
|
const vmIdArg = args.flags["vm-id"] ?? args.positional[0];
|
|
1392
|
+
const explicitSessionId = args.flags["session-id"];
|
|
1393
|
+
if (!vmIdArg && explicitSessionId) {
|
|
1394
|
+
die("usage: arker shell <vm_id> --session-id <session_id>");
|
|
1395
|
+
}
|
|
1151
1396
|
if (vmIdArg) {
|
|
1152
1397
|
computer = await client.vm(vmIdArg).refresh();
|
|
1153
1398
|
} else {
|
|
@@ -1156,100 +1401,114 @@ async function cmdShell(args, client) {
|
|
|
1156
1401
|
sourceVmName,
|
|
1157
1402
|
sourceOrgId: ARKER_ORG_ID
|
|
1158
1403
|
});
|
|
1404
|
+
err(`forked ${computer.id}`);
|
|
1159
1405
|
}
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1406
|
+
let sessionId = explicitSessionId;
|
|
1407
|
+
if (!sessionId) {
|
|
1408
|
+
const session = await computer.createSession({
|
|
1409
|
+
cwd: args.flags.cwd
|
|
1410
|
+
});
|
|
1411
|
+
sessionId = session.session_id ?? session.id;
|
|
1412
|
+
if (!sessionId) die("createSession response missing session_id");
|
|
1413
|
+
}
|
|
1414
|
+
const persist = args.flags["no-persist"] === true ? false : boolFlag(args, "persist");
|
|
1415
|
+
const colsFlag = numFlag(args, "cols");
|
|
1416
|
+
const rowsFlag = numFlag(args, "rows");
|
|
1417
|
+
const cols = colsFlag ?? import_node_process.stdout.columns ?? 80;
|
|
1418
|
+
const rows = rowsFlag ?? import_node_process.stdout.rows ?? 24;
|
|
1419
|
+
const cancelTtlSecs = numFlag(args, "cancel-ttl");
|
|
1420
|
+
const pty = await computer.connectPty({
|
|
1421
|
+
sessionId,
|
|
1422
|
+
cols,
|
|
1423
|
+
rows,
|
|
1424
|
+
command: args.flags.command,
|
|
1425
|
+
persist,
|
|
1426
|
+
cancelTtlSecs
|
|
1163
1427
|
});
|
|
1164
|
-
|
|
1165
|
-
const
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
if (
|
|
1179
|
-
|
|
1180
|
-
exitCode = 1;
|
|
1181
|
-
} else {
|
|
1182
|
-
exitCode = step.exitCode;
|
|
1183
|
-
}
|
|
1184
|
-
}
|
|
1185
|
-
if (exitAfter || preload === "exit") {
|
|
1186
|
-
process.exit(exitCode);
|
|
1187
|
-
}
|
|
1188
|
-
const rl = readline.createInterface({ input: import_node_process.stdin, output: import_node_process.stdout, prompt: "> " });
|
|
1189
|
-
rl.on("SIGINT", () => {
|
|
1190
|
-
if (inFlight) {
|
|
1191
|
-
process.stderr.write("^C\n");
|
|
1192
|
-
return;
|
|
1428
|
+
err(`connected ${computer.id} session ${sessionId}`);
|
|
1429
|
+
const exitCode = await bridgePty(pty, {
|
|
1430
|
+
fallbackCols: cols,
|
|
1431
|
+
fallbackRows: rows,
|
|
1432
|
+
autoResize: colsFlag === void 0 && rowsFlag === void 0 && Boolean(import_node_process.stdout.isTTY)
|
|
1433
|
+
});
|
|
1434
|
+
if (exitCode !== 0) process.exit(exitCode);
|
|
1435
|
+
}
|
|
1436
|
+
function bridgePty(pty, options) {
|
|
1437
|
+
return new Promise((resolve) => {
|
|
1438
|
+
let settled = false;
|
|
1439
|
+
let rawEnabled = false;
|
|
1440
|
+
const wasRaw = Boolean(import_node_process.stdin.isTTY && import_node_process.stdin.isRaw);
|
|
1441
|
+
const restoreTerminal = () => {
|
|
1442
|
+
if (rawEnabled && import_node_process.stdin.isTTY && typeof import_node_process.stdin.setRawMode === "function") {
|
|
1443
|
+
import_node_process.stdin.setRawMode(wasRaw);
|
|
1193
1444
|
}
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1445
|
+
rawEnabled = false;
|
|
1446
|
+
};
|
|
1447
|
+
const finish = (code) => {
|
|
1448
|
+
if (settled) return;
|
|
1449
|
+
settled = true;
|
|
1450
|
+
restoreTerminal();
|
|
1451
|
+
import_node_process.stdin.off("data", onInput);
|
|
1452
|
+
import_node_process.stdin.off("end", onInputEnd);
|
|
1453
|
+
process.off("SIGWINCH", onResize);
|
|
1454
|
+
process.off("SIGINT", onSigint);
|
|
1455
|
+
process.off("SIGTERM", onSigterm);
|
|
1456
|
+
process.off("SIGHUP", onSighup);
|
|
1457
|
+
process.off("exit", restoreTerminal);
|
|
1458
|
+
offData();
|
|
1459
|
+
offClose();
|
|
1460
|
+
offError();
|
|
1461
|
+
resolve(code);
|
|
1462
|
+
};
|
|
1463
|
+
const onInput = (chunk) => {
|
|
1464
|
+
pty.send(chunk);
|
|
1465
|
+
};
|
|
1466
|
+
const onInputEnd = () => {
|
|
1467
|
+
pty.close();
|
|
1468
|
+
};
|
|
1469
|
+
const onResize = () => {
|
|
1470
|
+
pty.resize(import_node_process.stdout.columns ?? options.fallbackCols, import_node_process.stdout.rows ?? options.fallbackRows);
|
|
1471
|
+
};
|
|
1472
|
+
const onSigint = () => {
|
|
1473
|
+
pty.send(new Uint8Array([3]));
|
|
1474
|
+
};
|
|
1475
|
+
const onSigterm = () => {
|
|
1476
|
+
pty.close();
|
|
1477
|
+
finish(143);
|
|
1478
|
+
};
|
|
1479
|
+
const onSighup = () => {
|
|
1480
|
+
pty.close();
|
|
1481
|
+
finish(129);
|
|
1482
|
+
};
|
|
1483
|
+
const offData = pty.onData((data) => {
|
|
1484
|
+
import_node_process.stdout.write(data);
|
|
1197
1485
|
});
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
const
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
if (
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
if (step.kind === "fatal") {
|
|
1210
|
-
err(`shell ended: ${step.message}`);
|
|
1211
|
-
exitCode = 1;
|
|
1212
|
-
break;
|
|
1213
|
-
}
|
|
1214
|
-
if (step.kind === "recoverable") {
|
|
1215
|
-
err(`error: ${step.message}`);
|
|
1486
|
+
const offClose = pty.onClose(() => finish(0));
|
|
1487
|
+
const offError = pty.onError((error) => {
|
|
1488
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1489
|
+
err(`pty error: ${message}`);
|
|
1490
|
+
});
|
|
1491
|
+
process.once("exit", restoreTerminal);
|
|
1492
|
+
pty.ready.then(() => {
|
|
1493
|
+
if (settled) return;
|
|
1494
|
+
if (import_node_process.stdin.isTTY && typeof import_node_process.stdin.setRawMode === "function") {
|
|
1495
|
+
import_node_process.stdin.setRawMode(true);
|
|
1496
|
+
rawEnabled = true;
|
|
1216
1497
|
}
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1498
|
+
import_node_process.stdin.resume();
|
|
1499
|
+
import_node_process.stdin.on("data", onInput);
|
|
1500
|
+
import_node_process.stdin.on("end", onInputEnd);
|
|
1501
|
+
if (options.autoResize) process.on("SIGWINCH", onResize);
|
|
1502
|
+
process.on("SIGINT", onSigint);
|
|
1503
|
+
process.on("SIGTERM", onSigterm);
|
|
1504
|
+
process.on("SIGHUP", onSighup);
|
|
1505
|
+
if (options.autoResize) onResize();
|
|
1506
|
+
}).catch((error) => {
|
|
1507
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1508
|
+
err(`pty failed to open: ${message}`);
|
|
1509
|
+
finish(1);
|
|
1222
1510
|
});
|
|
1223
|
-
}
|
|
1224
|
-
if (exitCode !== 0) process.exit(exitCode);
|
|
1225
|
-
}
|
|
1226
|
-
async function runShellLine(computer, sessionId, cmd, timeout) {
|
|
1227
|
-
try {
|
|
1228
|
-
const result = await computer.run(cmd, { session_id: sessionId, timeout });
|
|
1229
|
-
if (result.type === "completed") {
|
|
1230
|
-
if (result.stdout.length) process.stdout.write(new TextDecoder().decode(result.stdout));
|
|
1231
|
-
if (result.stderr.length) process.stderr.write(new TextDecoder().decode(result.stderr));
|
|
1232
|
-
const tail = result.stderr.length > 0 ? result.stderr[result.stderr.length - 1] : result.stdout.length > 0 ? result.stdout[result.stdout.length - 1] : void 0;
|
|
1233
|
-
if (tail !== void 0 && tail !== 10) process.stdout.write("\n");
|
|
1234
|
-
return { kind: "ok", exitCode: result.exitCode };
|
|
1235
|
-
}
|
|
1236
|
-
out({ run_id: result.runId });
|
|
1237
|
-
return { kind: "ok", exitCode: 0 };
|
|
1238
|
-
} catch (e) {
|
|
1239
|
-
const message = e instanceof Error ? e.message : String(e);
|
|
1240
|
-
const kind = classifyShellError(message, computer.id);
|
|
1241
|
-
return { kind, message };
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1244
|
-
function classifyShellError(message, vmId) {
|
|
1245
|
-
const msg = message.toLowerCase();
|
|
1246
|
-
if (msg.includes("unauthor") || msg.includes("forbidden") || msg.includes("invalid api key")) {
|
|
1247
|
-
return "fatal";
|
|
1248
|
-
}
|
|
1249
|
-
if ((msg.includes("not_found") || msg.includes("not found")) && msg.includes(vmId.toLowerCase())) {
|
|
1250
|
-
return "fatal";
|
|
1251
|
-
}
|
|
1252
|
-
return "recoverable";
|
|
1511
|
+
});
|
|
1253
1512
|
}
|
|
1254
1513
|
function numFlag(args, name) {
|
|
1255
1514
|
const v = args.flags[name];
|
|
@@ -1263,10 +1522,6 @@ function boolFlag(args, name) {
|
|
|
1263
1522
|
if (v === "false" || v === "0") return false;
|
|
1264
1523
|
return true;
|
|
1265
1524
|
}
|
|
1266
|
-
function parsePorts(value) {
|
|
1267
|
-
if (typeof value !== "string" || value.trim() === "") return void 0;
|
|
1268
|
-
return value.split(",").map((part) => Number(part.trim())).filter((port) => Number.isFinite(port));
|
|
1269
|
-
}
|
|
1270
1525
|
async function readAllStdin() {
|
|
1271
1526
|
const chunks = [];
|
|
1272
1527
|
for await (const chunk of import_node_process.stdin) chunks.push(chunk);
|
|
@@ -1275,7 +1530,7 @@ async function readAllStdin() {
|
|
|
1275
1530
|
function usage() {
|
|
1276
1531
|
out(
|
|
1277
1532
|
[
|
|
1278
|
-
|
|
1533
|
+
`arker v${VERSION}`,
|
|
1279
1534
|
"",
|
|
1280
1535
|
"Usage:",
|
|
1281
1536
|
" arker <command> [args]",
|
|
@@ -1287,26 +1542,46 @@ function usage() {
|
|
|
1287
1542
|
" arker fork --source-vm-id <id> fork by global id",
|
|
1288
1543
|
" arker fork --source-vm-name <n> --source-org-id <org>",
|
|
1289
1544
|
" fork by name in another org",
|
|
1290
|
-
" arker
|
|
1291
|
-
"
|
|
1545
|
+
" arker fork <vm> [--vcpu N] [--memory-mib N] [--disk-mib N] [--no-disk]",
|
|
1546
|
+
" fork with resource/network overrides",
|
|
1547
|
+
" arker run <vm> <command> [--session-id <id>] [--session-idx N] run a command",
|
|
1548
|
+
" arker resize <vm> [--memory-mib N] [--vcpu N] [--disk-mib N] resize a VM (PATCH)",
|
|
1549
|
+
" arker shell [vm_id] native PTY shell (forks ubuntu-full if no vm)",
|
|
1292
1550
|
"",
|
|
1293
1551
|
"Resources:",
|
|
1294
1552
|
" arker vms <ls|get|rm|fork|run> ...",
|
|
1295
1553
|
" arker runs <ls|get|rm> <vm_id> ...",
|
|
1296
1554
|
" arker sessions <ls|get|create|rm> <vm_id> ...",
|
|
1297
1555
|
" arker syncs <ls|create|rm> <vm_id> ...",
|
|
1298
|
-
" arker tunnels <ls|get|rm> <vm_id> ...",
|
|
1299
1556
|
" arker filesystems <ls|create|get|rm> ... (alias: fs)",
|
|
1300
1557
|
"",
|
|
1301
1558
|
"Flags:",
|
|
1302
1559
|
" --api-key <key> (or env ARKER_API_KEY)",
|
|
1303
1560
|
" --region <region> (or env ARKER_REGION; e.g. us-west-2)",
|
|
1304
|
-
" --provider <aws
|
|
1561
|
+
" --provider <aws> (or env ARKER_PROVIDER; default aws)",
|
|
1305
1562
|
" --base-url <url> override compute URL (env ARKER_BASE_URL)",
|
|
1306
1563
|
" --control-base-url <url> override CF Worker URL (env ARKER_CONTROL_BASE_URL)",
|
|
1307
1564
|
" --json emit JSON instead of tabular output",
|
|
1308
1565
|
"",
|
|
1309
|
-
|
|
1566
|
+
"Fork flags:",
|
|
1567
|
+
" --vcpu <n> vCPU count for the new VM (capped by source max_vcpus)",
|
|
1568
|
+
" --memory-mib <n> memory (MiB) for the new VM",
|
|
1569
|
+
" --disk-mib <n> disk size (MiB) for the new VM",
|
|
1570
|
+
" --no-disk fork a memory-backed (nodisk) VM",
|
|
1571
|
+
"",
|
|
1572
|
+
"Run flags:",
|
|
1573
|
+
" --session-id <ulid> run in a specific existing session",
|
|
1574
|
+
" --session-idx <n> run in the session at this index (default 0)",
|
|
1575
|
+
" --background return a run id instead of blocking",
|
|
1576
|
+
" --timeout <secs> per-run timeout",
|
|
1577
|
+
" --acquire <list> warm resources before the run (cpu,memory,disk)",
|
|
1578
|
+
" --release <list> release resources after the run (cpu,memory,disk)",
|
|
1579
|
+
"",
|
|
1580
|
+
"Shell flags:",
|
|
1581
|
+
" --session-id <id> reconnect to an existing PTY session",
|
|
1582
|
+
" --command <path> shell executable path (default: /bin/bash)",
|
|
1583
|
+
" --cols <n> --rows <n> initial terminal size",
|
|
1584
|
+
" --no-persist close the remote PTY process on disconnect"
|
|
1310
1585
|
].join("\n")
|
|
1311
1586
|
);
|
|
1312
1587
|
process.exit(2);
|
|
@@ -1336,6 +1611,10 @@ async function main() {
|
|
|
1336
1611
|
return await cmdSyncs(args, client);
|
|
1337
1612
|
case "shell":
|
|
1338
1613
|
return await cmdShell(args, client);
|
|
1614
|
+
// SSH is descoped/unsupported and hidden from the interface. The
|
|
1615
|
+
// implementation below (cmdSsh / cmdSshKeys) is kept intact; re-add
|
|
1616
|
+
// the `ssh` / `ssh-keys` cases here and their help entries to expose
|
|
1617
|
+
// it once the server-side SSH path is supported.
|
|
1339
1618
|
// Resources.
|
|
1340
1619
|
case "vms":
|
|
1341
1620
|
return await cmdVms(args, client);
|
|
@@ -1343,8 +1622,8 @@ async function main() {
|
|
|
1343
1622
|
return await cmdRuns(args, client);
|
|
1344
1623
|
case "sessions":
|
|
1345
1624
|
return await cmdSessions(args, client);
|
|
1346
|
-
case "
|
|
1347
|
-
return await
|
|
1625
|
+
case "resize":
|
|
1626
|
+
return await cmdResize(args, client);
|
|
1348
1627
|
case "filesystems":
|
|
1349
1628
|
case "fs":
|
|
1350
1629
|
return await cmdFilesystems(args, client);
|