import type { Component, Focusable, TUI } from "@kolisachint/hoocode-tui"; /** * How the same task list is presented: * - flat → one ungrouped list (default) * - subagents → grouped by owning agent (◆ main orchestrator + ◇ workers) * - teams → grouped by named role-agent (▸), with handoff arrows */ export type TaskPanelView = "flat" | "subagents" | "teams"; /** * Task panel rendered just above the editor prompt. * * - A state-colored left rail groups the pane (working=warning, reviewed=success, * stopped=error) without drawing a box. * - A tab strip tops the list — one tab per lens with content, each carrying its * own done/total — but only when there is more than one lens to switch to (or * the navigable teams roster is showing). A single-lens pane is rows only. * - Shows all tasks with all statuses (pending / in_progress / done / failed). * The active row carries the static ◐ of the design's glyph table; only * delegated rows animate, and only their 1s run clock. * - A single-cell owner glyph (◇ subagent / ▸ team role / ⧉ MCP) sits before * the id where it disambiguates; main-owned rows carry no glyph in the flat * lens (the rail already attributes the pane to the main agent). A text * origin tag before the title names the owner: the subagent type * ("[explore]"), the team role ("[planner]", fed by `--team `), or the * MCP server ("[github]"). * - Three views split by ownership (cycled via app.tasks.cycleForward, shown as a * `tasks · subagents · teams` switcher in the header): * - flat ("tasks") — the main agent's own TodoWrite plan, with each * dispatched subagent run nested under the plan item it was dispatched * for (linkedTaskId), so the plan and the agents executing it read as * one picture; * - subagents — a recursive task tree over delegated work, where a subagent * that spawned a subagent shows its nested tasks (roots are the dispatched * subagents and direct MCP calls; children link via parentTaskId, merged * across the process boundary). Each task is its own node keeping its * [subagentMode]/[server] tag, with depth drawn by └─/├─/│ connectors; a * run with only top-level tasks reads flat (no extra indent); * - teams — grouped by named role-agent with handoff arrows. * The cycle is adaptive: empty lenses are skipped and dropped from the * switcher, which hides entirely when only one lens has content. An empty flat * lens (no main task) falls through to subagents when delegated work exists. * - LIFO within the window: newest tasks appear at the bottom (closest to the prompt). * - Finished tasks carry their wall-clock cost and stay visible until the next * user message arrives (see taskStore.reset()), not the moment they finish. * - Collapses to zero lines when there are no tasks — unless a team roster is * registered (`--team`), in which case the empty flat lens falls through to * teams and every role renders as a placeholder group, so idle roles are * visible from startup. */ /** Every row the ledger has, or its counts alone on one row. */ export type TaskPanelDensity = "full" | "summary"; export declare class TaskPanelComponent implements Component, Focusable { private readonly ui; private runClockTimer; private view; private density; private disposed; private memoVersion; private memoWidth; private lineMemo; private agentByIdMemo; private subagentRowsMemo; private flatRowsMemo; /** Drop all memoized render state when the store or width changed. */ private syncMemo; private agentById; private subagentRows; private flatRows; /** * formatTaskLine with caching for rows that are stable between store mutations. * Only a live delegated row is not: its run clock advances against Date.now() * with no mutation to invalidate the entry, so it renders fresh on every tick. * Everything else — including a live main-plan row, whose activity text arrives * through a store mutation — is cached until the next mutation or width change * (handled by syncMemo). */ private taskLine; focused: boolean; private selectedRole; /** Open the inline nudge editor for the selected role. */ onNudge?: (role: string) => void; /** Open the attach side panel for the selected role. */ onAttach?: (role: string) => void; /** Leave team focus (focus returns to the main editor). */ onExitFocus?: () => void; constructor(ui?: TUI); invalidate(): void; private roleAgents; /** The role the team-focus cursor sits on (clamped to the live roster). */ focusedRole(): string | undefined; handleInput(data: string): void; getView(): TaskPanelView; setView(view: TaskPanelView): void; /** * How many rows the ledger takes. Driven by `ChromeController`, not by the * pane itself — the pane knows what it has to say, the chrome knows how much * room there is to say it in. */ setDensity(density: TaskPanelDensity): void; /** * Advance to the next view lens with content (flat → subagents → teams → * flat), skipping empty lenses. With nothing delegated this is a no-op on * flat; a stale view (its lens emptied since selection) snaps back to flat. */ cycleView(direction?: "forward" | "backward"): TaskPanelView; /** * Tick the run clock only while a delegated row is live. Nothing else in the * pane moves, so with no subagent or MCP call running there is no timer at all * — a stale in-progress plan item can no longer pin the process to a render * loop the way the old 120ms spinner did. */ private ensureRunClock; /** Stop the run clock. Call on teardown. */ dispose(): void; render(width: number): string[]; } //# sourceMappingURL=task-panel.d.ts.map