All checks were successful
ci/woodpecker/push/ci Pipeline was successful
Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
88 lines
2.3 KiB
TypeScript
88 lines
2.3 KiB
TypeScript
import React, { useState, useCallback } from 'react';
|
||
import { Box, Text } from 'ink';
|
||
import TextInput from 'ink-text-input';
|
||
import type { ParsedCommand } from '@mosaic/types';
|
||
import { parseSlashCommand, commandRegistry } from '../commands/index.js';
|
||
|
||
export interface InputBarProps {
|
||
onSubmit: (value: string) => void;
|
||
onSystemMessage?: (message: string) => void;
|
||
onLocalCommand?: (parsed: ParsedCommand) => void;
|
||
onGatewayCommand?: (parsed: ParsedCommand) => void;
|
||
isStreaming: boolean;
|
||
connected: boolean;
|
||
placeholder?: string;
|
||
}
|
||
|
||
export function InputBar({
|
||
onSubmit,
|
||
onSystemMessage,
|
||
onLocalCommand,
|
||
onGatewayCommand,
|
||
isStreaming,
|
||
connected,
|
||
placeholder: placeholderOverride,
|
||
}: InputBarProps) {
|
||
const [input, setInput] = useState('');
|
||
|
||
const handleSubmit = useCallback(
|
||
(value: string) => {
|
||
if (!value.trim() || isStreaming || !connected) return;
|
||
|
||
const trimmed = value.trim();
|
||
|
||
if (trimmed.startsWith('/')) {
|
||
const parsed = parseSlashCommand(trimmed);
|
||
if (!parsed) {
|
||
onSystemMessage?.(`Unknown command format: ${trimmed}`);
|
||
setInput('');
|
||
return;
|
||
}
|
||
const def = commandRegistry.find(parsed.command);
|
||
if (!def) {
|
||
onSystemMessage?.(
|
||
`Unknown command: /${parsed.command}. Type /help for available commands.`,
|
||
);
|
||
setInput('');
|
||
return;
|
||
}
|
||
if (def.execution === 'local') {
|
||
onLocalCommand?.(parsed);
|
||
setInput('');
|
||
return;
|
||
}
|
||
// Gateway-executed commands
|
||
onGatewayCommand?.(parsed);
|
||
setInput('');
|
||
return;
|
||
}
|
||
|
||
onSubmit(value);
|
||
setInput('');
|
||
},
|
||
[onSubmit, onSystemMessage, onLocalCommand, onGatewayCommand, isStreaming, connected],
|
||
);
|
||
|
||
const placeholder =
|
||
placeholderOverride ??
|
||
(!connected
|
||
? 'disconnected — waiting for gateway…'
|
||
: isStreaming
|
||
? 'waiting for response…'
|
||
: 'message mosaic…');
|
||
|
||
return (
|
||
<Box paddingX={1} borderStyle="single" borderColor="gray">
|
||
<Text bold color="green">
|
||
{'❯ '}
|
||
</Text>
|
||
<TextInput
|
||
value={input}
|
||
onChange={setInput}
|
||
onSubmit={handleSubmit}
|
||
placeholder={placeholder}
|
||
/>
|
||
</Box>
|
||
);
|
||
}
|