/** * Pi adapter for the party/raid frames widget (agent-frames-widget * capability; design D3, D4, D6, D11, and the subagent-ui-theming-and-style * change's approach A). * * Thin by design: observer wiring, the spinner tick, `setWidget` calls, * THEME BINDING, color-scheme detection, and the session-scoped visibility * flag live here. ALL formatting/layout lives in the host-neutral renderer * (`src/agent-frames.ts`) — this file contains no frame-drawing logic. * * Theme binding (approach A): the widget factory receives pi's global theme * PROXY, which always resolves the ACTIVE theme — so the chrome closures * bound here (`border`/`muted`/`dim`/`text` → `theme.fg(token, …)`) follow * theme switches automatically without a factory re-invoke (verified in pi * source: `onThemeChange` only invalidates + re-renders; extension widgets * are not re-created). The style object is rebuilt per render — cheap, and * it keeps `getColorMode()` current too. * * Color-scheme detection (design D1a): pi's `Theme` instance exposes color * MODE but not dark/light, and its detection helpers are not exported from * the package root — so this adapter mirrors them: an OSC-11 probe via * `tui.queryTerminalBackgroundColor` (kicked off once when the factory first * yields a TUI), with a COLORFGBG env fallback and a dark default. The * result is cached; `render(width)` reads it synchronously. */ import type { ExtensionUIContext } from "@earendil-works/pi-coding-agent"; import type { TUI } from "@earendil-works/pi-tui"; import type { WidgetSettings } from "#src/model-routing"; import type { ActivitySnapshot, SubagentObserver } from "#src/observer"; import type { SpawnQueue } from "#src/spawn-queue"; import type { DurableTracker } from "#src/tracker"; import type { SubagentRecord } from "#src/types"; import { type StyleConfig } from "#src/widget-style"; /** Injectable construction options (style config, scoping, test seams). */ export interface AgentWidgetOptions { /** * Resolved GLOBAL style config (widget-style-config) — merged over the * theme-derived defaults (config wins). Per-record role styles ride the * tracker records themselves. */ globalStyle?: StyleConfig; /** Current parent session id — scopes running-record visibility (D5). */ parentSessionId?: string; /** Registry-liveness predicate: agent actively driven in THIS session. */ isAgentLive?: (agentId: string) => boolean; /** Background-color probe override (tests). Default: OSC 11 via the TUI. */ queryBackground?: (tui: TUI) => Promise<{ r: number; g: number; b: number; } | undefined>; /** Environment for the COLORFGBG fallback (tests). */ env?: Record; /** Transient pending spawns, supplied by the extension composition root. */ spawnQueue?: SpawnQueue; } /** * Persistent frames widget showing all subagents as party frames/raid cells. * * Implements SubagentObserver so it receives lifecycle and activity events * (each just schedules a re-render; the renderer reads tracker state fresh * every frame). Visibility is presentation-only: hiding clears the widget * region while tracking, lifecycle monitoring, and observers keep running. */ export declare class AgentWidget implements SubagentObserver { private tracker; private settings; private options; private ui?; private tui?; private piTheme?; private frameIndex; private animTimer; private visibleFlag; /** Whether the last tick rendered any lines (skip idle re-renders). */ private hadContent; /** * Session epoch: terminal records that ended before this are never shown. * Stamped in attach() — AFTER the startup reconciler has marked stale * records crashed, so persisted history from earlier sessions (including * reconciler crash-marks) never renders as lingering failures. */ private sessionStartAt; /** Cached color scheme — env fallback until the async probe lands (D1a). */ private scheme; private schemeProbeStarted; private unsubscribeQueue?; constructor(tracker: DurableTracker, settings?: WidgetSettings, options?: AgentWidgetOptions); /** * Attach the widget to the Pi UI context and start the spinner tick. */ attach(ui: ExtensionUIContext): void; /** * Detach the widget and stop the animation. */ detach(): void; /** Whether the widget region is currently shown. */ get visible(): boolean; /** * Flip widget visibility. Hidden clears the layout region; shown restores * it reflecting current tracker state. Returns the new visibility. */ toggleVisibility(): boolean; onSubagentCreated(_record: SubagentRecord): void; onSubagentStarted(_record: SubagentRecord): void; onSubagentCompleted(_record: SubagentRecord): void; onSubagentActivity(_record: SubagentRecord, _activity: ActivitySnapshot): void; /** * Build the injectable style: chrome closures over pi's semantic tokens * (live theme proxy → auto light/dark + host 256 downgrade), the cached * detected scheme, the scheme-appropriate default palette, and the * resolved global config style merged on top (config wins). */ private buildStyle; /** Kick off the one-time async OSC-11 scheme probe (design D1a). */ private startSchemeProbe; /** * Register the component-factory widget. The component form (not string * lines) is required: only `render(width)` sees the viewport width, which * drives the width-responsive party slot count K. `placement` passes * through — the setting's values ARE pi's regions (design D6 rename). */ private registerWidget; /** Pure render pass — reads tracker state fresh (design D6). */ private renderLines; /** Spinner tick: advance the frame and re-render when there's content. */ private tick; /** The renderer's visibility selection (session + parent scoped). */ private visibleSelection; private requestRender; /** * Status bar keeps a compact running count (also useful while hidden). * Computed by the SAME shared counter the spawner's concurrency cap uses * (`countOwnedRunningAgents`), so the displayed count and the enforced cap * can never disagree on ownership scoping. */ private updateStatusBar; } //# sourceMappingURL=agent-widget.d.ts.map