@computesdk/cli 2.2.0 → 2.3.1
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 +74 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1373,22 +1373,52 @@ 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>.");
|
|
1379
1390
|
}
|
|
1380
|
-
|
|
1381
|
-
|
|
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) {
|
|
1382
1407
|
throw new ActionsCliError(
|
|
1383
1408
|
"invalid_argument",
|
|
1384
|
-
`Invalid --price "${price}". Expected a positive dollar amount (e.g. 0.12).`
|
|
1409
|
+
`Invalid --price "${price}". Expected a positive dollar amount (e.g. 0.12/hour).`
|
|
1410
|
+
);
|
|
1411
|
+
}
|
|
1412
|
+
if (unit === void 0) {
|
|
1413
|
+
throw new ActionsCliError(
|
|
1414
|
+
"invalid_argument",
|
|
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
1424
|
return { usd: usd2, per: unit };
|
|
@@ -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,
|
|
@@ -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) {
|
|
@@ -2411,6 +2449,14 @@ var packageJson = JSON.parse(
|
|
|
2411
2449
|
);
|
|
2412
2450
|
var isDevBuild = import.meta.url.includes("worktrees") || import.meta.url.includes("/packages/cli/");
|
|
2413
2451
|
var VERSION = isDevBuild ? `${packageJson.version}-dev` : packageJson.version;
|
|
2452
|
+
process.stdout.on("error", (err) => {
|
|
2453
|
+
if (err.code === "EPIPE") process.exit(0);
|
|
2454
|
+
throw err;
|
|
2455
|
+
});
|
|
2456
|
+
process.stderr.on("error", (err) => {
|
|
2457
|
+
if (err.code === "EPIPE") return;
|
|
2458
|
+
throw err;
|
|
2459
|
+
});
|
|
2414
2460
|
var program = new Command();
|
|
2415
2461
|
program.name("compute").description("ComputeSDK CLI").version(VERSION).enablePositionalOptions().passThroughOptions();
|
|
2416
2462
|
function envBaseUrl() {
|
|
@@ -2490,16 +2536,24 @@ program.command("login").description("Authenticate with ComputeSDK (OAuth device
|
|
|
2490
2536
|
await printSessionLine({ baseUrl: opts.baseUrl });
|
|
2491
2537
|
p.outro(pc4.green("Authenticated!"));
|
|
2492
2538
|
});
|
|
2493
|
-
program.command("logout").description("Clear stored credentials").action(async () => {
|
|
2539
|
+
program.command("logout").description("Clear stored credentials").option("--json", "print machine-readable JSON").action(async (opts) => {
|
|
2540
|
+
await runLogout();
|
|
2541
|
+
if (opts.json) {
|
|
2542
|
+
console.log(JSON.stringify({ loggedOut: true }, null, 2));
|
|
2543
|
+
return;
|
|
2544
|
+
}
|
|
2494
2545
|
console.log();
|
|
2495
2546
|
p.intro(pc4.cyan(`@computesdk/cli v${VERSION}`));
|
|
2496
|
-
await runLogout();
|
|
2497
2547
|
p.log.success("Logged out. Stored credentials removed.");
|
|
2498
2548
|
p.outro(pc4.green("Done!"));
|
|
2499
2549
|
});
|
|
2500
|
-
async function printWhoami() {
|
|
2550
|
+
async function printWhoami(options = {}) {
|
|
2501
2551
|
const { getMe } = await import("@benchsdk/cli");
|
|
2502
|
-
const me = await getMe(await benchAuth());
|
|
2552
|
+
const me = await getMe(await benchAuth({ baseUrl: options.baseUrl }));
|
|
2553
|
+
if (options.json) {
|
|
2554
|
+
console.log(JSON.stringify(me, null, 2));
|
|
2555
|
+
return;
|
|
2556
|
+
}
|
|
2503
2557
|
const active = me.organizations.find((o) => o.id === me.activeOrganizationId);
|
|
2504
2558
|
console.log(me.user.email ?? me.user.name ?? me.user.id);
|
|
2505
2559
|
console.log(
|
|
@@ -2546,8 +2600,8 @@ org.command("use <slug>").description("Set the active organization (persisted to
|
|
|
2546
2600
|
});
|
|
2547
2601
|
console.log(`Active organization set to ${result.organization.slug} (${result.organization.id})`);
|
|
2548
2602
|
});
|
|
2549
|
-
org.command("current").description("Show the current user and active organization").action(printWhoami);
|
|
2550
|
-
program.command("whoami").description("Show the current user and active organization").action(printWhoami);
|
|
2603
|
+
org.command("current").description("Show the current user and active organization").option("--base-url <url>", "platform URL to query").option("--json", "print machine-readable JSON").action((opts) => printWhoami(opts));
|
|
2604
|
+
program.command("whoami").description("Show the current user and active organization").option("--base-url <url>", "platform URL to query").option("--json", "print machine-readable JSON").action((opts) => printWhoami(opts));
|
|
2551
2605
|
registerActionsCommands(program);
|
|
2552
2606
|
registerMarketCommands(program);
|
|
2553
2607
|
registerSandboxesCommands(program);
|