Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
| import { HuggingFaceBucketWriteProbe } from "./bucket-write-probe.js"; | |
| import { SystemInstallerClock } from "./clock.js"; | |
| import { HuggingFaceControlTokenScope } from "./control-token-scope.js"; | |
| import { HfCli } from "./hf.js"; | |
| import { BoundedHttpAdapter } from "./http.js"; | |
| import { StableIdentityAdapter } from "./identity.js"; | |
| import { HuggingFaceInferenceTokenScope } from "./inference-token-scope.js"; | |
| import type { InstallPlan } from "./model.js"; | |
| import { BoundedJsonProcess } from "./process.js"; | |
| import { TtyInstallerSecretInput } from "./secret-input.js"; | |
| import { GitSourceAdapter } from "./source.js"; | |
| import type { | |
| ActivationResult, | |
| ApplyInstallResult, | |
| ConfigureProgressEvent, | |
| InstallerDependencies, | |
| } from "./workflow.js"; | |
| export function defaultDependencies(): InstallerDependencies { | |
| const hf = new HfCli(new BoundedJsonProcess()); | |
| const http = new BoundedHttpAdapter(); | |
| return { | |
| hf, | |
| clock: new SystemInstallerClock(), | |
| bucketWriteProbe: new HuggingFaceBucketWriteProbe(), | |
| controlTokenScope: new HuggingFaceControlTokenScope(http), | |
| inferenceTokenScope: new HuggingFaceInferenceTokenScope(http), | |
| reportControlCredentialWarnings(warnings) { | |
| process.stderr.write(formatControlCredentialWarnings(warnings)); | |
| }, | |
| reportConfigureProgress(event) { | |
| process.stderr.write(`${formatConfigureProgress(event)}\n`); | |
| }, | |
| http, | |
| identity: new StableIdentityAdapter(hf, http), | |
| secretInput: new TtyInstallerSecretInput(), | |
| source: new GitSourceAdapter(), | |
| }; | |
| } | |
| function formatElapsed(milliseconds: number): string { | |
| const seconds = Math.max(0, Math.floor(milliseconds / 1000)); | |
| const minutes = Math.floor(seconds / 60); | |
| const remainingSeconds = seconds % 60; | |
| return minutes === 0 ? `${seconds}s` : `${minutes}m ${remainingSeconds}s`; | |
| } | |
| export function formatConfigureProgress(event: ConfigureProgressEvent): string { | |
| switch (event.kind) { | |
| case "runtime_wait_started": | |
| return "Waiting for the Space runtime to start..."; | |
| case "runtime_waiting": | |
| return `Space runtime is still starting (${formatElapsed(event.elapsedMilliseconds)} elapsed).`; | |
| case "runtime_wait_complete": | |
| return `Space runtime wait completed (${formatElapsed(event.elapsedMilliseconds)} elapsed).`; | |
| case "readiness_wait_started": | |
| return "Waiting for the control service to become ready..."; | |
| case "readiness_initializing": | |
| return `Control service is still initializing (${formatElapsed(event.elapsedMilliseconds)} elapsed).`; | |
| case "readiness_ready": | |
| return `Control service is ready (${formatElapsed(event.elapsedMilliseconds)} elapsed).`; | |
| case "readiness_timed_out": | |
| return `Control service readiness timed out (${formatElapsed(event.elapsedMilliseconds)} elapsed).`; | |
| } | |
| } | |
| export function parseOptions( | |
| args: readonly string[], | |
| specification: Record<string, { required: boolean }>, | |
| ): Record<string, string> | "help" { | |
| if (args.includes("--help")) return "help"; | |
| const output: Record<string, string> = {}; | |
| for (let index = 0; index < args.length; index += 2) { | |
| const key = args[index]; | |
| const value = args[index + 1]; | |
| if (!key?.startsWith("--") || !value || value.startsWith("--")) { | |
| throw new Error("invalid command arguments"); | |
| } | |
| const name = key.slice(2); | |
| if (!(name in specification) || name in output) { | |
| throw new Error("invalid command arguments"); | |
| } | |
| output[name] = value; | |
| } | |
| for (const [name, option] of Object.entries(specification)) { | |
| if (option.required && !output[name]) { | |
| throw new Error(`missing --${name}`); | |
| } | |
| } | |
| return output; | |
| } | |
| export function parseSavedPlanOptions( | |
| args: readonly string[], | |
| ): { space: string; stateDirectory?: string } | "help" { | |
| const options = parseOptions(args, { | |
| space: { required: true }, | |
| "state-dir": { required: false }, | |
| }); | |
| if (options === "help") return options; | |
| return { | |
| space: options.space as string, | |
| ...(options["state-dir"] ? { stateDirectory: options["state-dir"] as string } : {}), | |
| }; | |
| } | |
| export function parseConfigureOptions( | |
| args: readonly string[], | |
| ): { space: string; stateDirectory?: string; replaceCredentials: boolean } | "help" { | |
| if (args.includes("--help")) return "help"; | |
| const replacementFlags = args.filter((arg) => arg === "--replace-credentials"); | |
| if (replacementFlags.length > 1) throw new Error("invalid command arguments"); | |
| const saved = parseSavedPlanOptions( | |
| args.filter((arg) => arg !== "--replace-credentials"), | |
| ); | |
| if (saved === "help") return saved; | |
| return { | |
| ...saved, | |
| replaceCredentials: replacementFlags.length === 1, | |
| }; | |
| } | |
| export function formatPlanOutput( | |
| plan: InstallPlan, | |
| customStateDirectory = false, | |
| ): string { | |
| const observed = plan.observed_preconditions; | |
| const phase = observed.space?.variables.HARBOR_HF_INSTALL_PHASE; | |
| const action = | |
| phase === "credentials_required" || phase === "source_staged" | |
| ? "continue paused credential bootstrap" | |
| : !observed.space | |
| ? "create paused bootstrap Space and Bucket" | |
| : observed.bucket | |
| ? "update installer-managed Space" | |
| : "update Space and create Bucket"; | |
| const nextCommand = | |
| !observed.space || !observed.bucket ? "install:provision" : "install:configure"; | |
| return [ | |
| `Space: ${plan.targets.space_id}`, | |
| `Bucket: ${plan.targets.bucket_id}`, | |
| "Access: protected", | |
| "Hardware: cpu-basic", | |
| "Write mode: disabled", | |
| `Action: ${action}`, | |
| "", | |
| "Plan saved privately.", | |
| ...(!observed.space ? ["No service credentials are required for bootstrap."] : []), | |
| customStateDirectory | |
| ? `Next: rerun ${nextCommand} with this Space and the same --state-dir.` | |
| : `Next: npm run ${nextCommand} -- --space ${plan.targets.space_id}`, | |
| "", | |
| ].join("\n"); | |
| } | |
| export function formatProvisionOutput( | |
| result: Extract<ApplyInstallResult, { status: "credentials_required" }>, | |
| customStateDirectory = false, | |
| ): string { | |
| return [ | |
| "Provisioning verified.", | |
| "", | |
| `Space: ${result.space_id}`, | |
| `Bucket: ${result.bucket_id}`, | |
| "Runtime: paused", | |
| "Write mode: disabled", | |
| "Secrets stored: no", | |
| "Source uploaded: no", | |
| "", | |
| customStateDirectory | |
| ? "Next: rerun install:configure with this Space and the same --state-dir." | |
| : `Next: npm run install:configure -- --space ${result.space_id}`, | |
| "", | |
| ].join("\n"); | |
| } | |
| export function formatConfigureOutput( | |
| spaceId: string, | |
| result: Extract<ApplyInstallResult, { status: "installed" }>, | |
| ): string { | |
| const verification = result.verification; | |
| const warnings = | |
| result.control_credential_warnings.length === 0 || | |
| result.control_credential_warnings_reported | |
| ? [] | |
| : formatControlCredentialWarnings(result.control_credential_warnings) | |
| .trimEnd() | |
| .split("\n"); | |
| return [ | |
| ...warnings, | |
| "Installation verified.", | |
| `Space: ${spaceId}`, | |
| `URL: ${verification.space_url}`, | |
| `Anonymous health: ${verification.anonymous_live}`, | |
| `Authenticated system: ${verification.authenticated_system}`, | |
| `Source upload: ${verification.source_upload_revision}`, | |
| "Write mode: disabled", | |
| "Production ready: no", | |
| "", | |
| "Review access and credential scopes before activation.", | |
| "", | |
| ].join("\n"); | |
| } | |
| export function formatControlCredentialWarnings(warnings: readonly string[]): string { | |
| if (warnings.length === 0) return ""; | |
| return [ | |
| "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", | |
| "WARNING: THE CONTROL CREDENTIAL IS OVER-SCOPED", | |
| "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", | |
| ...warnings.map((warning) => `WARNING: ${warning}`), | |
| "WARNING: Installation is continuing because required permissions and", | |
| "WARNING: the fresh artifact Bucket write/read-back proof passed.", | |
| "WARNING: Replace this credential with a narrower token when possible.", | |
| "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", | |
| "", | |
| ].join("\n"); | |
| } | |
| export function formatActivationOutput( | |
| spaceId: string, | |
| result: ActivationResult, | |
| ): string { | |
| return [ | |
| result.write_mode === "enabled" | |
| ? "Installation activated." | |
| : "Writes disabled and Space paused.", | |
| `Space: ${spaceId}`, | |
| `URL: ${result.space_url}`, | |
| "Hardware: cpu-basic", | |
| `Runtime: ${result.runtime}`, | |
| `Write mode: ${result.write_mode}`, | |
| `Authenticated system: ${result.authenticated_system}`, | |
| "Production ready: no", | |
| ...(result.write_mode === "enabled" | |
| ? ["", "Campaign submissions and reconciliation are enabled."] | |
| : []), | |
| "", | |
| ].join("\n"); | |
| } | |
| export async function cliMain(action: () => Promise<void>): Promise<void> { | |
| try { | |
| await action(); | |
| } catch (error) { | |
| const message = error instanceof Error ? error.message : "installer failed"; | |
| process.stderr.write(`error: ${message}\n`); | |
| process.exitCode = 1; | |
| } | |
| } | |