codeplot
Version:
Interactive CLI tool for feature planning and ADR generation using Gemini 2.5 Pro
197 lines (175 loc) • 6.22 kB
JSX
import React, { useState, useEffect } from 'react';
import { Box, Text, useApp } from 'ink';
import ChatView from './ChatView.jsx';
import InitializationView from './InitializationView.jsx';
import WorkflowSelector from './WorkflowSelector.jsx';
import { logger } from '../utils/logger.js';
const App = ({ featureArchitect }) => {
const { exit } = useApp();
const [appState, setAppState] = useState('initializing'); // initializing, awaiting_workflow_selection, planning, completed, error
const [statusMessage, setStatusMessage] = useState('Starting Codeplot...');
const [errorMessage, setErrorMessage] = useState(null);
const [repomixSummary, setRepomixSummary] = useState(null);
const [aiAnalysis, setAiAnalysis] = useState('');
const [isStreamingAnalysis, setIsStreamingAnalysis] = useState(false);
const [streamingAnalysis, setStreamingAnalysis] = useState('');
useEffect(() => {
const initialize = async () => {
try {
logger.debug('App: Starting initialization with injected FeatureArchitect');
setStatusMessage('Initializing Feature Architect...');
setStatusMessage('Packing repository with repomix...');
// Pack the codebase
logger.debug('App: Packing codebase');
const packResult = await featureArchitect.repoPackager.pack();
setRepomixSummary(packResult.summary);
// Initialize AI chat session
try {
logger.debug('App: Initializing AI chat session');
const initResult = await featureArchitect.chatSession.initialize(packResult.content);
if (initResult.isNewSession && initResult.analysis) {
logger.debug('App: Got AI analysis for new session');
setAiAnalysis(initResult.analysis);
}
} catch (error) {
logger.errorWithStack(error, 'AI initialization failed');
if (!process.env.DEBUG) {
setErrorMessage('AI initialization failed. Check debug log for details.');
setAppState('error');
return;
}
}
// Switch to workflow selection
logger.debug('App: Initialization complete, switching to workflow selection state');
setAppState('awaiting_workflow_selection');
} catch (error) {
logger.errorWithStack(error, 'App initialization failed');
if (!process.env.DEBUG) {
setErrorMessage('Initialization failed. Run with --debug for details.');
setAppState('error');
}
}
};
initialize();
}, [featureArchitect]);
const handlePlanningComplete = async featureData => {
try {
logger.debug('App: Planning complete, starting session completion', { featureData });
setAppState('completing');
setStatusMessage('Finalizing session...');
// Complete the session through FeatureArchitect
const result = await featureArchitect.completeSession(featureData);
logger.info('App: Session completed successfully', { adrPath: result.adrPath });
setStatusMessage(`✅ ADR generated: ${result.adrPath}`);
setAppState('completed');
// Auto-exit after a brief moment
setTimeout(() => {
logger.debug('App: Auto-exiting application');
exit();
}, 2000);
} catch (error) {
logger.errorWithStack(error, 'Session completion failed');
if (!process.env.DEBUG) {
setErrorMessage('Session completion failed. Check debug log for details.');
setAppState('error');
}
}
};
const handleError = error => {
logger.errorWithStack(error, 'App: Handled error from child component');
if (!process.env.DEBUG) {
setErrorMessage('An error occurred. Run with --debug for details.');
setAppState('error');
}
};
if (appState === 'error') {
return (
<Box flexDirection="column" padding={1}>
<Box borderStyle="single" borderColor="red" padding={1}>
<Text color="red" bold>
❌ Error
</Text>
</Box>
<Box padding={1}>
<Text color="red">{errorMessage}</Text>
</Box>
<Box padding={1}>
<Text color="gray">Debug log: {logger.getLogFilePath()}</Text>
</Box>
<Box padding={1}>
<Text color="gray">Press Ctrl+C to exit</Text>
</Box>
</Box>
);
}
if (appState === 'initializing') {
return (
<InitializationView
statusMessage={statusMessage}
repomixSummary={repomixSummary}
aiAnalysis={aiAnalysis}
isStreamingAnalysis={isStreamingAnalysis}
streamingAnalysis={streamingAnalysis}
/>
);
}
if (appState === 'completing') {
return (
<Box flexDirection="column" padding={1}>
<Box borderStyle="single" padding={1}>
<Text color="blue" bold>
📊 Codeplot
</Text>
<Text color="gray"> - AI-powered feature planning</Text>
</Box>
<Box padding={1}>
<Text color="yellow">🔄 {statusMessage}</Text>
</Box>
</Box>
);
}
if (appState === 'completed') {
return (
<Box flexDirection="column" padding={1}>
<Box borderStyle="single" borderColor="green" padding={1}>
<Text color="green" bold>
🎉 Feature Planning Completed!
</Text>
</Box>
<Box padding={1}>
<Text color="green">{statusMessage}</Text>
</Box>
<Box padding={1}>
<Text color="gray">Exiting...</Text>
</Box>
</Box>
);
}
if (appState === 'awaiting_workflow_selection') {
return (
<WorkflowSelector
onSelect={item => {
featureArchitect.agentOrchestrator.setWorkflow(item.value);
setAppState('planning');
}}
/>
);
}
if (appState === 'planning' && featureArchitect) {
return (
<ChatView
chatSession={featureArchitect.chatSession}
onComplete={handlePlanningComplete}
onError={handleError}
repomixSummary={repomixSummary}
aiAnalysis={aiAnalysis}
/>
);
}
return (
<Box padding={1}>
<Text color="gray">Loading...</Text>
</Box>
);
};
export default App;