/** * Shared state and constructor wiring for interactive mode. * Responsibility-specific behavior is installed by sibling modules. */ import { type ScrollView, type TuiInputListener, type WheelScrollLines } from "@earendil-works/pi-tui"; import type { AgentSessionQueuePauseControl } from "../../core/agent-session-methods.ts"; import type { MarkdownTransformer } from "../../core/extensions/types.ts"; import type { FullscreenExitOutput, MermaidRenderingMode } from "../../core/settings-manager.ts"; import type { EarlyInputSnapshot } from "../../main-early-input.ts"; import type { RemoteToolExecutionComponent } from "../interactive-engine/remote-renderer.ts"; import { KeybindingsReloadCoordinator } from "../rpc/rpc-keybindings-reload.ts"; import type { AtomicWorkingLoader } from "./components/atomic-working-status.ts"; import type { TranscriptOverlayReserve } from "./components/reserved-bottom-overlay.ts"; import { type AgentSession, type AgentSessionRuntime, type AssistantMessage, type AssistantMessageComponent, type AutocompleteProvider, type AutocompleteProviderFactory, type BashExecutionComponent, type Component, Container, type CountdownTimer, CustomEditor, type EditorComponent, type EditorFactory, FooterComponent, FooterDataProvider, type HostCustomUiStateListener, InteractiveThemeController, KeybindingsManager, type Loader, type LoaderIndicatorOptions, type Spacer, type Text, type ToolExecutionComponent, type TUI, UsageMeterComponent } from "./interactive-mode-deps.ts"; import "./interactive-mode-surface.ts"; import type { CompactionQueuedMessage, ExtensionDialogComponent, InteractiveModeOptions } from "./interactive-mode-types.ts"; import type { InteractiveSubmission } from "./interactive-submission.ts"; import { type BlockedStatus, ProgramStatusReporter } from "./program-status-reporter.ts"; export declare function isFullscreenViewportAction(data: string, keybindings: KeybindingsManager): boolean; /** * Whether a key scrolls the transcript. A reserving overlay — the * `ask_user_question` dialog, an extension component with * `reserveTranscriptRows` — declines these so the strip above it still pages * and jumps (#2378), and keeps everything else. */ export declare function isFullscreenTranscriptScrollAction(data: string, keybindings: KeybindingsManager): boolean; /** * Decide whether the fullscreen viewport should run before the focused * component. `isMouseInput` is classified by pi-tui's own mouse predicate in * `AtomicTuiAltScreen`, so this policy does not duplicate terminal grammars. * Mouse deferral is limited to actual overlays so inline components do not * disable pi-tui's application-owned transcript selection path. * * **Who owns viewport keys while an overlay is focused.** pi-tui 0.84.2 added * `shouldDeferViewportInputToOverlay()` (upstream #7894) and answers "the * overlay". Atomic answers "the overlay first, the transcript with whatever it * declines" (#2378 / PR #2381): the actions in `FULLSCREEN_VIEWPORT_ACTIONS` * and wheel reports are offered to the focused overlay, and * `AtomicTuiAltScreen` replays what it does not consume into pi-tui's viewport * listener. Atomic's answer stands, because a mounted dialog that keeps its * selection keys must not also freeze the transcript behind it. * * **The list covers every `tui.altScreen.*` scroll action pi-tui defines.** * An action a focused overlay declines still reaches the transcript, so the * shortcut is never simply lost. * * **A focused overlay with no `handleInput` is still an overlay.** The handler * is optional — `ExtensionCustomComponent` marks it `handleInput?` and * `docs/tui.md` documents it as optional — and a component that cannot answer * declines by definition. Answering "the viewport owns it" for that shape * would hand the key to pi-tui, whose native deferral then drops it because an * overlay holds focus, so the transcript would freeze behind a component that * never asked for the key. A handler-less overlay therefore takes the same * route as one that returns `false`: nothing to offer, then replay. Only a * focused component that is *not* an overlay keeps the shortcut, because * pi-tui defers nothing to it. */ export declare function shouldHandleFullscreenViewportInput(focused: Component | null, editor: Component, data: string, isMouseInput: boolean, focusedIsOverlay: boolean, keybindings: KeybindingsManager, _focusedIsViewportSearch?: boolean): boolean; export declare function seedStartupInput(pendingUserInputs: InteractiveSubmission[], editor: { setText(text: string): void; }, startupInput: EarlyInputSnapshot | undefined, startupReplayInputs?: string[], setStartupDraftText?: (text: string) => void, setStartupReplayActiveInput?: (text: string) => void): void; export interface InteractiveTuiInputSubscription { handler: TuiInputListener; unsubscribe: () => void; } export declare class InteractiveModeBase { runtimeHost: AgentSessionRuntime; ui: TUI; private renderer; readonly programStatus: ProgramStatusReporter; resetTranscriptSelection(): void; private readonly shouldHandleViewportInput; private readonly onOverlayUnhandledInput; private readonly onOverlayInternalUiAction; /** Dispatch the host thinking action after a focused workflow overlay declines input. */ handleOverlayUnhandledInput(data: string): boolean; setFullscreenWheelScrollLines(lines: WheelScrollLines): void; private readonly onRightClickPaste; chatContainer: Container; documentContainer: Container; transcriptScrollView: ScrollView | undefined; fullscreenLayoutRoot: Component | undefined; resourceDisclosureContainer: Container; startupNoticesContainer: Container; pendingMessagesContainer: Container; statusContainer: Container; defaultEditor: CustomEditor; editor: EditorComponent; editorComponentFactory: EditorFactory | undefined; autocompleteProvider: AutocompleteProvider | undefined; autocompleteProviderWrappers: AutocompleteProviderFactory[]; fdPath: string | undefined; editorContainer: Container; activeSelectorToken: object | undefined; activeSelectorDispose: (() => void) | undefined; footer: FooterComponent; footerContainer: Container; usageMeter: UsageMeterComponent; footerDataProvider: FooterDataProvider; keybindings: KeybindingsManager; reloadCoordinator: KeybindingsReloadCoordinator; interactiveEngineShortcutHandler: ((data: string) => boolean) | undefined; disposeInteractiveEngineHost: () => void; disposeMarkitDiagnosticSink: () => void; version: string; isInitialized: boolean; onInputCallback?: (submission: InteractiveSubmission) => void; pendingUserInputs: InteractiveSubmission[]; startupReplayInputs: string[]; startupReplayActiveInput: string | undefined; startupDraftText: string | undefined; workingIndicatorEmbedded: boolean; deferredRenderedUserInputs: string[]; deferredRenderedUserInputComponents: Map; loadingAnimation: Loader | AtomicWorkingLoader | undefined; workingMessage: string | undefined; workingVisible: boolean; workingIndicatorOptions: LoaderIndicatorOptions | undefined; readonly defaultWorkingMessage = "Working"; readonly defaultHiddenThinkingLabel = "Thinking..."; hiddenThinkingLabel: string; lastSigintTime: number; lastEscapeTime: number; changelogMarkdown: string | undefined; startupNoticesShown: boolean; /** Last model-catalog warning already shown, so the deferred re-read only speaks on a change. */ reportedModelCatalogWarning: string | undefined; startupNoticesPrepared: boolean; anthropicSubscriptionWarningShown: boolean; firstRunNoticeVisible: boolean; hadLastChangelogVersionAtStartup: boolean; firstRunOnboardingNoticeComponents: Component[]; autoTrustOnReloadCwd: string | undefined; lastStatusSpacer: Spacer | undefined; lastStatusText: Text | undefined; /** Leading spacer added once for the managed-tool startup status block. */ managedToolStatusStarted: boolean; /** Invalidates readiness callbacks after the transcript is rebuilt for another session. */ managedToolStatusGeneration: number; streamingComponent: AssistantMessageComponent | undefined; streamingMessage: AssistantMessage | undefined; pendingTools: Map; toolOutputExpanded: boolean; hideThinkingBlock: boolean; outputPad: 0 | 1; mermaidMarkdownTransformer: MarkdownTransformer; mermaidMarkdownTransformerMode: MermaidRenderingMode | undefined; skillCommands: Map; unsubscribe?: () => void; signalCleanupHandlers: Array<() => void>; isBashMode: boolean; bashComponent: BashExecutionComponent | undefined; pendingBashComponents: BashExecutionComponent[]; autoCompactionLoader: AtomicWorkingLoader | undefined; autoCompactionEscapeHandler?: () => void; /** True once the pre-compaction Escape handler has been captured for restore. */ autoCompactionEscapeHandlerSaved: boolean; /** True while `runUserPromptTurn()` owns the working loader. */ promptTurnWorkingLoaderActive: boolean; promptTurn: { dispatched: boolean; } | undefined; retryLoader: AtomicWorkingLoader | undefined; fallbackLoader: Loader | undefined; retryCountdown: CountdownTimer | undefined; retryEscapeHandler?: () => void; compactionQueuedMessages: CompactionQueuedMessage[]; /** True while queued compaction messages are being sent one at a time. */ compactionFlushPending: boolean; /** A queued message failed to send and waits at the front of the queue; later input queues behind it. */ compactionSendFailed: boolean; /** Keeps input queued while automatic compaction hands off to a manual request. */ manualCompactionTakeoverPending: boolean; deferredStartupPending: boolean; initialStartupBinding: boolean; deferredStartupPromise: Promise | undefined; startupTrustReleased: boolean; inputHandlerReadyRecorded: boolean; firstSubmitRecorded: boolean; shutdownRequested: boolean; extensionDialogs: Array<{ component: ExtensionDialogComponent; blocked: BlockedStatus | undefined; }>; tuiInputSubscriptions: Set; extensionTerminalInputSubscriptions: Set; tuiRendererChangeListeners: Set<() => void>; blockingInlineCustomUiDepth: number; navigationInlineCustomUiDepth: number; deferredInlineCustomUiFocusDepth: number; pendingInlineCustomUiFocus: Component | undefined; hostCustomUiStateListeners: Set; widgetReleaseListeners: Map void>>; transcriptOverlayReserve: TranscriptOverlayReserve | undefined; themeController: InteractiveThemeController; extensionWidgetsAbove: Map; extensionWidgetsBelow: Map; widgetContainerAbove: Container; widgetContainerBelow: Container; customFooter: (Component & { dispose?(): void; }) | undefined; headerContainer: Container; builtInHeader: Component | undefined; customHeader: (Component & { dispose?(): void; }) | undefined; get session(): AgentSession & AgentSessionQueuePauseControl; /** Includes the short handoff window that an isolated engine cannot mirror. */ get compactionActive(): boolean; get agent(): import("@earendil-works/pi-agent-core").Agent; get sessionManager(): import("./interactive-mode-deps.ts").SessionManager; get settingsManager(): import("../../core/settings-manager-core.ts").SettingsManager; /** * Tears down the selector that owns `editorContainer`, including in-flight * work such as a model catalog refresh. * * This lives on the base class so behavior modules can dispose a selector * without relying on `interactive-selectors.ts` load order. */ disposeActiveSelector(): void; /** * Show an extension dialog in the editor slot. * Dialogs form a stack: a new dialog hides the visible one, and closing the visible dialog shows * the previous one again. Every dialog stays answerable, so no dialog promise is left pending, * and dialogs opened from inside another dialog (for example a confirm from a custom component) work. */ pushExtensionDialog(component: ExtensionDialogComponent, blocked?: BlockedStatus, focus?: boolean): void; /** Remove an extension dialog. If it was visible, show the previous dialog or the editor. */ removeExtensionDialog(component: ExtensionDialogComponent, focus?: boolean): void; showTopExtensionDialog(focus?: boolean): void; addTuiInputListener(handler: TuiInputListener): () => void; rebindTuiInputListeners(): void; onTuiRendererChange(listener: () => void): () => void; mountInteractiveTui(tui: TUI, components: readonly Component[]): void; private handleRightClickPaste; stopInteractiveTui(fullscreenExitOutput: FullscreenExitOutput): void; options: InteractiveModeOptions; setEditorWorkingStatusIndicator(indicator: AtomicWorkingLoader | undefined): boolean; constructor(runtimeHost: AgentSessionRuntime, options?: InteractiveModeOptions); static readonly MAX_WIDGET_LINES = 10; /** * Gracefully shutdown the agent. * Stops the TUI before emitting shutdown events so extension UI cleanup cannot * repaint the final frame while the process is exiting. */ isShuttingDown: boolean; installChangeWarningShown: boolean; } //# sourceMappingURL=interactive-mode-base.d.ts.map