pi extension update

This commit is contained in:
Jonas H
2026-03-29 10:01:22 +02:00
parent 58ef050e4f
commit f66efc67bb
9 changed files with 3321 additions and 6 deletions

View File

@@ -62,6 +62,21 @@ function getModelShortName(modelId: string): string {
return modelId.replace(/^claude-/, "");
}
// Format duration in milliseconds to human readable (e.g., "2h 55m")
function formatDurationMs(ms: number): string {
if (!Number.isFinite(ms) || ms <= 0) return "now";
const totalSeconds = Math.floor(ms / 1000);
const d = Math.floor(totalSeconds / 86400);
const h = Math.floor((totalSeconds % 86400) / 3600);
const m = Math.floor((totalSeconds % 3600) / 60);
if (d > 0 && h > 0) return `${d}d ${h}h`;
if (d > 0) return `${d}d`;
if (h > 0 && m > 0) return `${h}h ${m}m`;
if (h > 0) return `${h}h`;
if (m > 0) return `${m}m`;
return "<1m";
}
// Nerd Font codepoints matched to what claude-account-switch.ts emits
const ICON_PERSONAL = "\uEF85"; // U+EF85 — home
const ICON_WORK = "\uDB80\uDCD6"; // U+F00D6 — briefcase (surrogate pair)
@@ -71,6 +86,12 @@ export default function (pi: ExtensionAPI) {
let ctx: any = null;
let tuiRef: any = null;
let footerDataRef: any = null;
// Track usage data for dynamic S/W bar rendering
let usageSession: number | null = null;
let usageWeekly: number | null = null;
let sessionResetsAt: number | null = null;
let weeklyResetsAt: number | null = null;
// ---------------------------------------------------------------------------
// Footer line builder — called on every render
@@ -106,7 +127,33 @@ export default function (pi: ExtensionAPI) {
const usageRaw = statuses.get("usage-bars");
const contextUsage = ctx?.getContextUsage?.();
{
let block = usageRaw ?? "";
let block: string;
if (usageSession !== null && usageWeekly !== null) {
// Build S/W bars directly from stored event data so we can cleanly
// append the dynamic countdown without trying to parse ANSI strings.
const session = Math.max(0, Math.min(100, Math.round(usageSession)));
const weekly = Math.max(0, Math.min(100, Math.round(usageWeekly)));
let sPart = theme.fg("muted", "S ") + renderBrailleBar(theme, session) + " " + theme.fg("dim", `${session}%`);
let wPart = theme.fg("muted", "W ") + renderBrailleBar(theme, weekly) + " " + theme.fg("dim", `${weekly}%`);
if (sessionResetsAt !== null) {
const msLeft = sessionResetsAt - Date.now();
if (msLeft > 0) sPart += " " + theme.fg("dim", formatDurationMs(msLeft));
}
if (weeklyResetsAt !== null) {
const msLeft = weeklyResetsAt - Date.now();
if (msLeft > 0) wPart += " " + theme.fg("dim", `\u27F3 ${formatDurationMs(msLeft)}`);
}
block = sPart + pipeSep + wPart;
} else {
// Fallback to raw status for loading / error states
block = usageRaw ?? "";
}
if (contextUsage && contextUsage.percent !== null) {
const pct = Math.round(contextUsage.percent);
const cBar =
@@ -188,4 +235,14 @@ export default function (pi: ExtensionAPI) {
pi.events.on("claude-account:switched", () => {
if (tuiRef) tuiRef.requestRender();
});
// Listen for usage updates — store raw values so we can build bars + dynamic
// countdown directly rather than parsing the ANSI status string from usage-bars.
pi.events.on("usage:update", (data: any) => {
if (data.session !== undefined) usageSession = data.session;
if (data.weekly !== undefined) usageWeekly = data.weekly;
if (data.sessionResetsAt !== undefined) sessionResetsAt = data.sessionResetsAt;
if (data.weeklyResetsAt !== undefined) weeklyResetsAt = data.weeklyResetsAt;
if (tuiRef) tuiRef.requestRender();
});
}