/** * /gpu slash commands — human-facing dashboard. All heavy lifting is in the * gpu_* tools; commands read the same registry. */ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; import { loadProviders, loadDeployments, loadJobs, loadPolicy, monthSpendUsd, todaySpendUsd, fmtUsd } from "./registry.js"; export function registerGpuCommands(pi: ExtensionAPI) { pi.registerCommand("gpu", { description: "GPU infrastructure dashboard — use /gpu setup, status, deploy , jobs, spend, stop , policy, onboard", handler: async (args, ctx) => { const a = args.trim(); const out = !a ? dashboard() : a === "setup" || a === "s" ? "Run /gpu setup (or ask the agent to run gpu_setup) to detect provider CLIs and authentication." : a === "status" || a === "st" ? statusView() : a === "jobs" || a === "j" ? jobsView() : a === "spend" ? spendView() : a === "onboard" || a === "ob" ? onboardCard() : a === "policy" ? (() => { const p = loadPolicy(); return `SPEND POLICY\n per-job ${fmtUsd(p.ceiling_per_job_usd)} · daily ${fmtUsd(p.ceiling_daily_usd)} · monthly ${fmtUsd(p.ceiling_monthly_usd)} · confirm above ${fmtUsd(p.confirm_above_usd)} · idle shutdown after ${p.idle_shutdown_after_min} min`; })() : a.startsWith("stop") || a.startsWith("destroy") ? `Destroy ${a.split(/\s+/)[1] || ""}: ask the agent to run gpu_destroy (it will confirm spend first).` : a.startsWith("deploy") ? `Deploy ${a.split(/\s+/)[1] || ""}: ask the agent to run gpu_ensure model= — it will find or provision the cheapest fitting deployment.` : dashboard(); ctx.ui.notify(out, "info"); }, }); } function dashboard(): string { const providers = loadProviders(); const deployments = loadDeployments(); const jobs = loadJobs(); const policy = loadPolicy(); const lines = [ "GPU INFRASTRUCTURE", "─────────────────", "Providers", ...providers.map((p) => ` ${p.name.padEnd(10)} ${p.installed && p.authenticated ? "✓" : p.installed ? "○ needs auth" : "○ not installed"}`), "Deployments", ...(deployments.length ? deployments.map((d) => { const dot = d.status === "ready" ? "●" : d.status === "provisioning" ? "◐" : d.status === "stopped" ? "○" : "✕"; return ` ${dot} ${d.id.padEnd(14)} ${d.model || d.runtime} ${d.gpu} @ ${d.provider} ${d.endpoint || ""} (${fmtUsd(d.cost_hr)}/hr)`; }) : [" (none — ask the agent to deploy a model)"]), `Jobs ${jobs.filter((j) => j.status === "running").length} running · ${jobs.filter((j) => j.status === "queued").length} queued · ${jobs.filter((j) => j.status === "completed").length} completed`, `Spend Today ${fmtUsd(todaySpendUsd())} · Month ${fmtUsd(monthSpendUsd())} (ceiling ${fmtUsd(policy.ceiling_monthly_usd)})`, "Commands: /gpu setup · /gpu deploy · /gpu jobs · /gpu spend · /gpu stop ", ]; return lines.join("\n"); } function statusView(): string { const providers = loadProviders(); const deployments = loadDeployments(); const lines = [ "STATUS", providers.map((p) => ` ${p.name}: ${p.installed ? (p.authenticated ? "ready" : "installed, needs auth") : "not installed"}`).join("\n"), "", deployments.length ? deployments.map((d) => ` ${d.id} ${d.status.toUpperCase()} ${d.gpu} @ ${d.provider} ${d.endpoint || ""} ${fmtUsd(d.cost_hr)}/hr`).join("\n") : " no deployments", ]; return lines.join("\n"); } function jobsView(): string { const jobs = loadJobs().slice(-15).reverse(); return jobs.length ? jobs.map((j) => `${j.id} ${j.status.padEnd(9)} ${j.workflow} ${j.duration_s ? j.duration_s + "s" : ""} ${j.cost_usd !== undefined ? fmtUsd(j.cost_usd) : ""}`).join("\n") : "No jobs yet."; } function spendView(): string { return `SPEND\n Today: ${fmtUsd(todaySpendUsd())}\n Month: ${fmtUsd(monthSpendUsd())}`; } function onboardCard(): string { return [ "H3 PRODUCTION — planning numbers (2026-08-12 snapshot, verify live)", " 1 finished minute = 4 × 15s clips (H3 maxes at 15s @ 2K with audio)", " anchors: RTX 6000 480p/15s = 56s @ 4-step Turbo · 5090 15s/0.4MP ≈ 3 min", " rule: Turbo LoRA 4-8 step + SageAttention2 + INT8 — never vanilla 20-step", " per finished minute: Salad 5090 ~$0.06 · Vast 5090 ~$0.14 · RunPod PRO 6000 ~$0.11", " $15 buys: Higgsfield 1 min · Vast 5090 ~100 min · Salad 5090 ~250 min", "Provider lanes: Vast 5090 (default) · Salad 5090 (aggressive economics) · RunPod PRO 6000 (predictable)", "Ask the agent to run the gpu-onboarding skill for the full first-run flow.", "Detail: docs/h3-economics.md", ].join("\n"); }