import type { Component, TUI } from "@oh-my-pi/pi-tui"; import { KeybindingsManager } from "@oh-my-pi/pi-tui/app-keybindings"; import type { ExtensionApprovalAnswer, ExtensionApprovalPrompt, ExtensionAskDialogQuestion, ExtensionAskDialogResult, ExtensionCustomOptions, ExtensionFormDialogResult, ExtensionUIContext, ExtensionUIDialogOptions, ExtensionUISelectItem, ExtensionWidgetContent, ExtensionWidgetOptions, TerminalInputHandler } from "../../extensibility/extensions/index.js"; import { type HookSelectorSlider } from "@oh-my-pi/pi-tui/overlays/hook-selector"; import { type Theme } from "@oh-my-pi/pi-tui/theme"; import type { InteractiveModeContext, InteractiveSelectorDialogOptions } from "../../modes/types.js"; export declare class ExtensionUiController { #private; private ctx; constructor(ctx: InteractiveModeContext); /** Remove extension-owned composer styles from the process registries. */ disposeComposerShapes(): void; /** * Initialize the hook system with TUI-based UI context. */ initHooksAndCustomTools(): Promise; /** * The `ExtensionUIContext` built in `initHooksAndCustomTools()` — the same * picker/dialog primitives passed as `context.ui` for every live tool * call. `/tree` `ask` re-answer (issue #5642) reuses this to drive a * standalone `AskTool.execute()` call outside a normal agent turn. * `undefined` before hooks have initialized. */ getToolUIContext(): ExtensionUIContext | undefined; setHookWidget(key: string, content: ExtensionWidgetContent, options?: ExtensionWidgetOptions): void; initializeHookRunner(uiContext: ExtensionUIContext, _hasUI: boolean): void; /** * Emit session event to all extension tools. */ emitCustomToolSessionEvent(reason: "start" | "switch" | "branch" | "tree" | "shutdown", previousSessionFile?: string): Promise; /** * Show a tool error in the chat. */ showToolError(toolName: string, error: string): void; /** * Set hook status text in the footer. */ setHookStatus(key: string, text: string | undefined): void; showCollabAwareSelector(title: string, options: ExtensionUISelectItem[], dialogOptions?: InteractiveSelectorDialogOptions, extra?: { slider?: HookSelectorSlider; }): Promise; showCollabAwareEditor(title: string, prefill?: string, dialogOptions?: ExtensionUIDialogOptions, editorOptions?: { promptStyle?: boolean; }): Promise; /** * The tool-approval prompt in the composer's place; a collab guest answers it as a select over * the full prompt with the same choices ({@link approvalChoiceLabels}): the prompt's grants when * it offers any, Approve, its "for this session" choice when it offers one, and Deny. Locally it * shows the compact prompt (the details summarized to a * row, so the composer beneath keeps its room) over that list, and the expand key * swaps in the full one, wrapped — even when the two match, since a row the summary kept whole * can still clip. The composer stays mounted beneath it and takes the typing: a user message * queued as steering while the call waits (sent here, from Tern, or by a collab guest) denies * the call, so the message tells the agent why instead of a bare denial. The watch starts with * the request, so approvals still queued behind another dialog are denied by the same message. */ showCollabAwareApproval(prompt: ExtensionApprovalPrompt, dialogOptions?: ExtensionUIDialogOptions): Promise; showAskDialog(questions: ExtensionAskDialogQuestion[], dialogOptions?: ExtensionUIDialogOptions): Promise; /** * An agent-written HTML form in the composer's place ({@link HtmlFormDialog}). A collab * guest answers it field by field — a select per choice group, an editor per text field — * and the first side to finish wins, as {@link showAskDialog}. */ showFormDialog(html: string, dialogOptions?: ExtensionUIDialogOptions): Promise; /** * Show a selector for hooks. */ showHookSelector(title: string, options: ExtensionUISelectItem[], dialogOptions?: InteractiveSelectorDialogOptions, extra?: { slider?: HookSelectorSlider; }): Promise; /** * Hide the hook selector. */ hideHookSelector(): void; /** * Show a confirmation dialog for hooks. */ showHookConfirm(title: string, message: string, dialogOptions?: InteractiveSelectorDialogOptions): Promise; /** * Show a text input for hooks. */ showHookInput(title: string, placeholder?: string, dialogOptions?: ExtensionUIDialogOptions): Promise; /** * Hide the hook input. */ hideHookInput(): void; /** * Show a multi-line editor for hooks (with Ctrl+G support). */ showHookEditor(title: string, prefill?: string, dialogOptions?: ExtensionUIDialogOptions, editorOptions?: { promptStyle?: boolean; }): Promise; /** * Hide the hook editor. */ hideHookEditor(): void; /** * Show a notification for hooks. */ showHookNotify(message: string, type?: "info" | "warning" | "error"): void; /** * Show a custom component with keyboard focus. */ showHookCustom(factory: (tui: TUI, theme: Theme, keybindings: KeybindingsManager, done: (result: T) => void) => (Component & { dispose?(): void; }) | Promise, options?: ExtensionCustomOptions): Promise; /** * Show an extension error in the UI. */ addExtensionTerminalInputListener(handler: TerminalInputHandler): () => void; clearHookWidgets(): void; clearExtensionTerminalInputListeners(): void; showExtensionError(extensionPath: string, error: string): void; }