import type { AgentMessage } from "@oh-my-pi/pi-agent-core"; import type { CompactionOutcome } from "@oh-my-pi/pi-agent-core/compaction"; import type { AssistantMessage, ImageContent, Message, UsageReport } from "@oh-my-pi/pi-ai"; import type { Component, Container, EditorTheme, Loader, Spacer, Text, TUI } from "@oh-my-pi/pi-tui"; import type { KeybindingsManager } from "../config/keybindings"; import type { Settings } from "../config/settings"; import type { ExtensionUIContext, ExtensionUIDialogOptions, ExtensionWidgetContent, ExtensionWidgetOptions, } from "../extensibility/extensions"; import type { CompactOptions } from "../extensibility/extensions/types"; import type { MCPManager } from "../mcp"; import type { PlanApprovalDetails } from "../plan-mode/approved-plan"; import type { AgentSession, AgentSessionEvent } from "../session/agent-session"; import type { HistoryStorage } from "../session/history-storage"; import type { SessionContext, SessionManager } from "../session/session-manager"; import type { LspStartupServerInfo } from "../tools"; import type { AssistantMessageComponent } from "./components/assistant-message"; import type { BashExecutionComponent } from "./components/bash-execution"; import type { CustomEditor } from "./components/custom-editor"; import type { EvalExecutionComponent } from "./components/eval-execution"; import type { HookEditorComponent } from "./components/hook-editor"; import type { HookInputComponent } from "./components/hook-input"; import type { HookSelectorComponent } from "./components/hook-selector"; import type { StatusLineComponent } from "./components/status-line"; import type { ToolExecutionHandle } from "./components/tool-execution"; import type { LoopLimitRuntime } from "./loop-limit"; import type { OAuthManualInputManager } from "./oauth-manual-input"; import type { Theme } from "./theme/theme"; export type CompactionQueuedMessage = { text: string; mode: "steer" | "followUp"; }; export type SubmittedUserInput = { text: string; images?: ImageContent[]; customType?: string; display?: boolean; cancelled: boolean; started: boolean; }; export type TodoStatus = "pending" | "in_progress" | "completed" | "abandoned"; export type TodoItem = { content: string; status: TodoStatus; details?: string; notes?: string[]; }; export type TodoPhase = { name: string; tasks: TodoItem[]; }; export interface InteractiveModeContext { // UI access ui: TUI; chatContainer: Container; pendingMessagesContainer: Container; statusContainer: Container; todoContainer: Container; btwContainer: Container; editor: CustomEditor; editorContainer: Container; hookWidgetContainerAbove: Container; hookWidgetContainerBelow: Container; statusLine: StatusLineComponent; // Session access session: AgentSession; sessionManager: SessionManager; settings: Settings; keybindings: KeybindingsManager; agent: AgentSession["agent"]; historyStorage?: HistoryStorage; mcpManager?: MCPManager; lspServers?: LspStartupServerInfo[]; // State isInitialized: boolean; isBackgrounded: boolean; isBashMode: boolean; toolOutputExpanded: boolean; todoExpanded: boolean; planModeEnabled: boolean; goalModeEnabled: boolean; goalModePaused: boolean; loopModeEnabled: boolean; loopPrompt?: string; loopLimit?: LoopLimitRuntime; planModePlanFilePath?: string; hideThinkingBlock: boolean; pendingImages: ImageContent[]; compactionQueuedMessages: CompactionQueuedMessage[]; pendingTools: Map; pendingBashComponents: BashExecutionComponent[]; bashComponent: BashExecutionComponent | undefined; pendingPythonComponents: EvalExecutionComponent[]; pythonComponent: EvalExecutionComponent | undefined; isPythonMode: boolean; streamingComponent: AssistantMessageComponent | undefined; streamingMessage: AssistantMessage | undefined; loadingAnimation: Loader | undefined; autoCompactionLoader: Loader | undefined; retryLoader: Loader | undefined; autoCompactionEscapeHandler?: () => void; retryEscapeHandler?: () => void; unsubscribe?: () => void; onInputCallback?: (input: SubmittedUserInput) => void; optimisticUserMessageSignature: string | undefined; locallySubmittedUserSignatures: Set; lastSigintTime: number; lastEscapeTime: number; shutdownRequested: boolean; hookSelector: HookSelectorComponent | undefined; hookInput: HookInputComponent | undefined; hookEditor: HookEditorComponent | undefined; lastStatusSpacer: Spacer | undefined; lastStatusText: Text | undefined; fileSlashCommands: Set; skillCommands: Map; oauthManualInput: OAuthManualInputManager; todoPhases: TodoPhase[]; // Lifecycle init(): Promise; shutdown(): Promise; checkShutdownRequested(): Promise; // Extension UI integration setToolUIContext(uiContext: ExtensionUIContext, hasUI: boolean): void; initializeHookRunner(uiContext: ExtensionUIContext, hasUI: boolean): void; createBackgroundUiContext(): ExtensionUIContext; setEditorComponent( factory: ((tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager) => CustomEditor) | undefined, ): void; // Event handling handleBackgroundEvent(event: AgentSessionEvent): Promise; // UI helpers showStatus(message: string, options?: { dim?: boolean }): void; showError(message: string): void; showWarning(message: string): void; showNewVersionNotification(newVersion: string): void; clearEditor(): void; updatePendingMessagesDisplay(): void; queueCompactionMessage(text: string, mode: "steer" | "followUp"): void; flushCompactionQueue(options?: { willRetry?: boolean }): Promise; flushPendingBashComponents(): void; flushPendingModelSwitch(): Promise; setWorkingMessage(message?: string): void; applyPendingWorkingMessage(): void; ensureLoadingAnimation(): void; startPendingSubmission(input: { text: string; images?: ImageContent[]; customType?: string; display?: boolean; }): SubmittedUserInput; cancelPendingSubmission(): boolean; markPendingSubmissionStarted(input: SubmittedUserInput): boolean; finishPendingSubmission(input: SubmittedUserInput): void; /** * Marks a locally-initiated user submission so the eventual `message_start` * event for that user message does not clobber the editor draft (see #783). * Returns a dispose function that removes the signature; call it on * delivery failure so a retry can be re-marked cleanly. */ recordLocalSubmission(text: string, imageCount?: number): () => void; /** * Wraps `fn` in a `recordLocalSubmission` marker that is automatically * removed if `fn` rejects. Use this for the common case where a thrown * delivery error should leave the signature set untouched. */ withLocalSubmission(text: string, fn: () => Promise, options?: { imageCount?: number }): Promise; isKnownSlashCommand(text: string): boolean; addMessageToChat(message: AgentMessage, options?: { populateHistory?: boolean }): Component[]; renderSessionContext( sessionContext: SessionContext, options?: { updateFooter?: boolean; populateHistory?: boolean }, ): void; renderInitialMessages(prebuiltContext?: SessionContext): void; getUserMessageText(message: Message): string; findLastAssistantMessage(): AssistantMessage | undefined; extractAssistantText(message: AssistantMessage): string; updateEditorTopBorder(): void; updateEditorBorderColor(): void; rebuildChatFromMessages(): void; setTodos(todos: TodoItem[] | TodoPhase[]): void; reloadTodos(): Promise; toggleTodoExpansion(): void; // Command handling handleExportCommand(text: string): Promise; handleShareCommand(): Promise; handleCopyCommand(sub?: string): void; handleTodoCommand(args: string): Promise; handleSessionCommand(): Promise; handleJobsCommand(): Promise; handleUsageCommand(reports?: UsageReport[] | null): Promise; handleChangelogCommand(showFull?: boolean): Promise; handleHotkeysCommand(): void; handleToolsCommand(): void; handleContextCommand(): void; handleDumpCommand(): void; handleDebugTranscriptCommand(): Promise; handleClearCommand(): Promise; handleDropCommand(): Promise; handleForkCommand(): Promise; handleBashCommand(command: string, excludeFromContext?: boolean): Promise; handlePythonCommand(code: string, excludeFromContext?: boolean): Promise; handleMCPCommand(text: string): Promise; handleSSHCommand(text: string): Promise; handleCompactCommand(customInstructions?: string): Promise; handleHandoffCommand(customInstructions?: string): Promise; handleMoveCommand(targetPath: string): Promise; handleRenameCommand(title: string): Promise; handleMemoryCommand(text: string): Promise; handleSTTToggle(): Promise; executeCompaction( customInstructionsOrOptions?: string | CompactOptions, isAuto?: boolean, ): Promise; openInBrowser(urlOrPath: string): void; refreshSlashCommandState(cwd?: string): Promise; // Selector handling showSettingsSelector(): void; showHistorySearch(): void; showExtensionsDashboard(): void; showAgentsDashboard(): void; showModelSelector(options?: { temporaryOnly?: boolean }): void; showPluginSelector(mode?: "install" | "uninstall"): void; showUserMessageSelector(): void; showTreeSelector(): void; showSessionSelector(): void; handleResumeSession(sessionPath: string): Promise; handleSessionDeleteCommand(): Promise; showOAuthSelector(mode: "login" | "logout", providerId?: string): Promise; showHookConfirm(title: string, message: string): Promise; showDebugSelector(): void; showSessionObserver(): void; resetObserverRegistry(): void; // Input handling handleCtrlC(): void; handleCtrlD(): void; handleCtrlZ(): void; handleDequeue(): void; handleBackgroundCommand(): void; handleImagePaste(): Promise; handleBtwCommand(question: string): Promise; hasActiveBtw(): boolean; handleBtwEscape(): boolean; cycleThinkingLevel(): void; cycleRoleModel(options?: { temporary?: boolean }): Promise; toggleToolOutputExpansion(): void; setToolsExpanded(expanded: boolean): void; toggleThinkingBlockVisibility(): void; openExternalEditor(): void; registerExtensionShortcuts(): void; handlePlanModeCommand(initialPrompt?: string): Promise; handleGoalModeCommand(rest?: string): Promise; handleLoopCommand(args?: string): Promise; disableLoopMode(): void; pauseLoop(): void; handlePlanApproval(details: PlanApprovalDetails): Promise; // Hook UI methods initHooksAndCustomTools(): Promise; emitCustomToolSessionEvent( reason: "start" | "switch" | "branch" | "tree" | "shutdown", previousSessionFile?: string, ): Promise; setHookWidget(key: string, content: ExtensionWidgetContent, options?: ExtensionWidgetOptions): void; setHookStatus(key: string, text: string | undefined): void; showHookSelector( title: string, options: string[], dialogOptions?: ExtensionUIDialogOptions, ): Promise; hideHookSelector(): void; showHookInput(title: string, placeholder?: string): Promise; hideHookInput(): void; showHookEditor( title: string, prefill?: string, dialogOptions?: ExtensionUIDialogOptions, editorOptions?: { promptStyle?: boolean }, ): Promise; hideHookEditor(): void; showHookNotify(message: string, type?: "info" | "warning" | "error"): void; showHookCustom( factory: ( tui: TUI, theme: Theme, keybindings: KeybindingsManager, done: (result: T) => void, ) => (Component & { dispose?(): void }) | Promise, options?: { overlay?: boolean }, ): Promise; showExtensionError(extensionPath: string, error: string): void; showToolError(toolName: string, error: string): void; }