/** * TuiApp - Main TUI application shell * DD ยง13.2. Uses OpenTUI @opentui/* as renderer (npm-dep, do NOT reimplement). * * @module packages/tui/src/TuiApp */ import { ProjectionClient } from '@aircoding/runtime' import { SessionView } from './components/SessionView.js' import { TaskListView } from './components/TaskListView.js' import { AgentStatusView } from './components/AgentStatusView.js' import { HudView } from './components/HudView.js' import type { SessionProjection } from '@aircoding/runtime' export interface TuiAppProps { client: ProjectionClient } export interface TuiAppState { projection: SessionProjection | null active_view: 'tasks' | 'agents' | 'tools' | 'diff' } export class TuiApp { private client: ProjectionClient private state: TuiAppState private unsubscribe: (() => void) | null = null constructor(props: TuiAppProps) { this.client = props.client this.state = { projection: null, active_view: 'tasks' } } /** * Start the TUI application. * TODO(P6): Initialize OpenTUI renderer and start render loop. */ async start(): Promise { this.unsubscribe = this.client.subscribe((projection) => { this.state.projection = projection this.render() }) // Initial snapshot const snapshot = this.client.get_snapshot() if (snapshot) { this.state.projection = snapshot this.render() } } /** * Stop the TUI application. */ stop(): void { this.unsubscribe?.() this.unsubscribe = null } /** * Set active view. */ set_view(view: TuiAppState['active_view']): void { this.state.active_view = view this.render() } /** * Render the current state. * TODO(P6): Use OpenTUI renderer instead of console output. */ private render(): void { // STUB: Would render via OpenTUI components const p = this.state.projection if (!p) { console.log('[TUI] No projection data') return } console.log(`[TUI] Session: ${p.session_id} | Status: ${p.status} | Tasks: ${p.tasks.length} | Agents: ${p.agents.length}`) } }