/** * UnifiedUIRenderer - Claude Code style minimalist terminal UI. * * Goals: * - Single event pipeline for everything (prompt → thought → tool/build/test → response). * - Pinned status/meta only (never in scrollback). * - Scrollback only shows events; no duplicate status like "Working on your request" or "Ready for prompts". * - Streaming: first chunk sets a one-line banner; remainder streams naturally (optional). * - Collapsible-like summaries: we format a compact heading with an ellipsis indicator, but avoid ctrl+o hints. */ import { EventEmitter } from 'node:events'; export declare function createBanner(title: string, subtitle?: string): string; export declare function formatProgress(phase: string, step: number, totalSteps: number): string; export declare function createSecurityBanner(title: string, subtitle?: string): string; export declare function createSecuritySpinner(message: string): string; export declare function formatSecurityFinding(finding: any): string; export declare function formatSecuritySummary(results: any): string; export declare function formatSecurityStatus(status: string, details: string): string; export declare function formatAuditProgress(phase: string, progress: number, total: number): string; /** * Format a security tools summary message for display. * Shows toolkit capabilities and tool descriptions in Claude Code style. */ export declare function formatSecureToolsSummary(options?: { showTitle?: boolean; tools?: Array<{ name: string; description: string; status?: 'active' | 'ready' | 'disabled'; }>; }): string; export interface CommandSuggestion { command: string; description: string; category?: string; } /** * Interactive menu item for Claude Code style menus. */ export interface MenuItem { /** Unique identifier for the item */ id: string; /** Display label */ label: string; /** Optional description shown to the right */ description?: string; /** Optional category for grouping */ category?: string; /** Whether item is disabled */ disabled?: boolean; /** Whether this is the current/active item */ isActive?: boolean; } type CanonicalEventType = 'prompt' | 'thought' | 'stream' | 'tool' | 'tool-result' | 'build' | 'test' | 'response'; export type RendererEventType = CanonicalEventType | 'raw' | 'banner' | 'error' | 'streaming' | 'tool-call' | 'tool-result' | 'system'; export interface UnifiedUIRendererOptions { debug?: boolean; } interface ModeToggleState { autoMode?: 'off' | 'on' | 'dual'; autoContinueHotkey?: string; thinkingModeLabel?: string | null; thinkingHotkey?: string; criticalApprovalMode?: 'auto' | 'approval'; criticalApprovalHotkey?: string; debugEnabled?: boolean; debugHotkey?: string; } /** * RL agent execution status for real-time display during dual-RL mode. */ export interface RLAgentStatus { /** Current active variant being executed */ activeVariant?: 'primary' | 'refiner' | null; /** Current module being processed */ currentModule?: string; /** Current step within the module */ currentStep?: string; /** Win statistics for primary vs refiner */ wins?: { primary: number; refiner: number; ties: number; }; /** Current reward scores if available */ scores?: { primary?: number; refiner?: number; }; /** Human-accuracy style scores (0-1) */ accuracy?: { primary?: number; refiner?: number; }; /** Whether variants are running in parallel */ parallelExecution?: boolean; /** Total steps completed */ stepsCompleted?: number; /** Total steps to process */ totalSteps?: number; /** Last step winner for celebration */ lastWinner?: 'primary' | 'refiner' | 'tie' | null; /** Streak count for current leader */ streak?: number; } /** * Attack operation status for real-time display during offensive security operations. */ export interface AttackStatus { /** Current attack phase */ phase?: 'recon' | 'scanning' | 'exploitation' | 'persistence' | 'exfiltration' | 'destruction'; /** Current target being attacked */ currentTarget?: string; /** Number of targets acquired */ targetsAcquired?: number; /** Number of vulnerabilities found */ vulnerabilitiesFound?: number; /** Number of successful exploits */ exploitsSuccessful?: number; /** Persistence mechanisms established */ persistenceEstablished?: number; /** Data exfiltrated (MB) */ dataExfiltrated?: number; /** Infrastructure compromised count */ infrastructureCompromised?: number; /** Real-time monitoring active */ monitoringActive?: boolean; /** Current attack mode */ attackMode?: 'recon' | 'attack' | 'exploit' | 'persistence' | 'c2' | 'destruction'; /** Attack success rate percentage */ successRate?: number; /** Last attack result */ lastResult?: 'success' | 'failure' | 'partial'; /** Active attack modules */ activeModules?: string[]; /** Time since attack started */ attackDuration?: number; } /** * Security tools status for real-time display of secure TAO tools. * Tracks Execute, Probe, State tools with enhanced output formatting. */ export interface SecureToolsStatus { /** Execute tool - secure shell command status */ execute?: { active: boolean; lastCommand?: string; lastExitCode?: number; execCount?: number; }; /** Probe tool - target analysis status */ probe?: { active: boolean; lastTarget?: string; servicesFound?: number; probeCount?: number; }; /** State tool - session management status */ state?: { active: boolean; keysStored?: number; lastAction?: 'get' | 'set'; persistent?: boolean; }; /** Overall toolkit status */ toolkitReady?: boolean; /** Input sanitization active */ sanitizationActive?: boolean; /** Last tool used */ lastToolUsed?: 'Execute' | 'Probe' | 'State' | 'Transform' | 'TaoOps' | null; /** Total tool invocations this session */ totalInvocations?: number; } export declare class UnifiedUIRenderer extends EventEmitter { private readonly output; private readonly input; private readonly rl; private readonly plainMode; private readonly interactive; private rows; private cols; private lastRenderWidth; private eventQueue; private isProcessingQueue; private buffer; private cursor; private history; private historyIndex; private suggestions; private suggestionIndex; private availableCommands; private hotkeysInToggleLine; private collapsedPaste; private mode; /** Queue for input received during streaming - processed after streaming ends */ private streamingInputQueue; /** Buffer to accumulate streaming content for post-processing */ private streamingContentBuffer; /** Track lines written during streaming for potential reformat */ private streamingLinesWritten; private lastToolResult; /** Stack of collapsed tool results for Ctrl+O expansion */ private collapsedToolResults; private readonly maxCollapsedResults; /** Track the last tool name for pairing with results */ private lastToolName; private streamingStartTime; private statusMessage; private statusOverride; private statusStreaming; private streamingSpinner; private thinkingIndicator; private contextMeter; private spinnerFrame; private spinnerInterval; private readonly maxInlinePanelLines; private compactingStatusMessage; private compactingStatusFrame; private compactingStatusInterval; private readonly compactingSpinnerFrames; private activityMessage; private activityPhraseIndex; private activityStarFrame; private readonly activityStarFrames; private streamingTokens; private elapsedColorFrame; private readonly elapsedColorFrames; private readonly funActivityPhrases; private readonly maxCuratedReasoningLines; private readonly maxCuratedReasoningChars; private readonly thoughtDedupWindowMs; private lastCuratedThought; private statusMeta; private toggleState; /** RL agent execution status for dual-RL mode display */ private rlStatus; /** Secure TAO tools status for real-time display */ private secureToolsStatus; /** Ensure cursor is always within valid bounds for the current buffer */ private clampCursor; /** Safely append to paste buffer with size limit enforcement */ private appendToPasteBuffer; /** Strip ANSI escape sequences and special formatting from text to get clean plaintext */ private sanitizePasteContent; private formatHotkey; private lastPromptEvent; private promptHeight; private lastOverlayHeight; private inlinePanel; private hasConversationContent; private isPromptActive; private inputRenderOffset; private readonly plainPasteIdleMs; private readonly plainPasteWindowMs; private readonly plainPasteTriggerChars; private readonly plainPasteEarlyNewlineChars; private readonly maxPasteBufferSize; private pasteBufferOverflow; private cursorVisibleColumn; private inBracketedPaste; private pasteBuffer; private inPlainPaste; private plainPasteBuffer; private plainPasteTimer; private pasteBurstWindowStart; private pasteBurstCharCount; private plainRecentChunks; private pendingInsertBuffer; private pendingInsertTimer; private readonly pendingInsertDelayMs; private emitPasteBuffer; private emitPasteTimer; private readonly emitPasteCommitMs; private lastRenderedEventKey; private lastOutputEndedWithNewline; private hasRenderedPrompt; private hasEverRenderedOverlay; private lastOverlay; private allowPromptRender; private promptRenderingSuspended; private secretMode; private pendingRender; private lastRenderTime; private readonly renderThrottleMs; private renderThrottleTimer; private lastRenderedBuffer; private forceNextRender; private lastRenderedCursor; private lastRenderedMode; private disposed; private initializing; private boundResizeHandler; private boundKeypressHandler; private boundDataHandler; private boundCtrlHandler; private originalEmit; private inputProtection; private inputCapture; private menuItems; private menuIndex; private menuTitle; private menuCallback; constructor(output?: NodeJS.WriteStream, input?: NodeJS.ReadStream, _options?: UnifiedUIRendererOptions); initialize(): void; cleanup(): void; suspendPromptRendering(): void; resumePromptRendering(render?: boolean): void; private interceptedToggle; private interceptedCtrlC; private interceptedCtrlD; private pendingToggleSkips; private setupInputHandlers; /** * Detect toggle characters from raw input data before readline processing. * Returns the toggle letter (g, a, d, t, v) or null if not a toggle. */ private detectToggleFromRawData; /** * Extract all toggle letters from an arbitrary chunk of input data. * Handles both Unicode toggles and ESC-prefixed Meta sequences, and * supports multiple toggles in a single data event. */ private extractToggleLetters; /** * Remove toggle symbols (and their ESC prefixes) from a string so they * can never leak into the prompt buffer. */ private stripToggleSymbols; /** * Check if a character is a toggle character that should never be inserted. * Used as a safety guard to prevent toggle symbols from appearing in input. */ private isToggleCharacter; /** * Handle a detected toggle action. Called from both raw data interception * and keypress processing for reliability. */ private handleToggle; /** * Handle Ctrl+C detected at raw data level. * Bypasses readline's keypress parsing for reliability. */ private handleCtrlC; /** * Handle Ctrl+D detected at raw data level. * Bypasses readline's keypress parsing for reliability. */ private handleCtrlD; /** * Commit buffered emit-level input after idle period. * Decides whether to treat as paste (collapse) or normal typing (insert). */ private commitEmitPasteBuffer; /** * Handle paste detected at emit level (multi-char data arriving at once). * This bypasses readline processing for reliable paste detection. */ private handleEmitLevelPaste; private emitInputChange; private handleKeypress; /** * Ensure horizontal cursor position stays within the visible input window. * Prevents jumps when using left/right arrows on long lines. */ private ensureCursorVisible; /** * Parse raw escape sequences when readline doesn't populate key metadata. * Prevents control codes (e.g., ^[[200~) from leaking into the buffer. */ private parseEscapeSequence; /** * Queue characters for deferred insertion. This prevents visual "leak" of * pasted content by holding characters until we're confident it's not a paste. */ private queuePendingInsert; /** * Commit pending characters as normal input (not a paste). * If we reach here, paste detection didn't trigger, so this is normal typing. */ private commitPendingInsert; /** * Consume pending insert buffer into paste detection (prevents visual leak). */ private consumePendingInsertForPaste; private handleBracketedPaste; private commitPasteBuffer; private handlePlainPaste; private trackPlainPasteBurst; private resetPlainPasteBurst; private cancelPlainPasteCapture; private recordRecentPlainChunk; private pruneRecentPlainChunks; private reclaimRecentPlainChunks; private schedulePlainPasteCommit; private finalizePlainPaste; private insertText; private insertSingleLineText; private submitText; private updateSuggestions; setAvailableCommands(commands: typeof this.suggestions): void; private applySuggestion; private resetSuggestions; private navigateSuggestions; /** Track last added event to prevent duplicates */ private lastAddedEventSignature; addEvent(type: RendererEventType, content: string): void; /** * Re-render the prompt/control bar immediately. * This keeps the chat box pinned during long streaming runs instead of waiting * for the event queue to drain before the prompt reappears. */ private renderPromptOverlay; private processQueue; /** * Merge adjacent response/thought events into a single block so continuous * chat text renders with one bullet instead of one per chunk. */ private coalesceAdjacentTextEvents; /** * Flush pending renderer events. * Useful for startup flows (e.g., welcome banner) to guarantee the scrollback is hydrated * before continuing with additional UI updates. */ flushEvents(timeoutMs?: number): Promise; private renderEvent; private normalizeEventType; private formatContent; /** * Programmatic garbage detection - checks if content looks like internal/system output * that shouldn't be shown to users. Uses structural checks, not pattern matching. */ private isGarbageOutput; /** * Sanitize tool result content to remove leaked reasoning/thinking output. * This filters out fragments that look like internal model output. */ private sanitizeToolResultContent; private curateReasoningContent; private ensureReasoningBullet; private looksStructuredThought; private prioritizeReasoningSegments; private reasoningSignalScore; private shouldRenderThought; /** * Format text in Claude Code style: ⏺ prefix with wrapped continuation lines * Example: * ⏺ The AI ran tools but gave no response. Need to fix * the response handling. Let me check where the AI's * text response should be displayed: */ private formatClaudeCodeBlock; /** * Format a tool call in Claude Code style: * ⏺ [Search] pattern: "foo", path: "src", * output_mode: "content", head_limit: 30 */ private formatToolCall; /** * Parse tool arguments from string like: key: "value", key2: value2 */ private parseToolArgs; /** * Format an argument value (truncate long strings) */ private formatArgValue; /** * Format a tool result in Claude Code style: * ⎿ Found 12 lines (ctrl+o to expand) */ private formatToolResult; /** * Format a compact tool call: ⏺ [Read] file.ts */ private formatCompactToolCall; /** * Parse tool params from args string */ private parseToolParams; /** * Format tool params in Claude Code style with wrapping (default green color) */ private formatToolParams; /** * Format tool params with custom tool color */ private formatToolParamsColored; /** * Color critical parameter values (paths, commands) for readability. */ private colorParamValue; /** * Extract a short summary from tool args */ private extractToolSummary; /** * Format a compact tool result: ⎿ Found X lines (ctrl+o to expand) * For edits, show a small inline diff preview */ private formatCompactToolResult; private colorResultSummary; /** * Format edit result with enhanced inline diff preview * Shows: ⎿ ✓ Updated (filename) - removed X, added Y chars * ├─┐ * │ - old content... * │ + new content... * └─ */ private formatEditResultWithDiff; /** * Format a compact response with bullet on first line */ private formatCompactResponse; /** * Wrap text with a single bullet on the first line and tidy indentation for readability. * Prevents awkward mid-word terminal wrapping by handling the layout ourselves. * Supports full markdown formatting: headers, lists, code blocks, inline styles. */ private wrapBulletText; /** * Format a markdown header with Claude Code style visual hierarchy. */ private formatMarkdownHeader; /** * Format thinking block with premium visual design. * Uses a distinct visual style to clearly separate thinking from responses. * Enhanced with gradient labels, better typography, and visual hierarchy. * * In plain output mode we keep it simple and inline with the rest of the * stream so transcripts remain easy to scan. */ private formatThinkingBlock; /** * Format assistant response with premium styling * Uses distinct visual style to clearly separate from thoughts */ private formatAssistantResponse; private wrapTextToWidth; /** * Format streaming elapsed time in Claude Code style: 3m 30s */ private formatStreamingElapsed; /** * Format a compact conversation block (Claude Code style) * Shows a visual separator with "history" label and ctrl+o hint */ private formatCompactBlock; /** * Add a compact conversation block to the event queue * This displays a collapsed view with expansion hint (Claude Code style) */ addCompactBlock(content: string, label?: string): void; /** * Expand the most recent tool result inline (Ctrl+O support). * Pops from the collapsed results stack and displays full content. */ expandLastToolResult(): boolean; /** * Check if tool output is structured (code, grep, file listings) that shouldn't be word-wrapped. */ private isStructuredToolOutput; /** * Format structured tool output preserving line structure. */ private formatStructuredToolOutput; /** * Get count of expandable collapsed results */ getCollapsedResultCount(): number; /** * Clear all collapsed results (e.g., on new conversation) */ clearCollapsedResults(): void; setMode(mode: 'idle' | 'streaming'): void; /** * Start the animated spinner for streaming status */ private startSpinnerAnimation; /** * Stop the animated spinner */ private stopSpinnerAnimation; /** * Set the activity message displayed with animated star * Example: "Ruminating…" shows as "✳ Ruminating… (esc to interrupt · 34s · ↑1.2k)" */ setActivity(message: string | null): void; /** * Update the token count displayed in the activity line */ updateStreamingTokens(tokens: number): void; /** * Format token count as compact string (e.g., 1.2k, 24k, 128k) */ private formatTokenCount; getMode(): 'idle' | 'streaming'; updateStatus(message: string | null): void; updateStatusBundle(status: { main?: string | null; override?: string | null; streaming?: string | null; }, options?: { render?: boolean; }): void; updateStatusMeta(meta: { model?: string; provider?: string; sessionTime?: string; contextPercent?: number; profile?: string; workspace?: string; directory?: string; writes?: string; sessionLabel?: string; thinkingLabel?: string; autosave?: boolean; version?: string; toolSummary?: string; }, options?: { render?: boolean; }): void; updateModeToggles(state: Partial): void; /** * Update RL agent execution status for display in the UI. * Called during dual-RL mode to show active agent, module/step progress, and win statistics. */ updateRLStatus(status: Partial): void; /** * Clear RL agent status (e.g., when RL run completes). */ clearRLStatus(): void; /** * Get current RL status for external access. */ getRLStatus(): Readonly; /** * Update secure TAO tools status for display in the UI. * Tracks Execute, Probe, State tools with enhanced output formatting. */ updateSecureToolsStatus(status: Partial): void; /** * Record a secure tool invocation for tracking. */ recordSecureToolInvocation(tool: 'Execute' | 'Probe' | 'State' | 'Transform' | 'TaoOps', details?: { command?: string; exitCode?: number; target?: string; services?: number; action?: 'get' | 'set'; keysCount?: number; }): void; /** * Get current secure tools status for external access. */ getSecureToolsStatus(): Readonly; setInlinePanel(lines: string[]): void; supportsInlinePanel(): boolean; clearInlinePanel(): void; /** * Show an interactive menu with arrow key navigation (Claude Code style). * Menu is displayed in the inline panel area and intercepts arrow/enter keys. * @param items - Menu items to display * @param options - Menu options (title, initialIndex) * @param callback - Called when user selects an item (or null if cancelled) */ setMenu(items: MenuItem[], options: { title?: string; initialIndex?: number; }, callback: (item: MenuItem | null) => void): void; /** * Close the active menu without selecting anything. */ closeMenu(): void; /** * Check if an interactive menu is currently active. */ isMenuActive(): boolean; /** * Render the menu to the inline panel. */ private renderMenuPanel; /** * Navigate menu selection. * @returns true if menu consumed the navigation */ private navigateMenu; /** * Select the currently highlighted menu item. * @returns true if menu consumed the selection */ private selectMenuItem; private limitInlinePanel; private renderPrompt; private renderPromptImmediate; private buildOverlayLines; /** * Build a single compact status line with all essential info * Format: deepseek-reasoner · ░░░░░░ 5% · agi-code · ~/GitHub */ private buildCompactStatusLine; private buildChromeLines; private abbreviatePath; private buildStatusBlock; private buildMetaBlock; /** * Build RL agent status segments for display during dual-RL execution. * Shows: tournament scoreboard, active agent, module/step progress, and scores. */ private buildRLStatusSegments; /** * Build secure TAO tools status segments for display. * Shows: toolkit status, tool invocation counts, and last tool used. */ private buildSecureToolsSegments; /** * Truncate a string in the middle, showing start and end with ellipsis. */ private truncateMiddle; private composeStatusLabel; private formatMetaSegment; private applyTone; private wrapSegments; private buildControlLines; private buildToggleLine; private buildShortcutLine; private buildInputLine; private buildInputWindow; /** * Expand collapsed paste into the buffer without submitting (Ctrl+L). * Allows user to edit the pasted content before submission. */ private expandCollapsedPasteToBuffer; /** * Expand collapsed paste and submit immediately. * Useful for programmatic submissions when a paste chip is active. */ private expandCollapsedPaste; captureInput(options?: { allowEmpty?: boolean; trim?: boolean; resetBuffer?: boolean; }): Promise; private cancelInputCapture; private wrapOverlayLine; private safeWidth; private visibleLength; private stripAnsi; private truncateLine; getBuffer(): string; getCursor(): number; setBuffer(text: string, cursorPos?: number): void; setSecretMode(enabled: boolean): void; clearBuffer(): void; setModeStatus(status: string | null): void; /** * Show a compacting status with animated spinner (Claude Code style) * Uses ✻ character with animation to indicate context compaction in progress */ showCompactingStatus(message: string): void; /** * Hide the compacting status and stop spinner animation */ hideCompactingStatus(): void; emitPrompt(content: string): void; /** * Display user prompt immediately in scrollback (Claude Code style) * Writes synchronously to ensure it appears ONCE in scrollback before status updates. * The prompt input area will then float below this and all subsequent events. */ private displayUserPrompt; render(): void; private delay; private write; private pushPromptEvent; private clearPromptArea; private updateTerminalSize; } export {}; //# sourceMappingURL=UnifiedUIRenderer.d.ts.map