feat: Add Claude Code terminal integration to dashboard

- Add embedded Claude Code terminal with xterm.js for full CLI experience
- Create WebSocket PTY backend for real-time terminal communication
- Add terminal status endpoint to check CLI availability
- Update dashboard to use Claude Code terminal instead of API chat
- Add optimization control panel with start/stop/validate actions
- Add study context provider for global state management
- Update frontend with new dependencies (xterm.js addons)
- Comprehensive README documentation for all new features

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Antoine
2025-12-04 15:02:13 -05:00
parent 8cbdbcad78
commit 9eed4d81eb
23 changed files with 5060 additions and 339 deletions

View File

@@ -2,6 +2,56 @@ import { StudyListResponse, HistoryResponse, PruningResponse, StudyStatus } from
const API_BASE = '/api';
export interface OptimizationControlResponse {
success: boolean;
message: string;
pid?: number;
}
export interface ReadmeResponse {
content: string;
path: string;
}
export interface ReportResponse {
content: string;
generated_at?: string;
}
export interface ConfigResponse {
config: Record<string, any>;
objectives: Array<{
name: string;
direction: string;
weight?: number;
target?: number;
units?: string;
}>;
design_variables: Array<{
name: string;
min: number;
max: number;
baseline?: number;
units?: string;
}>;
constraints?: Array<{
name: string;
type: string;
max_value?: number;
min_value?: number;
units?: string;
}>;
}
export interface ProcessStatus {
is_running: boolean;
pid?: number;
start_time?: string;
iteration?: number;
fea_count?: number;
nn_count?: number;
}
class ApiClient {
async getStudies(): Promise<StudyListResponse> {
const response = await fetch(`${API_BASE}/optimization/studies`);
@@ -37,12 +87,24 @@ class ApiClient {
return response.json();
}
async getStudyReport(studyId: string): Promise<{ content: string }> {
async getStudyReport(studyId: string): Promise<ReportResponse> {
const response = await fetch(`${API_BASE}/optimization/studies/${studyId}/report`);
if (!response.ok) throw new Error('Failed to fetch report');
return response.json();
}
async getStudyReadme(studyId: string): Promise<ReadmeResponse> {
const response = await fetch(`${API_BASE}/optimization/studies/${studyId}/readme`);
if (!response.ok) throw new Error('Failed to fetch README');
return response.json();
}
async getStudyConfig(studyId: string): Promise<ConfigResponse> {
const response = await fetch(`${API_BASE}/optimization/studies/${studyId}/config`);
if (!response.ok) throw new Error('Failed to fetch config');
return response.json();
}
async getConsoleOutput(studyId: string, lines: number = 200): Promise<{
lines: string[];
total_lines: number;
@@ -56,16 +118,81 @@ class ApiClient {
return response.json();
}
// Future endpoints for control
async startOptimization(studyId: string): Promise<void> {
const response = await fetch(`${API_BASE}/optimization/studies/${studyId}/start`, { method: 'POST' });
if (!response.ok) throw new Error('Failed to start optimization');
async getProcessStatus(studyId: string): Promise<ProcessStatus> {
const response = await fetch(`${API_BASE}/optimization/studies/${studyId}/process`);
if (!response.ok) throw new Error('Failed to fetch process status');
return response.json();
}
async stopOptimization(studyId: string): Promise<void> {
const response = await fetch(`${API_BASE}/optimization/studies/${studyId}/stop`, { method: 'POST' });
if (!response.ok) throw new Error('Failed to stop optimization');
// Control operations
async startOptimization(studyId: string, options?: {
freshStart?: boolean;
maxIterations?: number;
feaBatchSize?: number;
tuneTrials?: number;
ensembleSize?: number;
patience?: number;
}): Promise<OptimizationControlResponse> {
const response = await fetch(`${API_BASE}/optimization/studies/${studyId}/start`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(options || {}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.detail || 'Failed to start optimization');
}
return response.json();
}
async stopOptimization(studyId: string): Promise<OptimizationControlResponse> {
const response = await fetch(`${API_BASE}/optimization/studies/${studyId}/stop`, {
method: 'POST',
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.detail || 'Failed to stop optimization');
}
return response.json();
}
async validateOptimization(studyId: string, options?: {
topN?: number;
}): Promise<OptimizationControlResponse> {
const response = await fetch(`${API_BASE}/optimization/studies/${studyId}/validate`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(options || {}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.detail || 'Failed to start validation');
}
return response.json();
}
async generateReport(studyId: string): Promise<ReportResponse> {
const response = await fetch(`${API_BASE}/optimization/studies/${studyId}/report/generate`, {
method: 'POST',
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.detail || 'Failed to generate report');
}
return response.json();
}
// Optuna dashboard
async launchOptunaDashboard(studyId: string): Promise<{ url: string; pid: number }> {
const response = await fetch(`${API_BASE}/optimization/studies/${studyId}/optuna-dashboard`, {
method: 'POST',
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.detail || 'Failed to launch Optuna dashboard');
}
return response.json();
}
}
export const apiClient = new ApiClient();
export const apiClient = new ApiClient();