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 3792576566
commit 9ae1bac614
10 changed files with 629 additions and 3 deletions

View File

@@ -0,0 +1,44 @@
import React, { useState, useCallback } from 'react';
import { Box, Text } from 'ink';
import TextInput from 'ink-text-input';
export interface InputBarProps {
onSubmit: (value: string) => void;
isStreaming: boolean;
connected: boolean;
}
export function InputBar({ onSubmit, isStreaming, connected }: InputBarProps) {
const [input, setInput] = useState('');
const handleSubmit = useCallback(
(value: string) => {
if (!value.trim() || isStreaming || !connected) return;
onSubmit(value);
setInput('');
},
[onSubmit, isStreaming, connected],
);
const placeholder = !connected
? 'disconnected — waiting for gateway…'
: isStreaming
? 'waiting for response…'
: 'message mosaic…';
const promptColor = !connected ? 'red' : isStreaming ? 'yellow' : 'green';
return (
<Box paddingX={1} borderStyle="single" borderColor="gray">
<Text bold color={promptColor}>
{' '}
</Text>
<TextInput
value={input}
onChange={setInput}
onSubmit={handleSubmit}
placeholder={placeholder}
/>
</Box>
);
}