import type { KeybindingsManager, Theme } from "@earendil-works/pi-coding-agent"; import type { Component, Focusable, TUI, TuiMouseEvent, TuiMouseEventResult } from "@earendil-works/pi-tui"; import { type FabricConversationTranscriptRendererOptions } from "./conversation-render.js"; import { type FabricConversationAppearance } from "./conversation-chrome.js"; import type { AgentUsage } from "../agents/types.js"; import type { CodePreviewSettings } from "./code-preview.js"; import type { NativeConversationTranscript } from "./conversation-native-reader.js"; import { ConversationQueueStore } from "./conversation-queue-store.js"; export type FabricConversationDelivery = "steer" | "followUp"; export interface FabricConversationTarget { id: string; name: string; kind: "main" | "peer" | "agent" | "actor"; parentId?: string; status: string; runner?: string; model?: string; thinking?: string; cwd?: string; branch?: string; usage?: AgentUsage; contextWindow?: number; canSteer: boolean; canFollowUp: boolean; canStop: boolean; readOnlyReason?: string; stale?: boolean; /** Latest activity timestamp; enables an unread marker in the target picker. */ updatedAt?: number; } export interface FabricConversationStateEntry { draft: string; following: boolean; scroll: number; pageAnchor: "start" | "end" | "prepend" | undefined; anchorLength?: number | undefined; toolsExpanded: boolean; hideThinking?: boolean; lastSeenUpdatedAt: number; /** Session-local composer history, oldest first; lazily seeded, like Pi. */ promptHistory?: string[]; } /** Session-owned in-flight send; survives view close/reopen, cleared on clear(). */ export interface FabricConversationPendingSend { id: string; message: string; delivery: FabricConversationDelivery; } /** * Per-target view state owned by the parent controller. Created once and * reused across overlay opens so drafts, scroll/following, and the selected * target survive close/reopen; clear() on session shutdown (and bumps epoch * so in-flight sends from a previous session never mutate new state). */ export declare class FabricConversationState { readonly queues: ConversationQueueStore; selectedId: string | undefined; private epochCounter; private readonly entries; private readonly pendingSends; get epoch(): number; hasPendingSend(id: string, message: string): boolean; addPendingSend(pending: FabricConversationPendingSend): void; /** Acknowledged: drop the pending marker and clear only the exact accepted draft. */ resolvePendingSend(id: string, message: string): void; /** Rejected: drop the pending marker; the raw draft stays untouched. */ failPendingSend(id: string, message: string): void; /** Live view state for a target; creates (and may evict empty) entries. */ view(id: string): FabricConversationStateEntry; /** Non-mutating lookup; unread checks must never create or evict drafts. */ peek(id: string): FabricConversationStateEntry | undefined; clear(): void; private enforceLimit; } export interface FabricConversationOptions { targets: () => FabricConversationTarget[]; initialTargetId?: string; state: FabricConversationState; transcript: (id: string, followLatest: boolean) => NativeConversationTranscript; loadOlder: (id: string) => boolean; loadNewer: (id: string) => boolean; loadLatest: (id: string) => boolean; send: (id: string, message: string, delivery: FabricConversationDelivery) => Promise; stop: (id: string) => Promise; close: () => void; copyToClipboard?: (text: string) => Promise; onTargetChange?: (id: string) => void; keybindings?: Pick; codePreviewSettings?: CodePreviewSettings; appearance?: FabricConversationAppearance; rendererOptions?: FabricConversationTranscriptRendererOptions | undefined; queueEvents?: { emit(channel: string, data: unknown): void; } | undefined; } export declare class FabricConversationView implements Component, Focusable { private focusState; private readonly tui; private readonly theme; private readonly options; private readonly state; private readonly renderer; private editor; private suspendedEditor; private editorEpoch; private pickerInput; private pickerRows; private pickerSelectedId; private mode; private currentId; private feedback; private commandNotification; private notificationScope; private stopConfirmId; private disposed; private lastBodyLength; private lastBody; private lastBodyBudget; private editorTop; private editorHeight; private ownsMouseMode; private targets; private targetsKey; private readonly targetsById; private nonMain; private main; private observationKey; private observedTranscript; private pickerKey; private working; private workingTargetId; private readonly textSelection; private selectionWidth; private selectionWasFollowing; private bodyTop; private bodyHeight; private copyVersion; private copyTask; constructor(tui: TUI, theme: Theme, options: FabricConversationOptions); private createEditor; private releaseEditor; private resetEditor; private ensureEditorEpoch; private initializePromptHistory; private rememberPrompt; private setQueueEditorText; get focused(): boolean; set focused(value: boolean); /** Re-focus a target while the view is open; selecting Main closes to the native session. */ selectTarget(id: string): void; handleInput(data: string): void; handleMouse(event: TuiMouseEvent): TuiMouseEventResult | undefined; render(width: number): string[]; /** Observe files without rendering native history; true means a visible change * or a live animation still needs the normal TUI render path. */ refresh(): boolean; private observe; private selectedTargetIsWorking; private syncWorkingIndicator; private stopWorkingIndicator; invalidate(): void; dispose(): void; /** Keep the editor in sync with the shared session draft (e.g. after an ack * that landed while a previous view instance was disposed). */ private reconcileEditor; private applySelection; private markCurrentTargetSeen; private updateTargets; private currentTargets; private nonMainTargets; private currentTarget; private mainTarget; private targetById; private terminalRows; /** * Respects a configured binding; when an injected manager reports no keys * the binding is unbound (never falls back), and only the default global * manager (no injection) falls back to hard-coded keys. */ private bindingMatches; private bindingHint; private handleConversationInput; private clearCommandNotification; private notifyCommand; private copyFeedback; private copySelection; private copyResponse; private copyText; private submit; private dispatchStop; private navigateParent; private navigateFirstChild; private cycleTarget; private scrollBy; private scrollPrompt; private scrollToTop; private followLatest; private openPicker; private closePicker; private refreshPicker; private pickerSelectedIndex; private movePickerSelection; private pickSelected; private handlePickerInput; private isUnread; private breadcrumbLine; private currentFeedbackLine; private hintsLine; private renderEditorLines; private currentQueue; private transcriptLines; private transcriptTail; private windowBody; private pickerLines; } //# sourceMappingURL=conversation.d.ts.map