feat(cli): TUI component architecture — status bars, message list, input bar

- Split monolithic app.tsx into composable components:
  - TopBar: connection indicator (●/○), gateway URL, model name, conversation ID
  - BottomBar: cwd, git branch, token usage
  - MessageList: timestamped messages, tool call indicators, thinking display
  - InputBar: context-aware prompt with streaming/disconnect states
- Extract socket logic into useSocket hook with typed events
- Extract git/cwd info into useGitInfo hook
- Quiet disconnect: single indicator instead of error flood
- Add @mosaic/types dependency for typed Socket.IO events
- Add PRD and task tracking docs

Tasks: TUI-001 through TUI-007 (Wave 1)
This commit is contained in:
2026-03-15 13:33:37 -05:00
parent 09e649fc7e
commit 79ff308aad
11 changed files with 668 additions and 153 deletions

View File

@@ -0,0 +1,55 @@
import React from 'react';
import { Box, Text } from 'ink';
export interface TopBarProps {
connected: boolean;
connecting: boolean;
gatewayUrl: string;
conversationId?: string;
modelName: string | null;
}
export function TopBar({
connected,
connecting,
gatewayUrl,
conversationId,
modelName,
}: TopBarProps) {
const indicator = connected ? '●' : '○';
const indicatorColor = connected ? 'green' : connecting ? 'yellow' : 'red';
const statusLabel = connected ? 'connected' : connecting ? 'connecting' : 'disconnected';
// Strip protocol for compact display
const host = gatewayUrl.replace(/^https?:\/\//, '');
return (
<Box borderStyle="single" borderColor="gray" paddingX={1} justifyContent="space-between">
<Box>
<Text bold color="blue">
mosaic
</Text>
<Text> </Text>
<Text color={indicatorColor}>{indicator}</Text>
<Text dimColor> {statusLabel}</Text>
<Text dimColor> · {host}</Text>
</Box>
<Box>
{modelName && (
<>
<Text dimColor>model: </Text>
<Text color="magenta">{modelName}</Text>
<Text> </Text>
</>
)}
{conversationId && (
<>
<Text dimColor>conv: </Text>
<Text>{conversationId.slice(0, 8)}</Text>
</>
)}
</Box>
</Box>
);
}