From 5356758c1d918b74fc114b4c3be9681299d8874d Mon Sep 17 00:00:00 2001 From: Daniel Tao Date: Fri, 31 Oct 2025 20:13:18 -0700 Subject: [PATCH 1/2] fix: deprecate `sf extend` --- src/lib/extend/index.tsx | 104 +++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 60 deletions(-) diff --git a/src/lib/extend/index.tsx b/src/lib/extend/index.tsx index 7f5347b..ee46711 100644 --- a/src/lib/extend/index.tsx +++ b/src/lib/extend/index.tsx @@ -1,19 +1,10 @@ import { type Command } from "@commander-js/extra-typings"; -import { render } from "ink"; import dayjs from "npm:dayjs@1.11.13"; import duration from "npm:dayjs@1.11.13/plugin/duration.js"; import relativeTime from "npm:dayjs@1.11.13/plugin/relativeTime.js"; -import { parseDuration, SfBuyOptions } from "../buy/index.tsx"; -import React from "react"; -import { getContract } from "../../helpers/fetchers.ts"; -import { logAndQuit } from "../../helpers/errors.ts"; -import { QuoteAndBuy, QuoteComponent } from "../buy/index.tsx"; -import { ActiveContract } from "../contracts/types.ts"; -import { GPUS_PER_NODE } from "../constants.ts"; -import { - getContractAcceleratorQuantity, - getContractRange, -} from "../contracts/utils.ts"; +import boxen from "npm:boxen@8.0.1"; +import console from "node:console"; +import process from "node:process"; dayjs.extend(relativeTime); dayjs.extend(duration); @@ -29,7 +20,6 @@ function _registerExtend(program: Command) { .requiredOption( "-d, --duration ", "Extension duration (rounded up to the nearest hour)", - parseDuration, ) .option( "-p, --price ", @@ -44,61 +34,55 @@ function _registerExtend(program: Command) { "--standing", "Places a standing order. Default behavior is to place an order that auto-cancels if it can't be filled immediately.", ) - .configureHelp({ - optionDescription: (option) => { - if (option.flags === "-h, --help") { - return "Display help for extend"; - } - return option.description; - }, - }) .addHelpText( - "after", + "before", ` -Examples: - \x1b[2m# Get a Quote to extend a contract for 1 hour\x1b[0m - $ sf extend --contract --duration 1h --quote - - \x1b[2m# Auto confirm extending a contract by 1 hour at market price\x1b[0m - $ sf extend -c -d 1h --yes - - \x1b[2m# Extend a contract for 2 hours at a specific price\x1b[0m - $ sf extend -c -d 2h --price 1.50 +${ + boxen( + `\x1b[31m\x1b[97msf extend\x1b[31m is deprecated.\x1b[0m + \x1b[31mTo create, extend, and release specific machines directly, use \x1b[97msf nodes\x1b[31m.\x1b[0m + \x1b[31mTo "extend" a contract, use \x1b[97msf buy -colo -d \x1b[31m.\x1b[0m + \x1b[31mHowever, contracts don't map to specific machines, so you can't choose which will persist.\x1b[0m + \x1b[31mWe strongly recommend using \x1b[97msf nodes\x1b[31m instead.\x1b[0m`, + { + padding: 0.75, + borderColor: "red", + }, + ) + } `, ) - .action(async function extendAction(options) { - const contract = await getContract(options.contract); - if (!contract) { - logAndQuit(`Contract ${options.contract} not found`); - } + .action(function extendAction(options) { + // Build the equivalent sf buy command + let equivalentCommand = + `sf buy -colo ${options.contract} -d ${options.duration}`; - if (contract.status !== "active") { - logAndQuit( - `Contract ${contract.id} is ${contract.status}. Only active contracts can be extended.`, - ); + if (options.price) { + equivalentCommand += ` -p ${options.price}`; + } + if (options.yes) { + equivalentCommand += ` -y`; } - - const activeContract = contract as ActiveContract; - const activeContractRange = getContractRange(activeContract.shape); - - const quoteOptions: SfBuyOptions = { - type: activeContract.instance_type, - accelerators: getContractAcceleratorQuantity(activeContract.shape) * - GPUS_PER_NODE, - colocate: activeContract.id, - duration: options.duration, - price: options.price, - start: activeContractRange.endsAt, - quote: options.quote, - yes: options.yes, - standing: options.standing, - }; - if (options.quote) { - render(); - } else { - render(); + equivalentCommand += ` -q`; + } + if (options.standing) { + equivalentCommand += ` --standing`; } + + console.error(boxen( + `\x1b[31m\x1b[97msf extend\x1b[31m is deprecated.\x1b[0m + \x1b[31mTo create, extend, and release specific machines directly, use \x1b[97msf nodes\x1b[31m.\x1b[0m + \x1b[31mTo "extend" a contract, use: \x1b[97m${equivalentCommand}\x1b[31m.\x1b[0m + \x1b[31mHowever, contracts don't map to specific machines, so you can't choose which will persist.\x1b[0m + \x1b[31mWe strongly recommend using \x1b[97msf nodes\x1b[31m instead.\x1b[0m`, + { + padding: 0.75, + borderColor: "red", + }, + )); + + process.exit(0); }); } From 37d0ff76dfa990cf61a12bba1eac476b5b30dcf2 Mon Sep 17 00:00:00 2001 From: Daniel Tao Date: Fri, 31 Oct 2025 20:16:59 -0700 Subject: [PATCH 2/2] fix: bump lockfile --- deno.lock | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/deno.lock b/deno.lock index fdd53b5..143ad66 100644 --- a/deno.lock +++ b/deno.lock @@ -2,6 +2,7 @@ "version": "5", "specifiers": { "jsr:@std/assert@1.0.11": "1.0.11", + "jsr:@std/fmt@*": "1.0.8", "jsr:@std/internal@^1.0.5": "1.0.12", "npm:@commander-js/extra-typings@^12.1.0": "12.1.0_commander@12.1.0", "npm:@inkjs/ui@2": "2.0.0_ink@5.2.1__@types+react@18.3.26__react@18.3.1_@types+react@18.3.26_react@18.3.1", @@ -13,12 +14,16 @@ "npm:@types/semver@^7.5.8": "7.7.1", "npm:async-retry@^1.3.3": "1.3.3", "npm:axios@^1.8.4": "1.12.2", + "npm:boxen@8.0.1": "8.0.1", "npm:boxen@^8.0.1": "8.0.1", "npm:chrono-node@^2.9.0": "2.9.0", "npm:cli-progress@^3.12.0": "3.12.0", + "npm:cli-spinners@*": "3.3.0", "npm:cli-table3@0.6.5": "0.6.5", "npm:commander@^12.1.0": "12.1.0", "npm:date-fns@^4.1.0": "4.1.0", + "npm:dayjs@*": "1.11.13", + "npm:dayjs@1.11.13": "1.11.13", "npm:dayjs@^1.11.13": "1.11.18", "npm:dotenv@^16.4.5": "16.6.1", "npm:ink-link@^4.1.0": "4.1.0_ink@5.2.1__@types+react@18.3.26__react@18.3.1_@types+react@18.3.26_react@18.3.1", @@ -39,9 +44,12 @@ "npm:semver@^7.6.3": "7.7.3", "npm:shescape@^2.1.1": "2.1.6", "npm:tiny-invariant@^1.3.3": "1.3.3", + "npm:tweetnacl-util@*": "0.15.1", "npm:tweetnacl-util@~0.15.1": "0.15.1", + "npm:tweetnacl@*": "1.0.3", "npm:tweetnacl@^1.0.3": "1.0.3", - "npm:yaml@2.6.1": "2.6.1" + "npm:yaml@2.6.1": "2.6.1", + "npm:yn@*": "5.1.0" }, "jsr": { "@std/assert@1.0.11": { @@ -50,6 +58,9 @@ "jsr:@std/internal" ] }, + "@std/fmt@1.0.8": { + "integrity": "71e1fc498787e4434d213647a6e43e794af4fd393ef8f52062246e06f7e372b7" + }, "@std/internal@1.0.12": { "integrity": "972a634fd5bc34b242024402972cd5143eac68d8dffaca5eaa4dba30ce17b027" } @@ -432,6 +443,9 @@ "date-fns@4.1.0": { "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==" }, + "dayjs@1.11.13": { + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==" + }, "dayjs@1.11.18": { "integrity": "sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==" }, @@ -1033,6 +1047,9 @@ "integrity": "sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==", "bin": true }, + "yn@5.1.0": { + "integrity": "sha512-TfXLvT6eVsBNIm8rAXTwJYdQFtOXaHQ+rA7LU8HL8C/BFfaSfhvFE5T1rHAdBCbAj808HaqjXVkmo8jmeGOqhw==" + }, "yoctocolors-cjs@2.1.3": { "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==" }, @@ -1093,12 +1110,12 @@ "https://esm.sh/dayjs@1.11.13/denonext/plugin/duration.mjs": "64bd1dd95adf21a54fcda2dd3161998cd2780a4789d43c14b63d33ed012d3938", "https://esm.sh/dayjs@1.11.13/denonext/plugin/relativeTime.mjs": "b38196c727ee8c425eff06f091298f945b1f041fb8c3a0756b40081d6f067b3d", "https://esm.sh/dayjs@1.11.13/denonext/plugin/timezone.mjs": "94d48607684cc8423f815fee4e72bf334c801cdf52d79caa00481a7e83c345f4", - "https://esm.sh/dayjs@1.11.13/es2022/plugin/utc.mjs": "01c663b7318d6daa10a2377306a878808a535d6dc4056fa5b60a8d31c5d2254f", + "https://esm.sh/dayjs@1.11.13/denonext/plugin/utc.mjs": "7e89223a0933377aaa5fd52d97f116ed3d48c93d5b2ed305d86bde9e496b3e12", "https://esm.sh/dayjs@1.11.13/plugin/advancedFormat.js": "cbb82f21176632f2ad3590cc2c51356463d527be5a221545520d4a9034744fab", "https://esm.sh/dayjs@1.11.13/plugin/duration.js": "9f6f119d7af58b8e08424bf897daaa286cadaa63d58262140969102671296a51", "https://esm.sh/dayjs@1.11.13/plugin/relativeTime.js": "48ccbeb4a6e19c6320f41edc1028ac85e7baf8cd434faebe65e3208ec70cea6b", "https://esm.sh/dayjs@1.11.13/plugin/timezone.js": "cfe2b0eec9855373de8fbc92d3503d25930ab3156522482e55f7a66bb3d4fb32", - "https://esm.sh/dayjs@1.11.13/plugin/utc.js": "3c51f2f90816004281990ed17d5010311c2b77875663127cbc773dc440ae7dde", + "https://esm.sh/dayjs@1.11.13/plugin/utc.js": "2e41a0673e6e7c7c962983f1680911ef6feb27ded6007bc7705787ac1b2637b7", "https://esm.sh/emoji-regex@10.6.0/denonext/emoji-regex.mjs": "bec0264591b37a7132b080ed5586e3fc577392b1444230d973d7209d04f4f6e5", "https://esm.sh/emoji-regex@10.6.0?target=denonext": "0b0ed0e68f224d09d771339aaf83dd19d31c149e6fb1213ea3a12ef8ee977188", "https://esm.sh/emoji-regex@8.0.0/denonext/emoji-regex.mjs": "3969ad7b107b6f585354a5019c24320e3d91d6bb70a96e2beead925247aed9dc",