Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"prepare": "lefthook install || true"
},
"dependencies": {
"ccstatusline": "workspace:*",
"ink": "^6.6.0",
"ink-select-input": "^6.2.0",
"ink-text-input": "^6.0.0",
Expand Down
85 changes: 83 additions & 2 deletions src/tui/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ import {
AboutScreen,
FeedbackScreen,
TeamModeScreen,
StatusLineMainMenu,
MultiVariantSelector,
StatusLineConfigScreen,
StatusLineQuickInstall,
} from './screens/index.js';

// Import UI components
Expand Down Expand Up @@ -235,6 +239,7 @@ export const App: React.FC<AppProps> = ({
const [selectedVariant, setSelectedVariant] = useState<(VariantMeta & { wrapperPath: string }) | null>(null);
const [doctorReport, setDoctorReport] = useState<DoctorReportItem[]>([]);
const [apiKeyDetectedFrom, setApiKeyDetectedFrom] = useState<string | null>(null);
const [selectedVariants, setSelectedVariants] = useState<string[]>([]);

// Include experimental providers to show "Coming Soon" in UI
const providerList = useMemo(() => providers.listProviders(true), [providers]);
Expand Down Expand Up @@ -343,6 +348,19 @@ export const App: React.FC<AppProps> = ({
case 'doctor':
setScreen('home');
break;
// Status Line screens navigation
case 'statusline-main':
setScreen('home');
break;
case 'statusline-variant-select':
setScreen('statusline-main');
break;
case 'statusline-config':
setScreen('statusline-main');
break;
case 'statusline-quick-install':
setScreen('statusline-main');
break;
// Feedback screen - home
case 'feedback':
setScreen('home');
Expand All @@ -358,7 +376,7 @@ export const App: React.FC<AppProps> = ({
});

useEffect(() => {
if (screen === 'manage') {
if (screen === 'manage' || screen === 'statusline-main' || screen.startsWith('statusline-')) {
setVariants(core.listVariants(rootDir));
}
}, [screen, rootDir, core]);
Expand Down Expand Up @@ -550,6 +568,10 @@ export const App: React.FC<AppProps> = ({
if (value === 'manage') setScreen('manage');
if (value === 'updateAll') setScreen('updateAll');
if (value === 'doctor') setScreen('doctor');
if (value === 'statusline') {
setSelectedVariants([]);
setScreen('statusline-main');
}
if (value === 'about') setScreen('about');
if (value === 'feedback') setScreen('feedback');
if (value === 'exit') setScreen('exit');
Expand Down Expand Up @@ -1266,7 +1288,12 @@ export const App: React.FC<AppProps> = ({
}

if (screen === 'doctor') {
return <DiagnosticsScreen report={doctorReport} onDone={() => setScreen('home')} />;
return (
<DiagnosticsScreen
report={doctorReport}
onDone={() => setScreen('home')}
/>
);
}

if (screen === 'about') {
Expand All @@ -1277,6 +1304,60 @@ export const App: React.FC<AppProps> = ({
return <FeedbackScreen onBack={() => setScreen('home')} />;
}

// Status Line Main Menu
if (screen === 'statusline-main') {
return (
<StatusLineMainMenu
variants={variants}
onConfigureVariants={(variantNames) => {
setSelectedVariants(variantNames);
setScreen('statusline-variant-select');
}}
onQuickInstall={() => setScreen('statusline-quick-install')}
onBack={() => setScreen('home')}
/>
);
}

// Status Line Variant Selector (for configure path)
if (screen === 'statusline-variant-select') {
return (
<MultiVariantSelector
variants={variants}
selectedVariants={selectedVariants}
onSelectionChange={setSelectedVariants}
onSubmit={() => {
if (selectedVariants.length > 0) {
setScreen('statusline-config');
}
}}
onBack={() => setScreen('statusline-main')}
allowMultiple={true}
/>
);
}

// Status Line Configuration Screen (ccstatusline TUI)
if (screen === 'statusline-config') {
return (
<StatusLineConfigScreen
variants={variants}
selectedVariants={selectedVariants}
onBack={() => setScreen('statusline-main')}
/>
);
}

// Status Line Quick Install Screen
if (screen === 'statusline-quick-install') {
return (
<StatusLineQuickInstall
variants={variants}
onBack={() => setScreen('statusline-main')}
/>
);
}

return (
<Frame>
<Header title="CC-MIRROR" subtitle="Unknown state" />
Expand Down
40 changes: 36 additions & 4 deletions src/tui/screens/DiagnosticsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
* Diagnostics/Doctor Screen
*/

import React from 'react';
import React, { useState } from 'react';
import { Box, Text, useInput } from 'ink';
import { ScreenLayout } from '../components/ui/ScreenLayout.js';
import { HealthCheck } from '../components/ui/Progress.js';
import { EmptyVariantsArt } from '../components/ui/AsciiArt.js';
import { colors, keyHints } from '../components/ui/theme.js';
import { SelectMenu } from '../components/ui/Menu.js';
import type { MenuItem } from '../components/ui/types.js';

interface HealthCheckItem {
name: string;
Expand All @@ -24,13 +26,31 @@ interface DiagnosticsScreenProps {
onDone: () => void;
}

export const DiagnosticsScreen: React.FC<DiagnosticsScreenProps> = ({ report, onDone }) => {
export const DiagnosticsScreen: React.FC<DiagnosticsScreenProps> = ({
report,
onDone,
}) => {
const [selectedIndex, setSelectedIndex] = useState(0);

// Handle ESC key for back navigation
useInput((input, key) => {
if (key.return || key.escape) {
if (key.escape) {
onDone();
}
});

// Build menu items
const menuItems: MenuItem[] = [
{ value: 'done', label: 'Back to Home', icon: 'back' },
];

// Handle menu selection
const handleMenuSelect = (value: string) => {
if (value === 'done') {
onDone();
}
};

const healthyCount = report.filter((r) => r.ok).length;
const issueCount = report.length - healthyCount;

Expand All @@ -42,7 +62,7 @@ export const DiagnosticsScreen: React.FC<DiagnosticsScreenProps> = ({ report, on
title="Diagnostics"
subtitle="Health check results"
borderColor={borderColor}
hints={[keyHints.select + ' Back to Home']}
hints={[keyHints.select + ' Navigate', 'Enter Select', keyHints.back]}
>
<Box flexDirection="column" marginY={1}>
{report.length === 0 ? (
Expand All @@ -59,6 +79,18 @@ export const DiagnosticsScreen: React.FC<DiagnosticsScreenProps> = ({ report, on
<Text color={colors.textMuted}> | </Text>
<Text color={issueCount > 0 ? colors.warning : colors.textMuted}>Issues: {issueCount}</Text>
</Box>

<Box marginTop={2} flexDirection="column">
<Text color={colors.textMuted} bold={true}>Actions</Text>
<Box marginTop={1}>
<SelectMenu
items={menuItems}
selectedIndex={selectedIndex}
onIndexChange={setSelectedIndex}
onSelect={handleMenuSelect}
/>
</Box>
</Box>
</ScreenLayout>
);
};
1 change: 1 addition & 0 deletions src/tui/screens/HomeScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export const HomeScreen: React.FC<HomeScreenProps> = ({ onSelect }) => {
{ value: 'manage', label: 'Manage Variants', description: 'Update, remove, or inspect' },
{ value: 'updateAll', label: 'Update All', description: 'Sync all variants to latest' },
{ value: 'doctor', label: 'Diagnostics', description: 'Health check all variants' },
{ value: 'statusline', label: 'Status Line', description: 'Configure ccstatusline for variants' },
{ value: 'about', label: 'About', description: 'Learn how CC-MIRROR works' },
{ value: 'feedback', label: 'Feedback', description: 'Links, issues, and contributions' },
{ value: 'exit', label: 'Until next time', icon: 'exit' },
Expand Down
Loading