// docs/SIDEBAR.md: the session card's meta line — activity colour mapping and // the shared duration format. Both clients compute it identically; the TUI // mirrors this in crates/maestro-tui. import type { ActivityState, IsoTimestamp } from "./types.js"; /** A state held shorter than this has no duration fragment. */ export const META_LINE_MIN_HOLD_MS = 30_000; // Payloads predating #102 default `activity_since` to the Unix epoch; anything // implausibly old is treated as "never observed" rather than a huge duration. const PLAUSIBLE_EPOCH_MS = Date.UTC(2010, 0, 1); export function activityHeldMs(since: IsoTimestamp | undefined, now: number): number | null { if (!since) return null; const t = Date.parse(since); if (Number.isNaN(t) || t < PLAUSIBLE_EPOCH_MS) return null; return Math.max(0, now - t); } /** `<60s` → whole seconds, `<60m` → whole minutes, else whole hours. Floored * everywhere so the counter never shows a duration the state hasn't reached. */ export function activityDurationLabel(heldMs: number): string { const s = Math.floor(heldMs / 1000); if (s < 60) return `${s}s`; const m = Math.floor(s / 60); if (m < 60) return `${m}m`; return `${Math.floor(m / 60)}h`; } /** CSS hook for the state's colour (`styles.css` maps slugs to tokens). An * unknown variant degrades to idle so rendering never fails (Precedence). */ export function activityColorSlug(state: ActivityState | string): string { switch (state) { case "Active": return "active"; case "AwaitingInput": return "awaiting-input"; case "Error": return "error"; default: return "idle"; } }