import { basename } from "node:path" import { Show } from "solid-js" import { isLocal } from "../../config/paths.ts" import { useTui } from "../context.ts" const MODE_LABEL = { manual: "manual", edit: "edit", auto: "AUTO", plan: "plan" } as const export function fmtTokens(n: number): string { return n >= 10_000 ? `${Math.round(n / 1000)}k` : n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n) } /** The status bar's word for the session's jobs: the running count, `!` when one ended unseen or * holds output the model has not read; nothing while there is nothing to say. */ export function jobsWord(jobs: { state: string; unread: number; unseen?: boolean }[]): string { const running = jobs.filter((j) => j.state === "running").length const news = jobs.some((j) => j.unseen || j.unread > 0) if (!running && !news) return "" return `${running} job${running === 1 ? "" : "s"}${news ? "!" : ""}` } /** One line: mode · model · effort on the left; the jobs, context use and where on the right — or, * for a moment, a flash (a copy) in their place. The jobs word sits on the right, which is never * truncated: at 80 columns a long project name cuts the left short, and a running job is the one * thing that must stay visible. */ export function StatusBar(p: { mode: () => string; model: () => string; effort: () => string; branch?: string; voice?: () => string; flash?: () => string | undefined; remote?: () => string; credits?: () => string }) { const { theme, view, app } = useTui() const c = () => theme().colors const modeColor = () => ({ manual: c().statusText, edit: c().statusGood, auto: c().statusCritical, plan: c().info })[p.mode() as keyof typeof MODE_LABEL] ?? c().statusText const ctx = () => { const u = view.state.usage if (!u) return { text: "ctx —", color: c().statusDim } const used = view.state.used ?? u.input + u.output const total = view.state.context if (!total) return { text: `ctx ${fmtTokens(used)}${u.estimated ? "~" : ""}`, color: c().statusText } const pct = Math.round((used / total) * 100) const color = pct >= 90 ? c().statusCritical : pct >= 75 ? c().statusBad : pct >= 50 ? c().statusWarn : c().statusGood return { text: `ctx ${fmtTokens(used)}${u.estimated ? "~" : ""}/${fmtTokens(total)} ${pct}%`, color } } return ( {MODE_LABEL[p.mode() as keyof typeof MODE_LABEL] ?? p.mode()} · {p.model()} {p.effort() ? ` · ${p.effort()}` : ""} {p.voice?.() ? ` · ${p.voice()}` : ""} {p.remote?.() ? ` · ${p.remote()}` : ""} {jobsWord(view.state.jobs) ? `${jobsWord(view.state.jobs)} · ` : ""} {view.state.rate ? `${Math.round(view.state.rate)} tok/s · ` : ""} {p.credits?.() ? `${p.credits()} · ` : ""} {ctx().text} · {isLocal() ? "local " : ""} {basename(app.project.root)}{p.branch ? `@${p.branch}` : ""} } > {p.flash!()} ) }