import { useState, useEffect } from 'react'; import { Terminal, CheckCircle, XCircle, Shield, History, ChevronDown } from 'lucide-react'; import { Button, Card, CardHeader, CardTitle, CardContent, Badge } from '@/components/ui'; import { Link } from 'react-router-dom'; import { checkKubectlInstalledCmd, listCommandExecutionsCmd, getClassifierRulesCmd, type KubectlStatus, type CommandExecution, type ClassifierRules, } from '@/lib/tauriCommands'; // ── Tier display config ─────────────────────────────────────────────────────── interface TierConfig { label: string; behavior: string; colorBg: string; colorBorder: string; colorHeading: string; colorText: string; badgeClass: string; tier: 1 | 2 | 3; } const TIER_CONFIG: TierConfig[] = [ { tier: 1, label: 'Tier 1', behavior: 'Auto-execute (Read-only)', colorBg: 'bg-green-50 dark:bg-green-950/30', colorBorder: 'border-green-200 dark:border-green-800', colorHeading: 'text-green-900 dark:text-green-300', colorText: 'text-green-800 dark:text-green-400', badgeClass: 'bg-green-100 text-green-700 border-green-300 dark:bg-green-900/40 dark:text-green-300 dark:border-green-700', }, { tier: 2, label: 'Tier 2', behavior: 'Require approval (Mutating)', colorBg: 'bg-yellow-50 dark:bg-yellow-950/30', colorBorder: 'border-yellow-200 dark:border-yellow-800', colorHeading: 'text-yellow-900 dark:text-yellow-300', colorText: 'text-yellow-800 dark:text-yellow-400', badgeClass: 'bg-yellow-100 text-yellow-700 border-yellow-300 dark:bg-yellow-900/40 dark:text-yellow-300 dark:border-yellow-700', }, { tier: 3, label: 'Tier 3', behavior: 'Always deny (Destructive)', colorBg: 'bg-red-50 dark:bg-red-950/30', colorBorder: 'border-red-200 dark:border-red-800', colorHeading: 'text-red-900 dark:text-red-300', colorText: 'text-red-800 dark:text-red-400', badgeClass: 'bg-red-100 text-red-700 border-red-300 dark:bg-red-900/40 dark:text-red-300 dark:border-red-700', }, ]; // ── Helper: build per-tier category groups from ClassifierRules ─────────────── interface CategoryGroup { label: string; commands: string[]; } function buildTier1Groups(rules: ClassifierRules): CategoryGroup[] { return [ { label: 'kubectl', commands: rules.tier1_kubectl.map((c) => `kubectl ${c}`) }, { label: 'systemctl', commands: rules.tier1_systemctl.map((c) => `systemctl ${c}`) }, { label: 'proxmox', commands: rules.tier1_proxmox.map((c) => ` ${c}`) }, { label: 'general', commands: rules.tier1_general }, ].filter((g) => g.commands.length > 0); } function buildTier2Groups(rules: ClassifierRules): CategoryGroup[] { return [ { label: 'kubectl', commands: rules.tier2_kubectl.map((c) => `kubectl ${c}`) }, { label: 'systemctl', commands: rules.tier2_systemctl.map((c) => `systemctl ${c}`) }, { label: 'proxmox', commands: rules.tier2_proxmox.map((c) => ` ${c}`) }, { label: 'general', commands: rules.tier2_general }, ].filter((g) => g.commands.length > 0); } function buildTier3Groups(rules: ClassifierRules): CategoryGroup[] { return [{ label: 'all', commands: rules.tier3 }]; } const PREVIEW_COUNT = 6; // ── Sub-components ──────────────────────────────────────────────────────────── function CommandChip({ cmd, colorText }: { cmd: string; colorText: string }) { return ( {cmd} ); } interface TierCardProps { config: TierConfig; groups: CategoryGroup[]; } function TierCard({ config, groups }: TierCardProps) { const [expanded, setExpanded] = useState(false); const allCommands = groups.flatMap((g) => g.commands); const total = allCommands.length; const previewCommands = allCommands.slice(0, PREVIEW_COUNT); const hasMore = total > PREVIEW_COUNT; return (
{config.label}
{config.behavior}
{(expanded ? allCommands : previewCommands).map((cmd) => ( ))}
{total}
{hasMore && ( )}
); } // ── Main component ──────────────────────────────────────────────────────────── export default function ShellExecution() { const [kubectlStatus, setKubectlStatus] = useState(null); const [executions, setExecutions] = useState([]); const [classifierRules, setClassifierRules] = useState(null); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(''); const loadKubectlStatus = async () => { try { const status = await checkKubectlInstalledCmd(); setKubectlStatus(status); } catch (err) { setError(String(err)); } }; const loadExecutions = async () => { setIsLoading(true); try { const data = await listCommandExecutionsCmd(); setExecutions(data); } catch (err) { setError(String(err)); } finally { setIsLoading(false); } }; const loadClassifierRules = async () => { try { const rules = await getClassifierRulesCmd(); setClassifierRules(rules); } catch { // Non-fatal — fall back to empty state; the tier cards will just show 0 commands } }; useEffect(() => { loadKubectlStatus(); loadExecutions(); loadClassifierRules(); }, []); const getTierBadge = (tier: number) => { const colors: Record = { 1: 'bg-green-100 text-green-700 border-green-300', 2: 'bg-yellow-100 text-yellow-700 border-yellow-300', 3: 'bg-red-100 text-red-700 border-red-300', }; return colors[tier] ?? colors[1]; }; const getStatusBadge = (status: string) => { const config: Record = { auto: { label: 'Auto-executed', color: 'bg-blue-100 text-blue-700 border-blue-300' }, approved: { label: 'Approved', color: 'bg-green-100 text-green-700 border-green-300' }, denied: { label: 'Denied', color: 'bg-red-100 text-red-700 border-red-300' }, }; return config[status] ?? config.auto; }; // Build grouped command lists for each tier (empty arrays when rules not loaded) const tier1Groups = classifierRules ? buildTier1Groups(classifierRules) : []; const tier2Groups = classifierRules ? buildTier2Groups(classifierRules) : []; const tier3Groups = classifierRules ? buildTier3Groups(classifierRules) : []; return (

Shell Execution

Configure and monitor autonomous shell command execution with intelligent safety controls

{error && (
{error}
)} {/* kubectl Status */} kubectl Status {kubectlStatus ? ( <>
{kubectlStatus.installed ? ( <> kubectl is installed ) : ( <> kubectl is not installed )}
{kubectlStatus.path && (
Path: {kubectlStatus.path}
)} {kubectlStatus.version && (
{kubectlStatus.version}
)} ) : (

Checking kubectl status...

)}
{/* Safety Architecture — driven by live classifier data */} Safety Architecture

Commands are automatically classified into three safety tiers. The lists below reflect the active classifier rules — they update whenever a rule is added or removed.

{!classifierRules && (

Loading classifier rules…

)} {TIER_CONFIG.map((cfg) => { const groups = cfg.tier === 1 ? tier1Groups : cfg.tier === 2 ? tier2Groups : tier3Groups; return ; })}
{/* Command Execution History */} Recent Command Executions ({executions.length}) {isLoading ? (

Loading...

) : executions.length === 0 ? (

No command executions yet

) : (
{executions.slice(0, 10).map((exec) => { const statusConfig = getStatusBadge(exec.approval_status); return (
{exec.command}
T{exec.tier} {statusConfig.label}
{exec.exit_code !== undefined && ( Exit: {exec.exit_code} )} {exec.execution_time_ms !== undefined && ( {exec.execution_time_ms}ms )} {new Date(exec.executed_at).toLocaleString()}
{exec.stdout && (
Show output
                          {exec.stdout}
                        
)}
); })}
)}
); }