diff --git a/src/tui/App.tsx b/src/tui/App.tsx index 3dea5f0f..4e442c01 100644 --- a/src/tui/App.tsx +++ b/src/tui/App.tsx @@ -1,9 +1,26 @@ /** * @fileoverview Main TUI App component * - * The root component that manages the overall TUI layout: - * - StartScreen: Initial session discovery view - * - Main view: TabBar + Terminal + StatusBar + * The root component that manages the overall TUI layout and navigation. + * + * @description + * Provides two primary views: + * - **StartScreen**: Session discovery and selection interface + * - **Main view**: Active session management with: + * - TabBar: Session tabs with switching + * - TerminalView: Live terminal output display + * - RalphPanel: Inner loop tracking (conditional) + * - StatusBar: Session info and keyboard hints + * + * Keyboard shortcuts are handled globally via Ink's useInput hook. + * + * @example + * ```tsx + * import { render } from 'ink'; + * import { App } from './App.js'; + * + * render(); + * ``` */ import React, { useState, useEffect, useCallback } from 'react'; @@ -21,7 +38,23 @@ import type { ScreenSession } from '../types.js'; type ViewMode = 'start' | 'main'; /** - * Main application component + * Main TUI application component. + * + * @description + * Renders either the StartScreen or Main view based on current state. + * Handles all global keyboard shortcuts and manages terminal dimensions. + * + * **Global Shortcuts:** + * - `?` or `Ctrl+H`: Show help overlay + * - `Ctrl+C`: Exit application + * - `Ctrl+Tab/Shift+Tab`: Navigate sessions + * - `Ctrl+1-9`: Direct session access + * - `Ctrl+W`: Close current session + * - `Ctrl+K`: Kill all sessions + * - `Ctrl+N`: Create new session + * - `Escape`: Return to start screen + * + * @returns The rendered TUI application */ export function App(): React.ReactElement { const { exit } = useApp(); diff --git a/src/tui/components/HelpOverlay.tsx b/src/tui/components/HelpOverlay.tsx index d529ef10..4db56470 100644 --- a/src/tui/components/HelpOverlay.tsx +++ b/src/tui/components/HelpOverlay.tsx @@ -1,8 +1,16 @@ /** * @fileoverview HelpOverlay component * - * Full-screen overlay showing all keyboard shortcuts. - * Dismissible with Escape, q, or ?. + * Full-screen help overlay displaying all TUI keyboard shortcuts. + * + * @description + * Shows a comprehensive reference of keyboard shortcuts organized by context: + * - Start Screen: Session list navigation and actions + * - Main View - Navigation: Tab switching and screen navigation + * - Main View - Session Management: Create, close, kill sessions + * - General: Help toggle and exit + * + * Dismissible with Escape, q, or ? keys. */ import React from 'react'; @@ -57,7 +65,15 @@ const SHORTCUT_GROUPS: ShortcutGroup[] = [ ]; /** - * HelpOverlay component showing keyboard shortcuts + * Help overlay component displaying keyboard shortcuts reference. + * + * @description + * Renders a full-screen overlay with categorized keyboard shortcuts. + * Uses consistent styling with bordered header and grouped sections. + * + * @param props - Component props + * @param props.onClose - Callback invoked when overlay should close + * @returns The help overlay element */ export function HelpOverlay({ onClose }: HelpOverlayProps): React.ReactElement { return ( diff --git a/src/tui/components/RalphPanel.tsx b/src/tui/components/RalphPanel.tsx index d18a7960..49338eb2 100644 --- a/src/tui/components/RalphPanel.tsx +++ b/src/tui/components/RalphPanel.tsx @@ -1,10 +1,18 @@ /** * @fileoverview RalphPanel component * - * Displays Ralph Wiggum loop tracking information: - * - Loop status and completion phrase - * - Todo list with progress - * - Cycle count and elapsed time + * Displays Ralph Wiggum autonomous loop tracking information. + * + * @description + * The Ralph Wiggum loop is an autonomous work mode where Claude + * continues iterating on tasks until completion criteria are met. + * This panel provides visibility into: + * - Loop status (active/idle) and completion phrase + * - Progress through todos with visual indicators + * - Cycle count and elapsed time tracking + * + * @see {@link file://./../../inner-loop-tracker.ts} for detection logic + * @see {@link file://./../../../docs/ralph-wiggum-guide.md} for full documentation */ import React from 'react'; @@ -18,7 +26,10 @@ interface RalphPanelProps { } /** - * Status icon for todo items + * Returns the visual indicator for a todo item's status. + * + * @param status - The todo status: 'completed', 'in_progress', or 'pending' + * @returns Object with Unicode icon and color name */ function getStatusIcon(status: string): { icon: string; color: string } { switch (status) { @@ -33,7 +44,10 @@ function getStatusIcon(status: string): { icon: string; color: string } { } /** - * Formats elapsed hours to human-readable string + * Formats elapsed hours to a compact human-readable string. + * + * @param hours - Elapsed time in hours (can be fractional) + * @returns Formatted string like "45m" or "2.5h" */ function formatElapsed(hours: number | null): string { if (hours === null) return '-'; @@ -45,7 +59,21 @@ function formatElapsed(hours: number | null): string { } /** - * RalphPanel component showing loop tracking + * Panel component displaying Ralph Wiggum loop status and progress. + * + * @description + * Renders a bordered panel with: + * - Header showing loop status and completion phrase + * - Stats row with cycle count, elapsed time, and todo progress + * - Todo list (max 5 visible) with status icons + * + * Only renders when loop is enabled and has relevant data to show. + * + * @param props - Component props + * @param props.loopState - Current loop state from InnerLoopTracker + * @param props.todos - Array of todo items being tracked + * @param props.visible - Whether the panel should be visible (default: true) + * @returns The panel element or null if hidden/disabled */ export function RalphPanel({ loopState, diff --git a/src/tui/components/StartScreen.tsx b/src/tui/components/StartScreen.tsx index e0b37839..db310713 100644 --- a/src/tui/components/StartScreen.tsx +++ b/src/tui/components/StartScreen.tsx @@ -1,11 +1,16 @@ /** * @fileoverview StartScreen component * - * Initial screen shown when TUI launches. Displays: - * - List of existing screen sessions from ~/.claudeman/screens.json - * - Session status (alive/dead), runtime, mode - * - Arrow key navigation with highlighted selection - * - Options to select, create, attach, or refresh sessions + * Session discovery and selection interface for the TUI. + * + * @description + * The initial screen displayed when launching `claudeman tui`: + * - Reads session list from ~/.claudeman/screens.json + * - Shows session name, runtime, status (alive/dead), and mode + * - Arrow key navigation with visual selection highlight + * - Actions: Enter (view), a (attach), d (delete), n (new), r (refresh), q (quit) + * + * This is the "home screen" users return to with Escape from the main view. */ import React, { useState } from 'react'; @@ -23,7 +28,10 @@ interface StartScreenProps { } /** - * Formats duration from milliseconds to human-readable string + * Formats a duration from milliseconds to a compact human-readable string. + * + * @param ms - Duration in milliseconds + * @returns Formatted string like "45s", "5m", "2h 15m", or "3d 5h" */ function formatDuration(ms: number): string { const seconds = Math.floor(ms / 1000); @@ -44,7 +52,30 @@ function formatDuration(ms: number): string { } /** - * Start screen component showing session list with arrow key navigation + * Start screen component for session discovery and selection. + * + * @description + * Renders a table of available sessions with: + * - Arrow key navigation (wraps at boundaries) + * - Visual selection highlight (blue background) + * - Status indicators (green=alive, red=dead) + * - Runtime and mode information + * + * **Keyboard Shortcuts:** + * - `↑/↓`: Navigate selection + * - `Enter`: View session in TUI + * - `a`: Attach directly to screen (exits TUI) + * - `d/x`: Delete/kill selected session + * + * @param props - Component props + * @param props.sessions - Array of sessions to display + * @param props.onSelectSession - Callback to view session in TUI + * @param props.onAttachSession - Callback to attach directly to screen + * @param props.onDeleteSession - Callback to delete/kill session + * @param props.onCreateSession - Callback to create new session + * @param props.onRefresh - Callback to refresh session list + * @param props.onExit - Callback to exit TUI + * @returns The start screen element */ export function StartScreen({ sessions, diff --git a/src/tui/components/StatusBar.tsx b/src/tui/components/StatusBar.tsx index 164c9146..dd604665 100644 --- a/src/tui/components/StatusBar.tsx +++ b/src/tui/components/StatusBar.tsx @@ -1,12 +1,15 @@ /** * @fileoverview StatusBar component * - * Bottom status bar showing: - * - Session status (idle/working) - * - Token count - * - Cost - * - Runtime - * - Quick keyboard shortcuts + * Bottom status bar providing session information and navigation hints. + * + * @description + * Displays real-time session metrics: + * - Session name and connection status (alive/dead) + * - Runtime duration since session creation + * - Session mode (claude/shell) + * - Respawn controller status when enabled + * - Keyboard shortcut hints for quick reference */ import React from 'react'; @@ -26,7 +29,10 @@ interface StatusBarProps { } /** - * Formats duration from milliseconds to human-readable string + * Formats a duration from milliseconds to a human-readable string. + * + * @param ms - Duration in milliseconds + * @returns Formatted string like "45s", "5m 30s", or "2h 15m" */ function formatDuration(ms: number): string { const seconds = Math.floor(ms / 1000); @@ -43,7 +49,20 @@ function formatDuration(ms: number): string { } /** - * StatusBar component showing session information + * Status bar component displaying session information and keyboard hints. + * + * @description + * Renders a bordered bar at the bottom of the TUI with: + * - Left side: Session name, status indicator, runtime, mode, respawn state + * - Right side: Quick keyboard shortcut reference + * + * When no session is selected, displays a minimal bar with navigation hints. + * + * @param props - Component props + * @param props.session - The currently active session or null + * @param props.inputMode - Whether input mode is active (shows yellow indicator) + * @param props.respawnStatus - Respawn controller status if enabled + * @returns The status bar element */ export function StatusBar({ session, inputMode = false, respawnStatus }: StatusBarProps): React.ReactElement { if (!session) { diff --git a/src/tui/components/TabBar.tsx b/src/tui/components/TabBar.tsx index 10ab28b2..f873376b 100644 --- a/src/tui/components/TabBar.tsx +++ b/src/tui/components/TabBar.tsx @@ -1,11 +1,16 @@ /** * @fileoverview TabBar component * - * Horizontal tab bar showing all active sessions. - * Features: - * - Visual indication of active tab - * - Status indicator (idle/working) - * - Tab truncation for long names + * Horizontal tab bar for session navigation in the TUI. + * + * @description + * Provides browser-like tab navigation for Claude sessions: + * - Active tab highlighted with blue background + * - Status indicators: green dot (alive) or red dot (dead) + * - Session names truncated to 15 characters + * - Keyboard shortcut hints on the right + * + * Tab switching is handled by parent via keyboard shortcuts (Ctrl+Tab). */ import React from 'react'; @@ -19,7 +24,19 @@ interface TabBarProps { } /** - * TabBar component for session navigation + * Tab bar component showing all available sessions. + * + * @description + * Renders a horizontal bar with one tab per session, showing: + * - Status indicator (filled/hollow circle for alive/dead) + * - Session name (truncated to 15 chars) + * - Visual highlighting for the active session + * + * @param props - Component props + * @param props.sessions - Array of all sessions to display as tabs + * @param props.activeSessionId - ID of currently active session for highlighting + * @param props.onSelectSession - Callback when a tab is clicked (unused, keyboard nav only) + * @returns The tab bar element */ export function TabBar({ sessions, diff --git a/src/tui/components/TerminalView.tsx b/src/tui/components/TerminalView.tsx index 7b80745f..99245b55 100644 --- a/src/tui/components/TerminalView.tsx +++ b/src/tui/components/TerminalView.tsx @@ -1,11 +1,16 @@ /** * @fileoverview TerminalView component * - * Displays PTY output from the active session. - * Features: - * - Scrollable viewport showing last N lines - * - ANSI color support (handled by Ink) - * - Visual border indicating focus + * Primary terminal output display for Claude session monitoring. + * + * @description + * Renders the terminal output from a GNU screen session: + * - Viewport shows last N lines based on available height + * - Line splitting is memoized for performance + * - Visual border color indicates session state (green=active, gray=none) + * - Long lines are truncated to prevent wrapping issues + * + * Output is obtained via screen hardcopy polling in useSessionManager. */ import React, { useMemo } from 'react'; @@ -19,7 +24,17 @@ interface TerminalViewProps { } /** - * TerminalView component for PTY output display + * Terminal view component for displaying session output. + * + * @description + * Shows the last N lines of terminal output that fit within the given height. + * When no session is selected, displays a placeholder message. + * + * @param props - Component props + * @param props.output - Raw terminal output string from screen hardcopy + * @param props.height - Available height in terminal rows (includes border) + * @param props.session - The active session or null + * @returns The terminal view element */ export function TerminalView({ output, diff --git a/src/tui/hooks/useSessionManager.ts b/src/tui/hooks/useSessionManager.ts index bb760f82..a352f54b 100644 --- a/src/tui/hooks/useSessionManager.ts +++ b/src/tui/hooks/useSessionManager.ts @@ -1,10 +1,26 @@ /** * @fileoverview useSessionManager hook * - * Manages session state for the TUI. Connects to: - * - ~/.claudeman/screens.json for session discovery - * - ScreenManager for session operations - * - Session class for terminal output + * Core state management hook for the TUI application. + * + * @description + * This hook provides a complete interface for managing Claude sessions: + * - Session discovery from ~/.claudeman/screens.json + * - Terminal output polling via GNU screen hardcopy + * - Inner loop state tracking for Ralph Wiggum loops + * - Respawn status monitoring via the Claudeman API + * + * @example + * ```tsx + * const { + * sessions, + * activeSession, + * terminalOutput, + * selectSession, + * createSession, + * sendInput, + * } = useSessionManager(); + * ``` */ import { useState, useEffect, useCallback, useRef } from 'react'; @@ -43,7 +59,10 @@ interface SessionManagerState { } /** - * Check if a screen session is alive + * Checks if a GNU screen session is currently running. + * + * @param screenName - The name of the screen session to check + * @returns true if the session exists and is alive, false otherwise */ function isScreenAlive(screenName: string): boolean { try { @@ -55,7 +74,13 @@ function isScreenAlive(screenName: string): boolean { } /** - * Load sessions from screens.json + * Loads all sessions from the Claudeman screens registry. + * + * @description + * Reads ~/.claudeman/screens.json and enriches each session with + * its current alive/dead status by checking GNU screen. + * + * @returns Array of screen sessions with updated attached status */ function loadSessions(): ScreenSession[] { try { @@ -76,7 +101,14 @@ function loadSessions(): ScreenSession[] { } /** - * Load inner state for a session + * Loads Ralph Wiggum loop state for a specific session. + * + * @description + * Reads ~/.claudeman/state-inner.json which contains per-session + * tracking of inner loops, todos, and completion phrases. + * + * @param sessionId - The UUID of the session to load state for + * @returns The inner session state or null if not found */ function loadInnerState(sessionId: string): InnerSessionState | null { try { @@ -92,7 +124,34 @@ function loadInnerState(sessionId: string): InnerSessionState | null { } /** - * Hook for managing sessions in the TUI + * React hook for managing Claude sessions in the TUI. + * + * @description + * Provides complete session lifecycle management: + * - Automatic session discovery and status monitoring + * - Terminal output polling (500ms interval) + * - Inner loop state tracking (500ms interval) + * - Respawn status polling via API (2000ms interval) + * - Session CRUD operations via Claudeman API + * + * @returns SessionManagerState object with session data and control methods + * + * @example + * ```tsx + * function MyComponent() { + * const { sessions, selectSession, sendInput } = useSessionManager(); + * + * return ( + * + * {sessions.map(s => ( + * selectSession(s.sessionId)}> + * {s.name} + * + * ))} + * + * ); + * } + * ``` */ export function useSessionManager(): SessionManagerState { const [sessions, setSessions] = useState([]); diff --git a/src/tui/index.tsx b/src/tui/index.tsx index 30cb2ee3..0c3b8b1d 100644 --- a/src/tui/index.tsx +++ b/src/tui/index.tsx @@ -1,9 +1,27 @@ /** * @fileoverview TUI entry point for Claudeman * - * Renders the terminal user interface using Ink (React for CLI). - * This provides a full-screen TUI similar to the web interface, - * with tabs for sessions and real-time terminal output. + * Entry point for the terminal user interface, providing a full-screen + * session manager similar to the web interface but entirely in the terminal. + * + * @description + * Built with Ink (React for CLI), the TUI offers: + * - Session discovery from ~/.claudeman/screens.json + * - Tab-based session navigation (like browser tabs) + * - Real-time terminal output via screen hardcopy polling + * - Ralph Wiggum loop tracking + * - Respawn status monitoring + * + * @example + * ```bash + * # Start the TUI + * claudeman tui + * # Or via npm + * npm run tui + * ``` + * + * @see {@link ./App.tsx} for main application component + * @see {@link ./hooks/useSessionManager.ts} for state management */ import React from 'react'; @@ -11,7 +29,13 @@ import { render } from 'ink'; import { App } from './App.js'; /** - * Checks if the terminal supports raw mode (required for TUI) + * Checks if the terminal supports raw mode input. + * + * @description + * Raw mode is required for Ink to capture keyboard input directly. + * This check fails when stdin is piped or redirected (e.g., `echo | claudeman tui`). + * + * @returns true if raw mode is available, false otherwise */ function isRawModeSupported(): boolean { return Boolean( @@ -21,8 +45,15 @@ function isRawModeSupported(): boolean { } /** - * Starts the TUI application - * @returns Promise that resolves when the app exits + * Starts the TUI application in the current terminal. + * + * @description + * Initializes the Ink renderer and displays the TUI. + * The terminal is cleared for a full-screen experience. + * This function blocks until the user exits the TUI. + * + * @throws Exits with code 1 if TTY/raw mode is not supported + * @returns Promise that resolves when the TUI exits */ export async function startTUI(): Promise { // Check if we're in an interactive terminal