@computesdk/cli 2.1.1 → 2.3.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/dist/index.js +153 -23
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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";
|
|
@@ -1373,25 +1373,55 @@ function registerActionsCommands(program2) {
|
|
|
1373
1373
|
import pc2 from "picocolors";
|
|
1374
1374
|
var USD_RE = /^\d+(\.\d+)?([eE][+-]?\d+)?$/;
|
|
1375
1375
|
var RATE_UNITS = ["second", "minute", "hour"];
|
|
1376
|
+
var MARKET_LANES = ["actions", "sandbox"];
|
|
1377
|
+
function parseMarketLane(value) {
|
|
1378
|
+
if (value === void 0) return "actions";
|
|
1379
|
+
if (!MARKET_LANES.includes(value)) {
|
|
1380
|
+
throw new ActionsCliError(
|
|
1381
|
+
"invalid_argument",
|
|
1382
|
+
`--use-case must be ${MARKET_LANES.join(" or ")}, got "${value}".`
|
|
1383
|
+
);
|
|
1384
|
+
}
|
|
1385
|
+
return value;
|
|
1386
|
+
}
|
|
1376
1387
|
function parseRate(price, per) {
|
|
1377
1388
|
if (price === void 0) {
|
|
1378
|
-
throw new ActionsCliError("invalid_argument", "A price is required \u2014 pass --price <usd>.");
|
|
1389
|
+
throw new ActionsCliError("invalid_argument", "A price is required \u2014 pass --price <usd>/<unit>.");
|
|
1390
|
+
}
|
|
1391
|
+
let usdText = price;
|
|
1392
|
+
let unit = per;
|
|
1393
|
+
const slash = price.indexOf("/");
|
|
1394
|
+
if (slash !== -1) {
|
|
1395
|
+
usdText = price.slice(0, slash);
|
|
1396
|
+
const inline = price.slice(slash + 1);
|
|
1397
|
+
if (per !== void 0 && per !== inline) {
|
|
1398
|
+
throw new ActionsCliError(
|
|
1399
|
+
"invalid_argument",
|
|
1400
|
+
`--price "${price}" conflicts with --per "${per}".`
|
|
1401
|
+
);
|
|
1402
|
+
}
|
|
1403
|
+
unit = inline;
|
|
1404
|
+
}
|
|
1405
|
+
const usd2 = Number(usdText);
|
|
1406
|
+
if (!USD_RE.test(usdText) || !Number.isFinite(usd2) || usd2 <= 0) {
|
|
1407
|
+
throw new ActionsCliError(
|
|
1408
|
+
"invalid_argument",
|
|
1409
|
+
`Invalid --price "${price}". Expected a positive dollar amount (e.g. 0.12/hour).`
|
|
1410
|
+
);
|
|
1379
1411
|
}
|
|
1380
|
-
|
|
1381
|
-
if (!USD_RE.test(price) || !Number.isFinite(usd) || usd <= 0) {
|
|
1412
|
+
if (unit === void 0) {
|
|
1382
1413
|
throw new ActionsCliError(
|
|
1383
1414
|
"invalid_argument",
|
|
1384
|
-
|
|
1415
|
+
"--price needs a unit \u2014 write it as <usd>/<unit> (e.g. --price 0.12/hour) or pass --per hour."
|
|
1385
1416
|
);
|
|
1386
1417
|
}
|
|
1387
|
-
const unit = per ?? "second";
|
|
1388
1418
|
if (!RATE_UNITS.includes(unit)) {
|
|
1389
1419
|
throw new ActionsCliError(
|
|
1390
1420
|
"invalid_argument",
|
|
1391
|
-
|
|
1421
|
+
`The unit must be second, minute, or hour, got "${unit}".`
|
|
1392
1422
|
);
|
|
1393
1423
|
}
|
|
1394
|
-
return { usd, per: unit };
|
|
1424
|
+
return { usd: usd2, per: unit };
|
|
1395
1425
|
}
|
|
1396
1426
|
function parseCapacity(value) {
|
|
1397
1427
|
if (value === void 0) return void 0;
|
|
@@ -1427,6 +1457,7 @@ function sellBody(opts) {
|
|
|
1427
1457
|
}
|
|
1428
1458
|
return {
|
|
1429
1459
|
size: opts.size,
|
|
1460
|
+
useCase: parseMarketLane(opts.useCase),
|
|
1430
1461
|
...opts.region !== void 0 && { region: opts.region },
|
|
1431
1462
|
usd: rate.usd,
|
|
1432
1463
|
per: rate.per,
|
|
@@ -1493,11 +1524,11 @@ function credentialBody(fields, values) {
|
|
|
1493
1524
|
}
|
|
1494
1525
|
return { fields: values };
|
|
1495
1526
|
}
|
|
1496
|
-
function formatUsd(
|
|
1497
|
-
return `$${
|
|
1527
|
+
function formatUsd(usd2) {
|
|
1528
|
+
return `$${usd2.toFixed(6).replace(/\.?0+$/, "")}`;
|
|
1498
1529
|
}
|
|
1499
|
-
function formatRate(
|
|
1500
|
-
return `${formatUsd(
|
|
1530
|
+
function formatRate(usd2, per) {
|
|
1531
|
+
return `${formatUsd(usd2)}/${per}`;
|
|
1501
1532
|
}
|
|
1502
1533
|
function formatListingStatus(ask) {
|
|
1503
1534
|
let label;
|
|
@@ -1515,6 +1546,7 @@ function formatListingRow(ask) {
|
|
|
1515
1546
|
return [
|
|
1516
1547
|
ask.id,
|
|
1517
1548
|
formatListingStatus(ask),
|
|
1549
|
+
pc2.dim(ask.useCase === "sandbox" ? "sandbox" : "actions"),
|
|
1518
1550
|
safeTerm(ask.size),
|
|
1519
1551
|
safeTerm(ask.region ?? "-"),
|
|
1520
1552
|
formatRate(ask.usd, ask.per),
|
|
@@ -1530,6 +1562,9 @@ function formatProviderStatus(p2) {
|
|
|
1530
1562
|
`credential: ${p2.executorCredentialConnected ? pc2.green("connected") : pc2.yellow("not connected \u2014 your listings cannot fill until `compute market credential connect`")}`
|
|
1531
1563
|
);
|
|
1532
1564
|
if (p2.revokedAt) lines.push(pc2.red(`revoked: ${p2.revokedAt}`));
|
|
1565
|
+
lines.push(
|
|
1566
|
+
`lanes: ${(p2.useCases ?? ["actions"]).join(", ")}`
|
|
1567
|
+
);
|
|
1533
1568
|
lines.push(
|
|
1534
1569
|
`sizes: ${p2.sizes.map((s) => `${s.name} (${s.label})`).join(", ") || "-"}`
|
|
1535
1570
|
);
|
|
@@ -1544,13 +1579,14 @@ function formatProviderStatus(p2) {
|
|
|
1544
1579
|
}
|
|
1545
1580
|
function formatBook(book) {
|
|
1546
1581
|
const lines = [];
|
|
1582
|
+
const lane = (useCase) => pc2.dim(useCase === "sandbox" ? "sandbox" : "actions");
|
|
1547
1583
|
lines.push(pc2.bold("sellers' asking prices"));
|
|
1548
1584
|
if (book.asks.length === 0) lines.push(pc2.dim(" no listings are live"));
|
|
1549
1585
|
for (const ask of book.asks) {
|
|
1550
1586
|
const where = ask.region ? safeTerm(ask.region) : "any region";
|
|
1551
1587
|
const expiry = ask.expiresAt ? pc2.dim(ask.rollover ? ` renews ${ask.expiresAt}` : ` until ${ask.expiresAt}`) : "";
|
|
1552
1588
|
lines.push(
|
|
1553
|
-
` ${formatRate(ask.usd, ask.per)} ${safeTerm(ask.providerName)} ${safeTerm(ask.size)} ${where} up to ${ask.maxConcurrent} at once${expiry}`
|
|
1589
|
+
` ${lane(ask.useCase)} ${formatRate(ask.usd, ask.per)} ${safeTerm(ask.providerName)} ${safeTerm(ask.size)} ${where} up to ${ask.maxConcurrent} at once${expiry}`
|
|
1554
1590
|
);
|
|
1555
1591
|
}
|
|
1556
1592
|
lines.push("");
|
|
@@ -1559,7 +1595,7 @@ function formatBook(book) {
|
|
|
1559
1595
|
for (const bid of book.bids) {
|
|
1560
1596
|
const where = bid.region ? safeTerm(bid.region) : "anywhere";
|
|
1561
1597
|
lines.push(
|
|
1562
|
-
` pays up to ${formatRate(bid.maxUsd, bid.per)} ${safeTerm(bid.size)} ${where} ${pc2.dim(`posted ${bid.createdAt}`)}`
|
|
1598
|
+
` ${lane(bid.useCase)} pays up to ${formatRate(bid.maxUsd, bid.per)} ${safeTerm(bid.size)} ${where} ${pc2.dim(`posted ${bid.createdAt}`)}`
|
|
1563
1599
|
);
|
|
1564
1600
|
}
|
|
1565
1601
|
lines.push("");
|
|
@@ -1568,7 +1604,7 @@ function formatBook(book) {
|
|
|
1568
1604
|
for (const fill of book.fills) {
|
|
1569
1605
|
const statusNote = fill.status === "replaced" ? pc2.yellow(" replaced") : fill.status === "closed" ? pc2.gray(" closed") : "";
|
|
1570
1606
|
lines.push(
|
|
1571
|
-
` ${pc2.dim(fill.id)} ${formatRate(fill.usd, fill.per)} ${safeTerm(fill.provider)} ${safeTerm(fill.size)} ${safeTerm(fill.region ?? "-")} ${pc2.dim(fill.createdAt)}${statusNote}`
|
|
1607
|
+
` ${pc2.dim(fill.id)} ${lane(fill.useCase)} ${formatRate(fill.usd, fill.per)} ${safeTerm(fill.provider)} ${safeTerm(fill.size)} ${safeTerm(fill.region ?? "-")} ${pc2.dim(fill.createdAt)}${statusNote}`
|
|
1572
1608
|
);
|
|
1573
1609
|
}
|
|
1574
1610
|
return lines.join("\n");
|
|
@@ -1629,10 +1665,11 @@ function registerMarketCommands(program2) {
|
|
|
1629
1665
|
}
|
|
1630
1666
|
});
|
|
1631
1667
|
common(
|
|
1632
|
-
market.command("sell").description("Post a listing: sell capacity at a price").requiredOption("--price <usd>", "price per unit of time (e.g. 0.12)").option("--per <unit>", "
|
|
1668
|
+
market.command("sell").description("Post a listing: sell capacity at a price").requiredOption("--price <usd/unit>", "price per unit of time (e.g. 0.12/hour)").option("--per <unit>", "unit for a bare --price usd (second, minute, or hour)").option("--size <tier>", "size tier to sell (default: medium, else the provider's first tier)").option("--use-case <lane>", "lane to sell into: actions or sandbox (default: actions)").option("--region <region>", "region to sell in (default: anywhere the provider runs)").option("--capacity <n>", "max simultaneous fills (default: 1)").option("--expires-in <hours>", "delist after this many hours (default: standing)").option("--renew", "re-list for the same window each time it expires (requires --expires-in)")
|
|
1633
1669
|
).action(async (opts) => {
|
|
1634
1670
|
try {
|
|
1635
1671
|
const c = await client(opts);
|
|
1672
|
+
const useCase = parseMarketLane(opts.useCase);
|
|
1636
1673
|
let size = opts.size;
|
|
1637
1674
|
if (size === void 0) {
|
|
1638
1675
|
const { provider } = await c.get(
|
|
@@ -1650,7 +1687,7 @@ function registerMarketCommands(program2) {
|
|
|
1650
1687
|
}
|
|
1651
1688
|
const result = await c.post(
|
|
1652
1689
|
"/api/v1/market/asks",
|
|
1653
|
-
sellBody({ ...opts, size })
|
|
1690
|
+
sellBody({ ...opts, size, useCase })
|
|
1654
1691
|
);
|
|
1655
1692
|
output(opts, result, (r) => {
|
|
1656
1693
|
console.log(`listed ${pc2.cyan(r.ask.id)}`);
|
|
@@ -1661,7 +1698,7 @@ function registerMarketCommands(program2) {
|
|
|
1661
1698
|
}
|
|
1662
1699
|
});
|
|
1663
1700
|
common(
|
|
1664
|
-
market.command("price").description("Reprice a listing").argument("<listing-id>", "listing ID").requiredOption("--price <usd>", "new price per unit of time (e.g. 0.08)").option("--per <unit>", "
|
|
1701
|
+
market.command("price").description("Reprice a listing").argument("<listing-id>", "listing ID").requiredOption("--price <usd/unit>", "new price per unit of time (e.g. 0.08/hour)").option("--per <unit>", "unit for a bare --price usd (second, minute, or hour)")
|
|
1665
1702
|
).action(async (listingId, opts) => {
|
|
1666
1703
|
try {
|
|
1667
1704
|
const result = await (await client(opts)).post(
|
|
@@ -1742,11 +1779,12 @@ function registerMarketCommands(program2) {
|
|
|
1742
1779
|
}
|
|
1743
1780
|
);
|
|
1744
1781
|
common(
|
|
1745
|
-
market.command("book").description("Live prices: sellers' asking prices, buyer offers, recent sales")
|
|
1782
|
+
market.command("book").description("Live prices: sellers' asking prices, buyer offers, recent sales").option("--use-case <lane>", "only this lane: actions or sandbox (default: both)")
|
|
1746
1783
|
).action(async (opts) => {
|
|
1747
1784
|
try {
|
|
1785
|
+
const lane = opts.useCase === void 0 ? void 0 : parseMarketLane(opts.useCase);
|
|
1748
1786
|
const book = await (await client(opts)).get(
|
|
1749
|
-
|
|
1787
|
+
`/api/v1/market/book${lane ? `?useCase=${lane}` : ""}`
|
|
1750
1788
|
);
|
|
1751
1789
|
output(opts, book, (b) => console.log(formatBook(b)));
|
|
1752
1790
|
} catch (e) {
|
|
@@ -1843,6 +1881,33 @@ ${hints}`
|
|
|
1843
1881
|
|
|
1844
1882
|
// src/sandboxes.ts
|
|
1845
1883
|
import pc3 from "picocolors";
|
|
1884
|
+
function parseMaxPrice(value, per) {
|
|
1885
|
+
if (value === void 0) {
|
|
1886
|
+
if (per !== void 0) throw new Error("--max-price-per requires --max-price.");
|
|
1887
|
+
return void 0;
|
|
1888
|
+
}
|
|
1889
|
+
let usdText = value;
|
|
1890
|
+
let unit = per;
|
|
1891
|
+
const slash = value.indexOf("/");
|
|
1892
|
+
if (slash !== -1) {
|
|
1893
|
+
usdText = value.slice(0, slash);
|
|
1894
|
+
const inline = value.slice(slash + 1);
|
|
1895
|
+
if (per !== void 0 && per !== inline) {
|
|
1896
|
+
throw new Error(`--max-price "${value}" conflicts with --max-price-per "${per}".`);
|
|
1897
|
+
}
|
|
1898
|
+
unit = inline;
|
|
1899
|
+
}
|
|
1900
|
+
const usd2 = Number(usdText);
|
|
1901
|
+
if (!/^\d+(\.\d+)?([eE][+-]?\d+)?$/.test(usdText) || !Number.isFinite(usd2) || usd2 <= 0) {
|
|
1902
|
+
throw new Error(`Invalid --max-price "${value}". Expected a positive dollar amount like 0.12/hour.`);
|
|
1903
|
+
}
|
|
1904
|
+
if (unit !== "second" && unit !== "minute" && unit !== "hour") {
|
|
1905
|
+
throw new Error(
|
|
1906
|
+
"--max-price needs a unit \u2014 write it as <usd>/<unit> (e.g. --max-price 0.12/hour) or pass --max-price-per hour."
|
|
1907
|
+
);
|
|
1908
|
+
}
|
|
1909
|
+
return { usd: usd2, per: unit };
|
|
1910
|
+
}
|
|
1846
1911
|
function shellQuote(arg) {
|
|
1847
1912
|
return `'${arg.replace(/'/g, `'\\''`)}'`;
|
|
1848
1913
|
}
|
|
@@ -1854,12 +1919,40 @@ function printSandbox(s) {
|
|
|
1854
1919
|
console.log(` image: ${s.image ?? "\u2014"}${s.requestedImage !== null && s.requestedImage !== s.image ? ` ${pc3.dim(`(requested: ${s.requestedImage})`)}` : ""}`);
|
|
1855
1920
|
}
|
|
1856
1921
|
if (s.destroyError) console.log(` destroyError: ${pc3.red(s.destroyError)}`);
|
|
1922
|
+
if (s.placement) {
|
|
1923
|
+
const p2 = s.placement;
|
|
1924
|
+
const box = p2.box ? ` / ${p2.box.sizeName ?? "custom"}${p2.box.resources ? ` (${p2.box.resources.cpus ?? "?"} vCPU / ${p2.box.resources.memoryMb ?? "?"} MB)` : ""}` : "";
|
|
1925
|
+
console.log(
|
|
1926
|
+
` provider: ${p2.box?.provider ?? s.provider ?? "\u2014"}${box} size: ${p2.size ?? "\u2014"} order: ${p2.orderType ?? "\u2014"} rate: $${p2.rate.usd}/${p2.rate.per}`
|
|
1927
|
+
);
|
|
1928
|
+
}
|
|
1857
1929
|
if (attach !== void 0) {
|
|
1858
1930
|
console.log(
|
|
1859
1931
|
attach === null ? " attach: none (market fill or ambient provider \u2014 platform drive only)" : ` attach: ${attach.provider} / ${attach.providerSandboxId}${attach.region ? ` (${attach.region})` : ""}`
|
|
1860
1932
|
);
|
|
1861
1933
|
}
|
|
1862
1934
|
}
|
|
1935
|
+
var usd = (n, suffix = "") => n === void 0 ? "\u2014" : `$${n.toFixed(4).replace(/0+$/, "").replace(/\.$/, ".00")}${suffix}`;
|
|
1936
|
+
function printQuote(q, timeoutMs) {
|
|
1937
|
+
console.log(`quote: ${q.ok ? pc3.green("ok") : pc3.red(q.reason ?? "unfillable")}`);
|
|
1938
|
+
const box = q.placement?.box;
|
|
1939
|
+
console.log(
|
|
1940
|
+
` 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` : ""})` : "")
|
|
1941
|
+
);
|
|
1942
|
+
console.log(` order type: ${q.orderType} order: ${q.providerOrder.join(", ")}`);
|
|
1943
|
+
if (q.rateUsd) {
|
|
1944
|
+
console.log(` rate: ${usd(q.rateUsd.perHour, "/hour")} cheapest live: ${usd(q.cheapestLiveUsdPerHour, "/hr")} reference: ${usd(q.referenceUsdPerHour, "/hr")}`);
|
|
1945
|
+
} else if (q.rate) {
|
|
1946
|
+
console.log(` rate: $${q.rate.usd}/${q.rate.per}`);
|
|
1947
|
+
}
|
|
1948
|
+
const timeout = timeoutMs !== void 0 ? ` for ${timeoutMs}ms` : "";
|
|
1949
|
+
console.log(` est. cost${timeout}: ${usd(q.estimatedCostUsd)} required hold: ${usd(q.requiredHoldUsd)}`);
|
|
1950
|
+
console.log(
|
|
1951
|
+
` cap: ${q.maxPrice ? `$${q.maxPrice.usd}/${q.maxPrice.per}` : usd(q.marketCapUsdPerHour, "/hr")} protection limit: ${usd(q.protectionLimitUsdPerHour, "/hr")} balance: ${usd(q.creditBalanceUsd)}`
|
|
1952
|
+
);
|
|
1953
|
+
if (!q.ok && q.topUpPath) console.log(` ${pc3.dim(`\u2192 ${q.topUpPath}`)}`);
|
|
1954
|
+
if (q.liveAskDepth !== void 0) console.log(` ${pc3.dim(`live asks: ${q.liveAskDepth}`)}`);
|
|
1955
|
+
}
|
|
1863
1956
|
function printProcess(p2) {
|
|
1864
1957
|
const exit = p2.status === "exited" ? `exit=${p2.exitCode ?? "?"}${p2.signal ? ` (${p2.signal})` : ""}` : "";
|
|
1865
1958
|
const stdin = p2.stdin && p2.status === "running" ? " [stdin open]" : "";
|
|
@@ -1948,7 +2041,7 @@ function mergeLeadOpts(opts, inline) {
|
|
|
1948
2041
|
}
|
|
1949
2042
|
function registerSandboxesCommands(program2) {
|
|
1950
2043
|
const cmd = program2.command("sandboxes").alias("sbx").description("Create and drive sandboxes through the platform").enablePositionalOptions().configureOutput({ outputError: usageErrorOutput });
|
|
1951
|
-
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) => {
|
|
2044
|
+
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) => {
|
|
1952
2045
|
try {
|
|
1953
2046
|
const c = await client(opts);
|
|
1954
2047
|
const resources = {};
|
|
@@ -1957,18 +2050,55 @@ function registerSandboxesCommands(program2) {
|
|
|
1957
2050
|
if (opts.diskMb) resources.ephemeralDiskMb = Number(opts.diskMb);
|
|
1958
2051
|
const body = {};
|
|
1959
2052
|
if (opts.order) body.providerOrder = opts.order.split(",").map((s) => s.trim());
|
|
2053
|
+
if (opts.size) body.size = opts.size;
|
|
1960
2054
|
if (opts.label) body.label = opts.label;
|
|
1961
2055
|
if (opts.image) body.image = opts.image;
|
|
1962
2056
|
if (opts.snapshotId) body.snapshotId = opts.snapshotId;
|
|
1963
2057
|
if (opts.timeoutMs) body.timeoutMs = Number(opts.timeoutMs);
|
|
1964
2058
|
if (opts.secret && opts.secret.length > 0) body.secrets = opts.secret;
|
|
1965
2059
|
if (Object.keys(resources).length > 0) body.resources = resources;
|
|
2060
|
+
const maxPrice = parseMaxPrice(opts.maxPrice, opts.maxPricePer);
|
|
2061
|
+
if (maxPrice) body.maxPrice = { usd: maxPrice.usd, per: maxPrice.per };
|
|
2062
|
+
if (opts.orderType && opts.market) {
|
|
2063
|
+
throw new Error("--market and --order-type are mutually exclusive.");
|
|
2064
|
+
}
|
|
2065
|
+
if (opts.orderType) body.orderType = opts.orderType;
|
|
2066
|
+
if (opts.market) body.orderType = "market";
|
|
1966
2067
|
const res = await c.post("/api/v1/sandboxes", body);
|
|
1967
2068
|
output(opts, res.sandbox, printSandbox);
|
|
1968
2069
|
} catch (e) {
|
|
1969
2070
|
fail(e, opts);
|
|
1970
2071
|
}
|
|
1971
2072
|
});
|
|
2073
|
+
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) => {
|
|
2074
|
+
try {
|
|
2075
|
+
const c = await client(opts);
|
|
2076
|
+
const params = {
|
|
2077
|
+
size: opts.size,
|
|
2078
|
+
cpus: opts.cpus,
|
|
2079
|
+
memoryMb: opts.memoryMb,
|
|
2080
|
+
ephemeralDiskMb: opts.diskMb,
|
|
2081
|
+
region: opts.region,
|
|
2082
|
+
timeoutMs: opts.timeoutMs,
|
|
2083
|
+
orderType: opts.market ? "market" : opts.orderType
|
|
2084
|
+
};
|
|
2085
|
+
if (opts.orderType && opts.market) {
|
|
2086
|
+
throw new Error("--market and --order-type are mutually exclusive.");
|
|
2087
|
+
}
|
|
2088
|
+
const maxPrice = parseMaxPrice(opts.maxPrice, opts.maxPricePer);
|
|
2089
|
+
if (maxPrice) {
|
|
2090
|
+
params.maxPriceUsd = String(maxPrice.usd);
|
|
2091
|
+
params.maxPricePer = maxPrice.per;
|
|
2092
|
+
}
|
|
2093
|
+
const res = await c.get(
|
|
2094
|
+
"/api/v1/sandboxes/quote",
|
|
2095
|
+
params
|
|
2096
|
+
);
|
|
2097
|
+
output(opts, res.quote, (quote) => printQuote(quote, opts.timeoutMs));
|
|
2098
|
+
} catch (e) {
|
|
2099
|
+
fail(e, opts);
|
|
2100
|
+
}
|
|
2101
|
+
});
|
|
1972
2102
|
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) => {
|
|
1973
2103
|
try {
|
|
1974
2104
|
const c = await client(opts);
|