feat: enhance TUI with colors, command hints, and improved rendering

This commit is contained in:
William Valentin
2026-02-05 15:51:29 -08:00
parent dbf1acd822
commit c1f64d6ded
8 changed files with 459 additions and 122 deletions
+106 -8
View File
@@ -19,7 +19,7 @@ export function parseCommand(input: string): Command | null {
}
// Reset
if (trimmed === '/reset' || trimmed === '/clear') {
if (trimmed === '/reset' || trimmed === '/clear' || trimmed === '/new') {
return { type: 'reset' };
}
@@ -69,19 +69,117 @@ export function parseCommand(input: string): Command | null {
export function getHelpText(): string {
return `
Commands:
/help, /? Show this help
/model [name] Show or switch model (local, default, fast, complex)
/help, /? Show this help
/model [name] Show or switch model (local, default, fast, complex)
/backend [provider] Show or switch local backend (ollama, llamacpp)
/reset, /clear Clear conversation history
/status Show session info and token usage
/fullscreen, /fs Switch to fullscreen mode
/transfer <dest> Transfer session to another frontend
/quit, /exit Exit TUI
/reset, /clear, /new Clear conversation history
/status Show session info and token usage
/fullscreen, /fs Switch to fullscreen mode
/transfer <dest> Transfer session to another frontend
/quit, /exit Exit TUI
`.trim();
}
export type ModelAlias = 'local' | 'default' | 'fast' | 'complex' | 'opus' | 'sonnet' | 'ollama';
// List of all slash commands for autocompletion
export const SLASH_COMMANDS = [
'/help',
'/model',
'/backend',
'/reset',
'/clear',
'/new',
'/status',
'/fullscreen',
'/fs',
'/transfer',
'/quit',
'/exit',
];
// Command descriptions for tooltips
export const COMMAND_TOOLTIPS: Record<string, string> = {
'/help': 'Show available commands',
'/model': 'Show or switch model (local, default, fast, complex)',
'/backend': 'Show or switch local backend (ollama, llamacpp)',
'/reset': 'Clear conversation history',
'/clear': 'Clear conversation history',
'/new': 'Start a new conversation',
'/status': 'Show session info and token usage',
'/fullscreen': 'Switch to fullscreen mode',
'/fs': 'Switch to fullscreen mode',
'/transfer': 'Transfer session to another frontend',
'/quit': 'Exit TUI',
'/exit': 'Exit TUI',
};
// Model aliases for /model command autocompletion
export const MODEL_ALIASES = ['local', 'default', 'fast', 'complex', 'opus', 'sonnet', 'ollama'];
// Model alias descriptions
export const MODEL_TOOLTIPS: Record<string, string> = {
local: 'Local Ollama model',
default: 'Default model (Opus)',
fast: 'Fast model (Sonnet)',
complex: 'Complex reasoning model',
opus: 'Claude Opus',
sonnet: 'Claude Sonnet',
ollama: 'Local Ollama model',
};
export function getCommandCompletions(partial: string): string[] {
const trimmed = partial.trim();
// Complete /model arguments
if (trimmed.startsWith('/model ')) {
const modelPartial = trimmed.slice('/model '.length).toLowerCase();
return MODEL_ALIASES
.filter(alias => alias.startsWith(modelPartial))
.map(alias => `/model ${alias}`);
}
// Complete slash commands
if (trimmed.startsWith('/')) {
return SLASH_COMMANDS.filter(cmd => cmd.startsWith(trimmed.toLowerCase()));
}
return [];
}
export function getCommandTooltip(partial: string): string | null {
const trimmed = partial.trim().toLowerCase();
// Tooltip for /model arguments
if (trimmed.startsWith('/model ')) {
const modelArg = trimmed.slice('/model '.length).trim();
if (modelArg && MODEL_TOOLTIPS[modelArg]) {
return MODEL_TOOLTIPS[modelArg];
}
// Show tooltip for partial match
const matches = MODEL_ALIASES.filter(a => a.startsWith(modelArg));
if (matches.length === 1 && MODEL_TOOLTIPS[matches[0]]) {
return MODEL_TOOLTIPS[matches[0]];
}
return 'Choose: local, default, fast, complex';
}
// Exact match tooltip
if (COMMAND_TOOLTIPS[trimmed]) {
return COMMAND_TOOLTIPS[trimmed];
}
// Partial match - show tooltip if only one command matches
if (trimmed.startsWith('/')) {
const matches = SLASH_COMMANDS.filter(cmd => cmd.startsWith(trimmed));
if (matches.length === 1 && COMMAND_TOOLTIPS[matches[0]]) {
return COMMAND_TOOLTIPS[matches[0]];
}
}
return null;
}
export function resolveModelAlias(alias: string): 'local' | 'default' | 'fast' | 'complex' {
const map: Record<string, 'local' | 'default' | 'fast' | 'complex'> = {
local: 'local',