termcode
Version:
Superior terminal AI coding agent with enterprise-grade security, intelligent error recovery, performance monitoring, and plugin system - Advanced Claude Code alternative
148 lines (147 loc) • 6.49 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import React, { useState, useEffect } from 'react';
import { Box, Text } from 'ink';
import SelectInput from 'ink-select-input';
export const CommandPalette = ({ onClose, onExecute, providers, currentProvider, currentModel, }) => {
const [filter, setFilter] = useState('');
// Build command palette items
const commands = [
// Provider switching
...providers.map(provider => ({
id: `provider-${provider}`,
title: `Switch to ${provider}`,
description: `Change provider to ${provider}`,
category: 'provider',
action: () => onExecute(`/provider ${provider}`),
})),
// Common models for each provider
{
id: 'model-gpt4o',
title: 'GPT-4o',
description: 'OpenAI\'s flagship model',
category: 'model',
action: () => onExecute('/model gpt-4o'),
},
{
id: 'model-claude-sonnet',
title: 'Claude 3.5 Sonnet',
description: 'Anthropic\'s flagship model',
category: 'model',
action: () => onExecute('/model claude-3-5-sonnet-20241022'),
},
{
id: 'model-grok',
title: 'Grok Beta',
description: 'xAI\'s conversational model',
category: 'model',
action: () => onExecute('/model grok-beta'),
},
// Actions
{
id: 'action-test',
title: 'Run Tests',
description: 'Execute project test suite',
category: 'test',
action: () => onExecute('test'),
},
{
id: 'action-lint',
title: 'Run Linter',
description: 'Check code style and quality',
category: 'test',
action: () => onExecute('lint'),
},
{
id: 'action-build',
title: 'Run Build',
description: 'Compile and build project',
category: 'test',
action: () => onExecute('build'),
},
// Git actions
{
id: 'git-rollback',
title: 'Rollback Changes',
description: 'Discard all changes and return to main',
category: 'git',
action: () => onExecute('rollback'),
},
{
id: 'git-merge',
title: 'Merge to Main',
description: 'Merge current branch to main',
category: 'git',
action: () => onExecute('merge'),
},
// Information commands
{
id: 'action-whoami',
title: 'Session Info',
description: 'Show current session details',
category: 'action',
action: () => onExecute('/whoami'),
},
{
id: 'action-health',
title: 'Health Check',
description: 'Check provider connectivity',
category: 'action',
action: () => onExecute('/health'),
},
{
id: 'action-budget',
title: 'Budget Status',
description: 'Show usage and costs',
category: 'action',
action: () => onExecute('/budget'),
},
];
// Filter commands based on search
const filteredCommands = commands.filter(cmd => cmd.title.toLowerCase().includes(filter.toLowerCase()) ||
cmd.description.toLowerCase().includes(filter.toLowerCase()));
// Group by category
const groupedCommands = filteredCommands.reduce((groups, cmd) => {
if (!groups[cmd.category]) {
groups[cmd.category] = [];
}
groups[cmd.category].push(cmd);
return groups;
}, {});
// Convert to SelectInput format
const selectItems = Object.entries(groupedCommands).flatMap(([category, items]) => [
// Category header
{
label: `── ${category.toUpperCase()} ──`,
value: `header-${category}`,
disabled: true,
},
// Category items
...items.map(item => ({
label: `${item.title}`,
value: item.id,
})),
]);
const handleSelect = (item) => {
if (item.value.startsWith('header-')) {
return; // Ignore category headers
}
const command = commands.find(cmd => cmd.id === item.value);
if (command) {
command.action();
}
onClose();
};
// Handle escape key to close
useEffect(() => {
const handleKeyPress = (str, key) => {
if (key.escape) {
onClose();
}
};
process.stdin.on('keypress', handleKeyPress);
return () => {
process.stdin.off('keypress', handleKeyPress);
};
}, [onClose]);
return (_jsxs(Box, { position: "absolute", top: 2, left: 2, right: 2, bottom: 2, borderStyle: "double", borderColor: "blue", backgroundColor: "black", flexDirection: "column", children: [_jsxs(Box, { paddingX: 2, paddingY: 1, borderStyle: "single", borderTop: false, borderLeft: false, borderRight: false, children: [_jsx(Text, { color: "blue", bold: true, children: "\u26A1 Command Palette" }), _jsx(Box, { marginLeft: "auto", children: _jsx(Text, { color: "gray", dimColor: true, children: "ESC to close" }) })] }), _jsx(Box, { paddingX: 2, paddingBottom: 1, children: _jsxs(Text, { color: "gray", children: ["Provider: ", _jsx(Text, { color: "cyan", children: currentProvider }), " \u2022 Model: ", _jsx(Text, { color: "white", children: currentModel })] }) }), _jsx(Box, { paddingX: 2, paddingY: 1, flexGrow: 1, children: selectItems.length === 0 ? (_jsx(Text, { color: "gray", dimColor: true, children: "No commands found" })) : (_jsx(SelectInput, { items: selectItems, onSelect: handleSelect, indicatorComponent: ({ isSelected }) => (_jsx(Box, { marginRight: 1, children: _jsx(Text, { color: isSelected ? 'blue' : 'gray', children: isSelected ? '▶' : ' ' }) })), itemComponent: ({ isSelected, label }) => (_jsx(Text, { color: isSelected ? 'blue' : 'white', children: label })) })) }), _jsx(Box, { paddingX: 2, paddingY: 1, borderStyle: "single", borderBottom: false, borderLeft: false, borderRight: false, justifyContent: "center", children: _jsx(Text, { color: "gray", dimColor: true, children: "\u2191\u2193 Navigate \u2022 Enter: Execute \u2022 ESC: Cancel" }) })] }));
};