import { AlternateScreen, Box, NoSelect, ScrollBox, Text } from '@hermes/ink' import { useStore } from '@nanostores/react' import { memo } from 'react' import type { AppLayoutProgressProps, AppLayoutProps } from '../app/interfaces.js' import { $isBlocked } from '../app/overlayStore.js' import { $uiState } from '../app/uiStore.js' import { PLACEHOLDER } from '../content/placeholders.js' import type { Theme } from '../theme.js' import type { DetailsMode } from '../types.js' import { GoodVibesHeart, StatusRule, StickyPromptTracker, TranscriptScrollbar } from './appChrome.js' import { FloatingOverlays, PromptZone } from './appOverlays.js' import { Banner, Panel, SessionPanel } from './branding.js' import { MessageLine } from './messageLine.js' import { QueuedMessages } from './queuedMessages.js' import { TextInput } from './textInput.js' import { ToolTrail } from './thinking.js' const StreamingAssistant = memo(function StreamingAssistant({ busy, cols, compact, detailsMode, progress, t }: StreamingAssistantProps) { if (!progress.showProgressArea && !progress.showStreamingArea) { return null } return ( <> {progress.showProgressArea && ( )} {progress.showStreamingArea && ( )} ) }) const TranscriptPane = memo(function TranscriptPane({ actions, composer, progress, transcript }: Pick) { const ui = useStore($uiState) return ( <> {transcript.virtualHistory.topSpacer > 0 ? : null} {transcript.virtualRows.slice(transcript.virtualHistory.start, transcript.virtualHistory.end).map(row => ( {row.msg.kind === 'intro' ? ( {row.msg.info?.version && } ) : row.msg.kind === 'panel' && row.msg.panelData ? ( ) : ( )} ))} {transcript.virtualHistory.bottomSpacer > 0 ? : null} ) }) const ComposerPane = memo(function ComposerPane({ actions, composer, status }: Pick) { const ui = useStore($uiState) const isBlocked = useStore($isBlocked) const sh = (composer.inputBuf[0] ?? composer.input).startsWith('!') const pw = sh ? 2 : 3 return ( {ui.bgTasks.size > 0 && ( {ui.bgTasks.size} background {ui.bgTasks.size === 1 ? 'task' : 'tasks'} running )} {status.showStickyPrompt ? ( {status.stickyPrompt} ) : ( )} {ui.statusBar && ( )} {!isBlocked && ( {composer.inputBuf.map((line, i) => ( {i === 0 ? `${ui.theme.brand.prompt} ` : ' '} {line || ' '} ))} {sh ? ( $ ) : ( {composer.inputBuf.length ? ' ' : `${ui.theme.brand.prompt} `} )} )} {!composer.empty && !ui.sid && ⚕ {ui.status}} ) }) export const AppLayout = memo(function AppLayout({ actions, composer, mouseTracking, progress, status, transcript }: AppLayoutProps) { return ( ) }) interface StreamingAssistantProps { busy: boolean cols: number compact?: boolean detailsMode: DetailsMode progress: AppLayoutProgressProps t: Theme }