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:
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user