import type { HubTheme } from "./theme.js"; import { type Component, type TUI } from "@earendil-works/pi-tui"; import { DaemonClient } from "../lib/client.js"; import { type WorktreeChange } from "../lib/worktree.js"; import { type AgentDef } from "../lib/agents.js"; import type { DispatchArgs, JobRow } from "../lib/protocol.js"; import { type Preset } from "../lib/config.js"; /** M23: a picker's items matching its search: every word of it, in any case. */ export declare function pickerShown(p: { items: { label: string; value: string; }[]; query?: string; }): { label: string; value: string; }[]; export interface AgentViewOptions { tui: TUI; theme: HubTheme; /** Directory new jobs start in. */ cwd: string; /** AV-7: show only jobs started under this directory. */ cwdFilter?: string; /** Builds the dispatch request for a task typed into the view. */ /** A new pi job; the view adds its /model and /thinking defaults and @dir target. */ launch: (task: string, opts?: LaunchOptions) => LaunchRequest; /** M18: agents a task's first word or `@name` can pick, and the default one (`dispatchAgent`). */ agents?: () => ReadonlyMap; defaultAgent?: string; /** * M39: the template of a scheduled pi session: as `launch`, with `{{run}}` where each * run's own session file goes (no worktree). */ scheduleLaunch?: (task: string, opts: { cwd: string; model?: string; thinking?: string; }) => LaunchRequest; /** DI-6: a shell job (no model). */ launchShell?: (command: string, cwd: string) => DispatchArgs; /** M30: the user's agent profiles (terminal agents besides pi), by name. */ profiles?: () => string[]; /** M30: a new session of a profile's agent. */ launchProfile?: (profile: string, task: string, opts: { cwd: string; model?: string; thinking?: string; worktree?: boolean; }) => LaunchRequest; /** Slash commands of this pi (DI-4, DI-5: skills and prompt templates become first prompts). */ commands?: () => { name: string; source: string; }[]; /** M10: new sessions get a worktree unless /worktree off (config worktreeIsolation "all"). */ worktreeDefault?: boolean; /** DI-4: models for the /model picker, as "provider/id". */ models?: () => string[]; /** DI-4: past sessions of a directory for /resume. */ resumable?: (cwd: string) => Promise; /** * M23: pi's own session selector for /resume (search, this directory or all, sort); * without it, or when it cannot be built, the view's own list. */ sessionSelector?: (o: { cwd: string; onSelect: (session: Resumable) => void; onCancel: () => void; requestRender: () => void; /** A session a live job runs (not to be deleted from the list). */ busy: (path: string) => boolean; }) => Overlay; /** M23: what new sessions run when no model is chosen ("provider/id"). */ defaultModel?: () => string | undefined; /** M23: this pi's own session file (it cannot be resumed in the background). */ currentSession?: () => string | undefined; /** M23: the models pi cycles through (`enabledModels`); none: all of them. */ scopedModels?: () => string[]; setTitle: (title: string) => void; /** Daemon connection; tests pass a fake. */ connect?: () => Promise; /** AV-K6: initial grouping and where a change is persisted. */ groupBy?: "state" | "directory"; onGroupBy?: (groupBy: "state" | "directory") => void; /** NT-1: a job needs input or finished while the view is on screen. */ notify?: (row: JobRow, kind: "needs_input" | "completed") => void; /** AV-9: a row to keep bold (the conversation just moved to the background). */ highlightId?: string; /** BG-5: Esc goes back into this job (the conversation that just moved) instead of leaving. */ origin?: string; /** Shown above the list until the user returns to the origin. */ banner?: string; /** Screen-reader mode: no animation (PRD accessibility). */ reducedMotion?: boolean; /** Render exactly the terminal's height: list at the top, input and keys at the bottom. */ fullscreen?: boolean; /** M8: show each row's model and context window use (default true). */ rowDetails?: boolean; /** M13: subagents a session spawns are not rows (Claude Code), or are (inline). */ subagents?: "hide" | "inline"; /** M8: how long a /model or /thinking switch may take to show (tests shorten it). */ switchCheckMs?: number; /** M27: the presets (user's and project's) and saving one to the user's file (null removes). */ presets?: () => Record; savePreset?: (name: string, preset: Preset | null) => void; /** M27: whether the user's own file has this preset (a project's cannot be removed here). */ userPreset?: (name: string) => boolean; /** M26: what a session changed in its worktree (tests may replace git). */ worktreeChange?: (path: string, base: string) => Promise; /** M44: the launch of the concierge's pi session (its model and thinking level from roost.json). */ conciergeLaunch?: () => LaunchRequest; done: () => void; } /** A dispatch request, plus (M10) how to undo its worktree and what to tell the user. */ export type LaunchRequest = DispatchArgs & { discard?: () => void; note?: string; }; export interface LaunchOptions { cwd?: string; model?: string; thinking?: string; /** M10: in its own git worktree (undefined: the user's default). */ worktree?: boolean; /** /resume: run this existing session instead of a new one. */ sessionFile?: string; name?: string; origin?: "dispatch" | "adopt"; /** M18: run as this agent. */ agent?: AgentDef; /** M26: one of a fan-out: a worktree when the directory is a repository, else none (no error). */ fanout?: string; } export interface Resumable { path: string; name: string; cwd: string; modified: number; } /** M23: a component shown in place of the list (pi's session selector), with its keys. */ export interface Overlay { render(width: number): string[]; handleInput?(data: string): void; focused?: boolean; dispose?(): void; } /** The agent view (PRD §6.1–6.5) as one focused pi-tui component. */ export declare class AgentView implements Component { private o; private client; /** DM-7: a failed or stopped session restarts on a second Enter. */ private restartAsk; private rows; private collapsed; private cursor; private peek; private help; /** M17: pi's editor: several lines (Shift+Enter), long pastes folded. */ private input; /** M48: the reply box is an editor like the task box (lines, pastes, undo, completion). */ private reply; /** AV-K10: the row being renamed, edited in its own input. */ private renaming; private renameInput; private groupBy; /** DI-4: defaults for the next dispatches. */ private model; private thinking; /** M10: /worktree for the next dispatches (undefined: the user's default). */ private worktree; private picker; private overlay; private notice; private armedStop; private ctrlCAt; private frame; private spinner; private resync; private attached; private closed; private connectError; /** M44: the concierge as the daemon last said; asking: a `? …` whose answer is awaited (two minutes at most). */ private concierge; private asking; private askTimer; /** An answer that came while another overlay was open: shown once it closes. */ private pendingAnswer; /** M45: suggestions the user dismissed (Esc), by row and time: the banner skips them. */ private dismissed; /** M47: the task board's counts, as the daemon last said (the header line; /tasks fetches the tasks). */ private board; private nameWidth; /** M8: the model / context column, the same for every row of a render so it lines up. */ private columns; /** M8: switches sent to live sessions, until their reports show them (or do not). */ private switches; /** M25: rows checked with Ctrl+O; the batch keys act on all of them. */ private marked; private sendingMarked; /** M26: the next task starts one session per model. */ private fanout; /** M27: the preset in use: its name, and what the view has no setting of its own for. */ private preset; /** M30: new sessions run this profile's agent instead of pi. */ private profile; private dispatching; /** The job a reply is typed for; replies never retarget to another row. */ private peekId; private origin; /** Esc/Enter came before the moved conversation's worker was up: attach once it is. */ private attachWhenLive; constructor(o: AgentViewOptions); start(): Promise; dispose(): void; private connect; /** * M22: the rows, and the events that came after the reply: those are newer than it, * though handled before the code after the await runs. */ private listFrom; /** M22: a row event over a fresh list (no notifications: it was seen already). */ private applyRow; /** M22: the daemon's rows as they are now (the stream after the reply carries on from them). */ private resyncRows; private onEvent; private render0; /** M13: the rows the view lists (subagents live in their session's panel). */ private listedRows; private sections; /** DI-7: the input holds filters (s: n: o:) rather than a task. */ private filter; private itemList; private selectedIndex; private selected; private selectedRow; private move; private say; handleInput(data: string): void; private moveAndRender; private togglePeek; private closePeek; /** AV-K15: close peek → clear input → exit. */ private escape; /** AV-K16: clear input; twice to exit. */ private ctrlC; private enter; /** Ctrl+G: write the task in $VISUAL / $EDITOR (P2 row "Ctrl+G external editor"). */ private editExternally; /** Returns true when the command was handled here (and the input consumed). */ /** M18: not a skill or prompt template (those can be an agent's first prompt). */ private isViewCommand; private command; /** M30: the agent new sessions run (pi unless a profile is chosen). */ private setProfile; private openPicker; /** * M23: models to choose from, searchable; the enabled ones (`enabledModels`, what pi * cycles through) first when there are some, Tab for all of them. */ private modelPicker; /** M23: the model for new sessions (/model, Ctrl+L). */ private newModelPicker; /** M23: Ctrl+P / Shift+Ctrl+P: the next or previous enabled model for new sessions, as in pi. */ private cycleModel; /** M23: Shift+Tab: the next thinking level for new sessions, as in pi. */ private cycleThinking; /** M23 /resume: pi's own session list when there is one, else the view's. */ private resume; /** * M39 /schedule: ` ` adds one (a pi session with the view's model, * thinking and directory); `list` (or bare), `run`, `pause`, `resume`, `rm `. */ private scheduleCommand; /** M39 /schedule list: each schedule, when it runs next, its last run; Esc closes. */ private showSchedules; /** M24 /usage: what the sessions spent, by model and by session; Esc closes, ↑↓ scroll. */ private showUsage; /** M43 /log: what happened lately across the sessions (newest first); r reloads, Esc closes. */ private showLog; /** M44 /concierge on|off|status|log|attach|ask …: the hub's resident agent. */ private conciergeCommand; /** M44: the status line under the header. */ private conciergeLine; /** M45: the row the banner is about: the selected one if it waits with a suggestion, else the longest waiting. */ private escalation; private escalationLine; /** Ctrl+Y: the suggestion goes as the user's reply. */ private acceptSuggestion; /** Ctrl+E: the suggestion in the reply box of that row's peek, to edit before sending. */ private editSuggestion; /** M46: the standing orders, newest first. */ private showOrders; /** M44: `? …`: a question to the concierge; its answer opens in an overlay. */ private ask; /** A question is awaited, or not (an answer came; it went off; two minutes passed). */ private asked; private showAnswer; private usageLines; private closeOverlay; /** * M23: into a past session at once: its row when it has one (started again if it * ended), else a new background job on it, attached as soon as it runs. */ private resumeSession; private pickerKey; /** DI-4 /resume: a past session of this directory without a row becomes a job. */ private resumePicker; /** DI-3: Tab completes the @dir being typed. */ private completeAt; private atCache; /** Cached briefly: render runs on every key and tick, and this reads directories. */ private atSuggestions; private toggleGroupBy; private togglePin; private startRename; private endRename; private renameKey; private jumpHeader; private reorder; private attachNth; /** Where a dispatch goes: the selected directory section when grouping by directory. */ private dispatchCwd; private dispatch; /** M28: Enter steers into the work under way (pi's Enter); Alt+Enter waits for it (pi's Alt+Enter). */ private sendReply; /** * M47: `/tasks`: the shared task board. Bare: the board. `add [after #n …] [-- detail]`, * `assign <id> <session>`, `done <id> [result]`, `rm <id>`, `release <id>`. */ private tasksCommand; /** M47: the board as an overlay: open (claimable), blocked, claimed, then done, newest first. */ private showTasks; /** M48: a `/command` typed in a peek acts on that session (the keys' code, by name). */ private peekCommand; /** M48 /transcript in a peek: its transcript (a terminal agent: its screen), the end first in view; r reloads. */ private showTranscript; /** M48: pi's own completion (pi-tui) for a box: `/` its commands, `@` paths under its directory (fuzzy with fd). */ private completion; /** The task box's commands: the view's, then pi's prompt templates and skills (an agent's first prompt). */ private viewCommands; /** A peek's commands: for that session. */ private peekCommands; /** M8: switch a session's model or thinking level from its peek. */ private sessionSetting; private sendSetting; /** One watch per session and setting: a /thinking does not cancel the check of a /model. */ private watchSwitch; /** A report shows a switch (or pi's adjusted thinking level). */ private checkSwitch; /** * M27: the preset's directory, under the hub's (links resolved: a cloned project's * preset cannot reach outside it), when it has one. */ private presetDir; /** M27: /preset [name | off | save name | rm name]; false: the text stays in the input. */ private presetCommand; private applyPreset; private clearPreset; /** M26: bare /fanout: Enter adds or removes a model, the list opens again until Esc. */ private fanoutPicker; private dispatchFanout; /** M26: the sessions to compare: the selected row's fan-out, else the marked rows. */ private compareRows; /** M26: /compare: one column per session, ← → choose, Enter opens it, k twice keeps it. */ private compare; private compareLines; /** M26: keep one of a comparison: the others are deleted (worktrees with work are kept). */ private keepOne; /** * M25: the marked rows on screen, in list order. A marked row in a folded group or * filtered out stays marked but is not acted on: a batch never reaches what is not shown. */ private markedRows; /** M25: Ctrl+O marks the row, or on a header the whole group (again: unmarks it). */ private toggleMark; /** M25: the typed text to every marked session; /model and /thinking switch them all. */ private sendToMarked; private markedSetting; /** AV-K12: stop; again within 2 s delete; on a header, the whole group. */ private stopSelected; private attachSelected; /** AT-1/AT-2: hand the terminal to the job's PTY host, then repaint. */ private attachTo; invalidate(): void; render(width: number): string[]; /** * In render: the selected row's first and last line (with its peek and reply input), * the first line of the bottom block (input, keys), and the fixed lines on top. */ private selLine; private selEnd; private bottomFrom; private headLines; private renderLines; private mark; private rowLine; /** * M8: how much of the model / context column fits. The summary keeps MIN_SUMMARY * columns: on a narrow terminal the column shrinks to the share, then goes. */ private columnsFor; private layoutColumns; /** M8: "claude-opus-5-5 · 43%", padded to the column (blank for a row without them). */ private detailText; /** PK-1: the full sentence, choices, waiting time, and the reply input. */ private peekLines; /** * M48: the tail of its transcript (or its screen): raw lines cached per row, the file looked at * (its size and mtime) every 2 s at most and read only when it changed; cut to the width at render. */ private tails; private tailLines; private footer; /** `room`: the lines left under the header. */ private pickerLines; /** `room`: the lines left under the header; two columns when one does not fit. */ private helpLines; } export declare function presetText(p: Preset): string; /** M26: a fan-out's rows say their model (pi names each session on its own, often alike). */ export declare function rowName(row: JobRow): string; /** * Full screen: exactly `rows` lines. The bottom block (input, notices, keys) is pinned * to the last lines; the first `keep` lines (title, rule) stay; the rest scrolls so the * selection — `selected` to `selectedEnd`, a row with its peek — is visible, its end * (the reply input) first. Lines from `bottom` on are the bottom block (-1: none). */ export declare function fitScreen(lines: string[], rows: number, selected: number, bottom: number, opts?: { selectedEnd?: number; keep?: number; }): string[];