@computesdk/cli 2.1.0 → 2.2.0
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 +11 -0
- package/dist/index.js +190 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,6 +44,17 @@ override, pass `--org <slug>` (on the root command or any `sandboxes` /
|
|
|
44
44
|
on the request. Precedence: `--org` > `COMPUTE_ORG` > the stored login's org.
|
|
45
45
|
The platform ignores the header for org API keys.
|
|
46
46
|
|
|
47
|
+
For `compute sandboxes exec` and `compute sandboxes spawn`, everything after
|
|
48
|
+
the command's first word goes to the sandbox untouched — flags like `uname
|
|
49
|
+
-a` or `node -e` are not CLI options. Pass CLI options (`--json`,
|
|
50
|
+
`--timeout-ms`, `--cwd`, `-e/--env`, `--stdin`, `--org`) before the command;
|
|
51
|
+
a bare `--` before the command is optional but supported.
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
compute sandboxes exec sb1 uname -a
|
|
55
|
+
compute sandboxes spawn sb1 --cwd /app -e NODE_ENV=production -- npm run dev
|
|
56
|
+
```
|
|
57
|
+
|
|
47
58
|
## Migrating from @computesdk/cli 1.x
|
|
48
59
|
|
|
49
60
|
v2 removes the legacy console authentication and its commands:
|
package/dist/index.js
CHANGED
|
@@ -835,15 +835,15 @@ function maxPriceFields(maxBid, maxBidPer) {
|
|
|
835
835
|
throw new ActionsCliError("invalid_argument", "--max-bid-per requires --max-bid.");
|
|
836
836
|
}
|
|
837
837
|
if (maxBid === void 0) return void 0;
|
|
838
|
-
const
|
|
839
|
-
if (!/^\d+(\.\d+)?([eE][+-]?\d+)?$/.test(maxBid) || !Number.isFinite(
|
|
838
|
+
const usd2 = Number(maxBid);
|
|
839
|
+
if (!/^\d+(\.\d+)?([eE][+-]?\d+)?$/.test(maxBid) || !Number.isFinite(usd2) || usd2 <= 0) {
|
|
840
840
|
throw new ActionsCliError("invalid_argument", `Invalid --max-bid "${maxBid}". Expected a positive dollar amount (e.g. 0.12).`);
|
|
841
841
|
}
|
|
842
842
|
const per = maxBidPer ?? "second";
|
|
843
843
|
if (per !== "second" && per !== "minute" && per !== "hour") {
|
|
844
844
|
throw new ActionsCliError("invalid_argument", `--max-bid-per must be second, minute, or hour, got "${maxBidPer}".`);
|
|
845
845
|
}
|
|
846
|
-
return { maxPriceUsd:
|
|
846
|
+
return { maxPriceUsd: usd2, maxPricePer: per };
|
|
847
847
|
}
|
|
848
848
|
function parseVaultKind(kind) {
|
|
849
849
|
if (kind === void 0 || kind === "secret" || kind === "variable") return kind ?? "secret";
|
|
@@ -1377,8 +1377,8 @@ function parseRate(price, per) {
|
|
|
1377
1377
|
if (price === void 0) {
|
|
1378
1378
|
throw new ActionsCliError("invalid_argument", "A price is required \u2014 pass --price <usd>.");
|
|
1379
1379
|
}
|
|
1380
|
-
const
|
|
1381
|
-
if (!USD_RE.test(price) || !Number.isFinite(
|
|
1380
|
+
const usd2 = Number(price);
|
|
1381
|
+
if (!USD_RE.test(price) || !Number.isFinite(usd2) || usd2 <= 0) {
|
|
1382
1382
|
throw new ActionsCliError(
|
|
1383
1383
|
"invalid_argument",
|
|
1384
1384
|
`Invalid --price "${price}". Expected a positive dollar amount (e.g. 0.12).`
|
|
@@ -1391,7 +1391,7 @@ function parseRate(price, per) {
|
|
|
1391
1391
|
`--per must be second, minute, or hour, got "${per}".`
|
|
1392
1392
|
);
|
|
1393
1393
|
}
|
|
1394
|
-
return { usd, per: unit };
|
|
1394
|
+
return { usd: usd2, per: unit };
|
|
1395
1395
|
}
|
|
1396
1396
|
function parseCapacity(value) {
|
|
1397
1397
|
if (value === void 0) return void 0;
|
|
@@ -1493,11 +1493,11 @@ function credentialBody(fields, values) {
|
|
|
1493
1493
|
}
|
|
1494
1494
|
return { fields: values };
|
|
1495
1495
|
}
|
|
1496
|
-
function formatUsd(
|
|
1497
|
-
return `$${
|
|
1496
|
+
function formatUsd(usd2) {
|
|
1497
|
+
return `$${usd2.toFixed(6).replace(/\.?0+$/, "")}`;
|
|
1498
1498
|
}
|
|
1499
|
-
function formatRate(
|
|
1500
|
-
return `${formatUsd(
|
|
1499
|
+
function formatRate(usd2, per) {
|
|
1500
|
+
return `${formatUsd(usd2)}/${per}`;
|
|
1501
1501
|
}
|
|
1502
1502
|
function formatListingStatus(ask) {
|
|
1503
1503
|
let label;
|
|
@@ -1843,6 +1843,33 @@ ${hints}`
|
|
|
1843
1843
|
|
|
1844
1844
|
// src/sandboxes.ts
|
|
1845
1845
|
import pc3 from "picocolors";
|
|
1846
|
+
function parseMaxPrice(value, per) {
|
|
1847
|
+
if (value === void 0) {
|
|
1848
|
+
if (per !== void 0) throw new Error("--max-price-per requires --max-price.");
|
|
1849
|
+
return void 0;
|
|
1850
|
+
}
|
|
1851
|
+
let usdText = value;
|
|
1852
|
+
let unit = per;
|
|
1853
|
+
const slash = value.indexOf("/");
|
|
1854
|
+
if (slash !== -1) {
|
|
1855
|
+
usdText = value.slice(0, slash);
|
|
1856
|
+
const inline = value.slice(slash + 1);
|
|
1857
|
+
if (per !== void 0 && per !== inline) {
|
|
1858
|
+
throw new Error(`--max-price "${value}" conflicts with --max-price-per "${per}".`);
|
|
1859
|
+
}
|
|
1860
|
+
unit = inline;
|
|
1861
|
+
}
|
|
1862
|
+
const usd2 = Number(usdText);
|
|
1863
|
+
if (!/^\d+(\.\d+)?([eE][+-]?\d+)?$/.test(usdText) || !Number.isFinite(usd2) || usd2 <= 0) {
|
|
1864
|
+
throw new Error(`Invalid --max-price "${value}". Expected a positive dollar amount like 0.12/hour.`);
|
|
1865
|
+
}
|
|
1866
|
+
if (unit !== "second" && unit !== "minute" && unit !== "hour") {
|
|
1867
|
+
throw new Error(
|
|
1868
|
+
"--max-price needs a unit \u2014 write it as <usd>/<unit> (e.g. --max-price 0.12/hour) or pass --max-price-per hour."
|
|
1869
|
+
);
|
|
1870
|
+
}
|
|
1871
|
+
return { usd: usd2, per: unit };
|
|
1872
|
+
}
|
|
1846
1873
|
function shellQuote(arg) {
|
|
1847
1874
|
return `'${arg.replace(/'/g, `'\\''`)}'`;
|
|
1848
1875
|
}
|
|
@@ -1854,12 +1881,40 @@ function printSandbox(s) {
|
|
|
1854
1881
|
console.log(` image: ${s.image ?? "\u2014"}${s.requestedImage !== null && s.requestedImage !== s.image ? ` ${pc3.dim(`(requested: ${s.requestedImage})`)}` : ""}`);
|
|
1855
1882
|
}
|
|
1856
1883
|
if (s.destroyError) console.log(` destroyError: ${pc3.red(s.destroyError)}`);
|
|
1884
|
+
if (s.placement) {
|
|
1885
|
+
const p2 = s.placement;
|
|
1886
|
+
const box = p2.box ? ` / ${p2.box.sizeName ?? "custom"}${p2.box.resources ? ` (${p2.box.resources.cpus ?? "?"} vCPU / ${p2.box.resources.memoryMb ?? "?"} MB)` : ""}` : "";
|
|
1887
|
+
console.log(
|
|
1888
|
+
` provider: ${p2.box?.provider ?? s.provider ?? "\u2014"}${box} size: ${p2.size ?? "\u2014"} order: ${p2.orderType ?? "\u2014"} rate: $${p2.rate.usd}/${p2.rate.per}`
|
|
1889
|
+
);
|
|
1890
|
+
}
|
|
1857
1891
|
if (attach !== void 0) {
|
|
1858
1892
|
console.log(
|
|
1859
1893
|
attach === null ? " attach: none (market fill or ambient provider \u2014 platform drive only)" : ` attach: ${attach.provider} / ${attach.providerSandboxId}${attach.region ? ` (${attach.region})` : ""}`
|
|
1860
1894
|
);
|
|
1861
1895
|
}
|
|
1862
1896
|
}
|
|
1897
|
+
var usd = (n, suffix = "") => n === void 0 ? "\u2014" : `$${n.toFixed(4).replace(/0+$/, "").replace(/\.$/, ".00")}${suffix}`;
|
|
1898
|
+
function printQuote(q, timeoutMs) {
|
|
1899
|
+
console.log(`quote: ${q.ok ? pc3.green("ok") : pc3.red(q.reason ?? "unfillable")}`);
|
|
1900
|
+
const box = q.placement?.box;
|
|
1901
|
+
console.log(
|
|
1902
|
+
` size: ${q.placement?.size ?? "\u2014"} provider: ${q.placement?.provider ?? "\u2014"}` + (box ? ` box: ${box.sizeName ?? "custom"} (${box.provider}${box.resources ? `, ${box.resources.cpus ?? "?"} vCPU / ${box.resources.memoryMb ?? "?"} MB` : ""})` : "")
|
|
1903
|
+
);
|
|
1904
|
+
console.log(` order type: ${q.orderType} order: ${q.providerOrder.join(", ")}`);
|
|
1905
|
+
if (q.rateUsd) {
|
|
1906
|
+
console.log(` rate: ${usd(q.rateUsd.perHour, "/hour")} cheapest live: ${usd(q.cheapestLiveUsdPerHour, "/hr")} reference: ${usd(q.referenceUsdPerHour, "/hr")}`);
|
|
1907
|
+
} else if (q.rate) {
|
|
1908
|
+
console.log(` rate: $${q.rate.usd}/${q.rate.per}`);
|
|
1909
|
+
}
|
|
1910
|
+
const timeout = timeoutMs !== void 0 ? ` for ${timeoutMs}ms` : "";
|
|
1911
|
+
console.log(` est. cost${timeout}: ${usd(q.estimatedCostUsd)} required hold: ${usd(q.requiredHoldUsd)}`);
|
|
1912
|
+
console.log(
|
|
1913
|
+
` cap: ${q.maxPrice ? `$${q.maxPrice.usd}/${q.maxPrice.per}` : usd(q.marketCapUsdPerHour, "/hr")} protection limit: ${usd(q.protectionLimitUsdPerHour, "/hr")} balance: ${usd(q.creditBalanceUsd)}`
|
|
1914
|
+
);
|
|
1915
|
+
if (!q.ok && q.topUpPath) console.log(` ${pc3.dim(`\u2192 ${q.topUpPath}`)}`);
|
|
1916
|
+
if (q.liveAskDepth !== void 0) console.log(` ${pc3.dim(`live asks: ${q.liveAskDepth}`)}`);
|
|
1917
|
+
}
|
|
1863
1918
|
function printProcess(p2) {
|
|
1864
1919
|
const exit = p2.status === "exited" ? `exit=${p2.exitCode ?? "?"}${p2.signal ? ` (${p2.signal})` : ""}` : "";
|
|
1865
1920
|
const stdin = p2.stdin && p2.status === "running" ? " [stdin open]" : "";
|
|
@@ -1872,9 +1927,83 @@ function printSnapshot(s) {
|
|
|
1872
1927
|
` provider: ${s.provider}${s.region ? ` (${s.region})` : ""} label: ${s.label ?? "\u2014"} created: ${s.createdAt}${s.expiresAt ? ` expires: ${s.expiresAt}` : ""}`
|
|
1873
1928
|
);
|
|
1874
1929
|
}
|
|
1930
|
+
var AUTH_LEAD_OPTS = [
|
|
1931
|
+
{ aliases: ["--api-key"], key: "apiKey", flag: "value" },
|
|
1932
|
+
{ aliases: ["--base-url"], key: "baseUrl", flag: "value" },
|
|
1933
|
+
{ aliases: ["--allow-untrusted-host"], key: "allowUntrustedHost", flag: "bool" },
|
|
1934
|
+
{ aliases: ["--org"], key: "org", flag: "value" },
|
|
1935
|
+
{ aliases: ["--json"], key: "json", flag: "bool" }
|
|
1936
|
+
];
|
|
1937
|
+
var EXEC_LEAD_OPTS = [
|
|
1938
|
+
...AUTH_LEAD_OPTS,
|
|
1939
|
+
{ aliases: ["--timeout-ms"], key: "timeoutMs", flag: "value" }
|
|
1940
|
+
];
|
|
1941
|
+
var SPAWN_LEAD_OPTS = [
|
|
1942
|
+
...AUTH_LEAD_OPTS,
|
|
1943
|
+
{ aliases: ["--cwd"], key: "cwd", flag: "value" },
|
|
1944
|
+
{ aliases: ["-e", "--env"], key: "env", flag: "repeat" },
|
|
1945
|
+
{ aliases: ["--stdin"], key: "stdin", flag: "bool" }
|
|
1946
|
+
];
|
|
1947
|
+
function takeLeadingOptions(argv, specs) {
|
|
1948
|
+
var _a;
|
|
1949
|
+
const byAlias = /* @__PURE__ */ new Map();
|
|
1950
|
+
for (const spec of specs) for (const alias of spec.aliases) byAlias.set(alias, spec);
|
|
1951
|
+
const inline = {};
|
|
1952
|
+
let i = 0;
|
|
1953
|
+
for (; i < argv.length; i++) {
|
|
1954
|
+
const token = argv[i];
|
|
1955
|
+
if (token === "--") {
|
|
1956
|
+
i++;
|
|
1957
|
+
break;
|
|
1958
|
+
}
|
|
1959
|
+
if (!token.startsWith("-") || token === "-") break;
|
|
1960
|
+
const eq = token.indexOf("=");
|
|
1961
|
+
const flag = eq === -1 ? token : token.slice(0, eq);
|
|
1962
|
+
let spec = byAlias.get(flag);
|
|
1963
|
+
let attached;
|
|
1964
|
+
if (!spec && !flag.startsWith("--") && flag.length > 2) {
|
|
1965
|
+
const shortSpec = byAlias.get(flag.slice(0, 2));
|
|
1966
|
+
if (shortSpec && shortSpec.flag !== "bool") {
|
|
1967
|
+
spec = shortSpec;
|
|
1968
|
+
attached = flag.slice(2);
|
|
1969
|
+
if (attached.startsWith("=")) attached = attached.slice(1);
|
|
1970
|
+
if (eq !== -1) attached += token.slice(eq);
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
if (!spec) {
|
|
1974
|
+
throw new Error(
|
|
1975
|
+
`unknown option '${flag}' \u2014 pass CLI options before the command, or use -- to separate them`
|
|
1976
|
+
);
|
|
1977
|
+
}
|
|
1978
|
+
if (spec.flag === "bool") {
|
|
1979
|
+
if (eq !== -1) throw new Error(`option '${flag}' takes no value`);
|
|
1980
|
+
inline[spec.key] = true;
|
|
1981
|
+
} else {
|
|
1982
|
+
const value = attached ?? (eq !== -1 ? token.slice(eq + 1) : argv[++i]);
|
|
1983
|
+
if (value === void 0) throw new Error(`option '${flag}' requires a value`);
|
|
1984
|
+
if (spec.flag === "repeat") {
|
|
1985
|
+
(inline[_a = spec.key] ?? (inline[_a] = [])).push(value);
|
|
1986
|
+
} else {
|
|
1987
|
+
inline[spec.key] = value;
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
return { command: argv.slice(i), inline };
|
|
1992
|
+
}
|
|
1993
|
+
function mergeLeadOpts(opts, inline) {
|
|
1994
|
+
const merged = { ...opts };
|
|
1995
|
+
for (const [key, value] of Object.entries(inline)) {
|
|
1996
|
+
if (Array.isArray(value)) {
|
|
1997
|
+
merged[key] = [...merged[key] ?? [], ...value];
|
|
1998
|
+
} else {
|
|
1999
|
+
merged[key] = value;
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
return merged;
|
|
2003
|
+
}
|
|
1875
2004
|
function registerSandboxesCommands(program2) {
|
|
1876
|
-
const cmd = program2.command("sandboxes").alias("sbx").description("Create and drive sandboxes through the platform").configureOutput({ outputError: usageErrorOutput });
|
|
1877
|
-
cmd.command("create").description('Place a sandbox (provider order walks 1,2,3; "market" bids first)').option("--order <providers>", 'provider order, comma-separated (e.g. "market,blaxel,vercel")').option("--label <label>", "label for the sandbox").option("--image <image>", "container image to boot").option("--snapshot-id <id>", "provider snapshot to resume").option("--cpus <n>", "CPU cores").option("--memory-mb <n>", "memory in MB").option("--disk-mb <n>", "ephemeral disk in MB").option("--timeout-ms <ms>", "sandbox timeout in ms").option("--secret <name>", "vault secret name to inject (repeatable)", (v, a) => a.concat(v), []).option("--api-key <key>", "platform API key (or COMPUTE_API_KEY)").option("--base-url <url>", "platform base URL").option("--allow-untrusted-host", "allow non-computesdk.com base URLs").option("--json", "print the raw response").action(async (opts) => {
|
|
2005
|
+
const cmd = program2.command("sandboxes").alias("sbx").description("Create and drive sandboxes through the platform").enablePositionalOptions().configureOutput({ outputError: usageErrorOutput });
|
|
2006
|
+
cmd.command("create").description('Place a sandbox (provider order walks 1,2,3; "market" bids first)').option("--order <providers>", 'provider order, comma-separated (e.g. "market,blaxel,vercel")').option("--size <size>", "platform size: small (1 vCPU/2 GB), medium, large, xlarge (8/16 GB); default medium").option("--label <label>", "label for the sandbox").option("--image <image>", "container image to boot").option("--snapshot-id <id>", "provider snapshot to resume").option("--cpus <n>", "CPU cores (raw resources \u2014 mutually exclusive with --size)").option("--memory-mb <n>", "memory in MB (raw resources)").option("--disk-mb <n>", "ephemeral disk in MB (raw resources)").option("--max-price <usd/unit>", "max price for a market fill (e.g. 0.12/hour); makes the create a limit order").option("--max-price-per <unit>", "unit for a bare --max-price usd (second, minute, or hour)").option("--market", 'place the create on the compute market (order type "market")').option("--order-type <type>", "explicit market order type: market or limit").option("--timeout-ms <ms>", "sandbox timeout in ms").option("--secret <name>", "vault secret name to inject (repeatable)", (v, a) => a.concat(v), []).option("--api-key <key>", "platform API key (or COMPUTE_API_KEY)").option("--base-url <url>", "platform base URL").option("--allow-untrusted-host", "allow non-computesdk.com base URLs").option("--json", "print the raw response").action(async (opts) => {
|
|
1878
2007
|
try {
|
|
1879
2008
|
const c = await client(opts);
|
|
1880
2009
|
const resources = {};
|
|
@@ -1883,18 +2012,55 @@ function registerSandboxesCommands(program2) {
|
|
|
1883
2012
|
if (opts.diskMb) resources.ephemeralDiskMb = Number(opts.diskMb);
|
|
1884
2013
|
const body = {};
|
|
1885
2014
|
if (opts.order) body.providerOrder = opts.order.split(",").map((s) => s.trim());
|
|
2015
|
+
if (opts.size) body.size = opts.size;
|
|
1886
2016
|
if (opts.label) body.label = opts.label;
|
|
1887
2017
|
if (opts.image) body.image = opts.image;
|
|
1888
2018
|
if (opts.snapshotId) body.snapshotId = opts.snapshotId;
|
|
1889
2019
|
if (opts.timeoutMs) body.timeoutMs = Number(opts.timeoutMs);
|
|
1890
2020
|
if (opts.secret && opts.secret.length > 0) body.secrets = opts.secret;
|
|
1891
2021
|
if (Object.keys(resources).length > 0) body.resources = resources;
|
|
2022
|
+
const maxPrice = parseMaxPrice(opts.maxPrice, opts.maxPricePer);
|
|
2023
|
+
if (maxPrice) body.maxPrice = { usd: maxPrice.usd, per: maxPrice.per };
|
|
2024
|
+
if (opts.orderType && opts.market) {
|
|
2025
|
+
throw new Error("--market and --order-type are mutually exclusive.");
|
|
2026
|
+
}
|
|
2027
|
+
if (opts.orderType) body.orderType = opts.orderType;
|
|
2028
|
+
if (opts.market) body.orderType = "market";
|
|
1892
2029
|
const res = await c.post("/api/v1/sandboxes", body);
|
|
1893
2030
|
output(opts, res.sandbox, printSandbox);
|
|
1894
2031
|
} catch (e) {
|
|
1895
2032
|
fail(e, opts);
|
|
1896
2033
|
}
|
|
1897
2034
|
});
|
|
2035
|
+
cmd.command("quote").description("Quote a sandbox create: placement, rate, caps and credits \u2014 creates nothing").option("--size <size>", "platform size (or raw resource flags; default medium)").option("--cpus <n>", "CPU cores").option("--memory-mb <n>", "memory in MB").option("--disk-mb <n>", "ephemeral disk in MB").option("--region <region>", "pin the placement region").option("--timeout-ms <ms>", "sandbox timeout in ms").option("--order-type <type>", "market order type: market or limit").option("--market", "quote a market order (fills at the live price, protection-bounded)").option("--max-price <usd/unit>", "max price for a market fill (e.g. 0.12/hour)").option("--max-price-per <unit>", "unit for a bare --max-price usd (second, minute, or hour)").option("--api-key <key>").option("--base-url <url>").option("--allow-untrusted-host").option("--json", "print the raw response").action(async (opts) => {
|
|
2036
|
+
try {
|
|
2037
|
+
const c = await client(opts);
|
|
2038
|
+
const params = {
|
|
2039
|
+
size: opts.size,
|
|
2040
|
+
cpus: opts.cpus,
|
|
2041
|
+
memoryMb: opts.memoryMb,
|
|
2042
|
+
ephemeralDiskMb: opts.diskMb,
|
|
2043
|
+
region: opts.region,
|
|
2044
|
+
timeoutMs: opts.timeoutMs,
|
|
2045
|
+
orderType: opts.market ? "market" : opts.orderType
|
|
2046
|
+
};
|
|
2047
|
+
if (opts.orderType && opts.market) {
|
|
2048
|
+
throw new Error("--market and --order-type are mutually exclusive.");
|
|
2049
|
+
}
|
|
2050
|
+
const maxPrice = parseMaxPrice(opts.maxPrice, opts.maxPricePer);
|
|
2051
|
+
if (maxPrice) {
|
|
2052
|
+
params.maxPriceUsd = String(maxPrice.usd);
|
|
2053
|
+
params.maxPricePer = maxPrice.per;
|
|
2054
|
+
}
|
|
2055
|
+
const res = await c.get(
|
|
2056
|
+
"/api/v1/sandboxes/quote",
|
|
2057
|
+
params
|
|
2058
|
+
);
|
|
2059
|
+
output(opts, res.quote, (quote) => printQuote(quote, opts.timeoutMs));
|
|
2060
|
+
} catch (e) {
|
|
2061
|
+
fail(e, opts);
|
|
2062
|
+
}
|
|
2063
|
+
});
|
|
1898
2064
|
cmd.command("list").description("List sandboxes").option("--status <status>", "creating | running | destroyed").option("--limit <n>", "page size").option("--cursor <cursor>", "page cursor from a previous response").option("--api-key <key>").option("--base-url <url>").option("--allow-untrusted-host").option("--json", "print the raw response").action(async (opts) => {
|
|
1899
2065
|
try {
|
|
1900
2066
|
const c = await client(opts);
|
|
@@ -1928,8 +2094,13 @@ function registerSandboxesCommands(program2) {
|
|
|
1928
2094
|
fail(e, opts);
|
|
1929
2095
|
}
|
|
1930
2096
|
});
|
|
1931
|
-
cmd.command("exec <sandboxId> <command...>").description("Run a one-shot command and print its result").option("--timeout-ms <ms>", "command timeout in ms").option("--api-key <key>").option("--base-url <url>").option("--allow-untrusted-host").option("--json", "print the raw response").action(async (sandboxId,
|
|
2097
|
+
cmd.command("exec <sandboxId> <command...>").description("Run a one-shot command and print its result (options before the command; -- also works)").option("--timeout-ms <ms>", "command timeout in ms").option("--api-key <key>").option("--base-url <url>").option("--allow-untrusted-host").option("--json", "print the raw response").passThroughOptions().action(async (sandboxId, rawCommand, rawOpts) => {
|
|
2098
|
+
let opts = rawOpts;
|
|
1932
2099
|
try {
|
|
2100
|
+
const lead = takeLeadingOptions(rawCommand, EXEC_LEAD_OPTS);
|
|
2101
|
+
opts = mergeLeadOpts(rawOpts, lead.inline);
|
|
2102
|
+
const command = lead.command;
|
|
2103
|
+
if (command.length === 0) throw new Error("missing command to run");
|
|
1933
2104
|
const c = await client(opts);
|
|
1934
2105
|
const res = await c.post(
|
|
1935
2106
|
`/api/v1/sandboxes/${sandboxId}/commands`,
|
|
@@ -1948,8 +2119,13 @@ function registerSandboxesCommands(program2) {
|
|
|
1948
2119
|
fail(e, opts);
|
|
1949
2120
|
}
|
|
1950
2121
|
});
|
|
1951
|
-
cmd.command("spawn <sandboxId> <command...>").description("Start a detached process that outlives this request").option("--cwd <dir>", "working directory").option("-e, --env <key=value>", "environment variable (repeatable)", (v, a) => a.concat(v), []).option("--stdin", "keep the process's stdin pipe open for `stdin`/`close-stdin`").option("--api-key <key>").option("--base-url <url>").option("--allow-untrusted-host").option("--json", "print the raw response").action(async (sandboxId,
|
|
2122
|
+
cmd.command("spawn <sandboxId> <command...>").description("Start a detached process that outlives this request (options before the command; -- also works)").option("--cwd <dir>", "working directory").option("-e, --env <key=value>", "environment variable (repeatable)", (v, a) => a.concat(v), []).option("--stdin", "keep the process's stdin pipe open for `stdin`/`close-stdin`").option("--api-key <key>").option("--base-url <url>").option("--allow-untrusted-host").option("--json", "print the raw response").passThroughOptions().action(async (sandboxId, rawCommand, rawOpts) => {
|
|
2123
|
+
let opts = rawOpts;
|
|
1952
2124
|
try {
|
|
2125
|
+
const lead = takeLeadingOptions(rawCommand, SPAWN_LEAD_OPTS);
|
|
2126
|
+
opts = mergeLeadOpts(rawOpts, lead.inline);
|
|
2127
|
+
const command = lead.command;
|
|
2128
|
+
if (command.length === 0) throw new Error("missing command to spawn");
|
|
1953
2129
|
const c = await client(opts);
|
|
1954
2130
|
const res = await c.post(
|
|
1955
2131
|
`/api/v1/sandboxes/${sandboxId}/processes`,
|