From 5dce5e093cc82724b1befca89bc73568beb04466 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 25 Dec 2025 17:18:03 +0000 Subject: [PATCH] Fix TypeScript compilation errors after merge - Update startDashboard to accept options object instead of positional args - Add spawn modal element references to types.ts and components.ts - Add spawn modal functions (openSpawnModal, closeSpawnModal, spawnAgent, fetchSpawnedAgents) - Align element IDs with HTML (spawn-agent-name, spawn-agent-cli, etc.) --- src/dashboard/frontend/components.ts | 101 +++++++++++++++++++++++++++ src/dashboard/frontend/types.ts | 13 ++-- src/dashboard/server.ts | 12 +++- src/dashboard/start.ts | 7 +- 4 files changed, 125 insertions(+), 8 deletions(-) diff --git a/src/dashboard/frontend/components.ts b/src/dashboard/frontend/components.ts index 2626d9fe0..0749e4879 100644 --- a/src/dashboard/frontend/components.ts +++ b/src/dashboard/frontend/components.ts @@ -49,6 +49,16 @@ export function initElements(): DOMElements { threadSendBtn: document.getElementById('thread-send-btn') as HTMLButtonElement, mentionAutocomplete: document.getElementById('mention-autocomplete')!, mentionAutocompleteList: document.getElementById('mention-autocomplete-list')!, + // Spawn modal elements + spawnAgentBtn: document.getElementById('spawn-agent-btn') as HTMLButtonElement, + spawnModalOverlay: document.getElementById('spawn-modal-overlay')!, + spawnModalClose: document.getElementById('spawn-modal-close') as HTMLButtonElement, + spawnAgentName: document.getElementById('spawn-agent-name') as HTMLInputElement, + spawnAgentCli: document.getElementById('spawn-agent-cli') as HTMLSelectElement, + spawnAgentModel: document.getElementById('spawn-agent-model') as HTMLInputElement, + spawnAgentTask: document.getElementById('spawn-agent-task') as HTMLTextAreaElement, + spawnModalCancel: document.getElementById('spawn-modal-cancel') as HTMLButtonElement, + spawnModalSubmit: document.getElementById('spawn-modal-submit') as HTMLButtonElement, }; return elements; } @@ -800,3 +810,94 @@ export function getCurrentMentionQuery(): string | null { return null; } + +// Track spawned agents +let spawnedAgents: string[] = []; + +/** + * Open the spawn agent modal + */ +export function openSpawnModal(): void { + elements.spawnModalOverlay.classList.add('visible'); + elements.spawnAgentName.value = ''; + elements.spawnAgentCli.value = 'claude'; + elements.spawnAgentModel.value = ''; + elements.spawnAgentTask.value = ''; + elements.spawnAgentName.focus(); +} + +/** + * Close the spawn agent modal + */ +export function closeSpawnModal(): void { + elements.spawnModalOverlay.classList.remove('visible'); +} + +/** + * Spawn a new agent via the API + */ +export async function spawnAgent(): Promise<{ success: boolean; error?: string }> { + const name = elements.spawnAgentName.value.trim(); + const cli = elements.spawnAgentCli.value || 'claude'; + const model = elements.spawnAgentModel.value.trim(); + const task = elements.spawnAgentTask.value.trim(); + + if (!name) { + return { success: false, error: 'Agent name is required' }; + } + + elements.spawnModalSubmit.disabled = true; + + try { + const response = await fetch('/api/spawn', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ name, cli, model, task }), + }); + + const result = await response.json(); + + if (response.ok && result.success) { + // Refresh spawned agents list + await fetchSpawnedAgents(); + + // Close modal after brief delay + setTimeout(() => { + closeSpawnModal(); + }, 500); + + return { success: true }; + } else { + throw new Error(result.error || 'Failed to spawn agent'); + } + } catch (err: any) { + return { success: false, error: err.message }; + } finally { + elements.spawnModalSubmit.disabled = false; + } +} + +/** + * Fetch list of spawned agents from API + */ +export async function fetchSpawnedAgents(): Promise { + try { + const response = await fetch('/api/spawned'); + const result = await response.json(); + + if (result.success && Array.isArray(result.agents)) { + spawnedAgents = result.agents.map((a: any) => a.name); + // Re-render agents to show spawned status + renderAgents(); + } + } catch (err) { + console.error('[UI] Failed to fetch spawned agents:', err); + } +} + +/** + * Check if an agent is spawned + */ +export function isSpawnedAgent(name: string): boolean { + return spawnedAgents.includes(name); +} diff --git a/src/dashboard/frontend/types.ts b/src/dashboard/frontend/types.ts index 0950ccecf..dd4ac76c0 100644 --- a/src/dashboard/frontend/types.ts +++ b/src/dashboard/frontend/types.ts @@ -93,14 +93,15 @@ export interface DOMElements { mentionAutocomplete: HTMLElement; mentionAutocompleteList: HTMLElement; // Spawn modal elements - spawnBtn: HTMLButtonElement; + spawnAgentBtn: HTMLButtonElement; spawnModalOverlay: HTMLElement; spawnModalClose: HTMLButtonElement; - spawnNameInput: HTMLInputElement; - spawnCliInput: HTMLInputElement; - spawnTaskInput: HTMLTextAreaElement; - spawnSubmitBtn: HTMLButtonElement; - spawnStatus: HTMLElement; + spawnAgentName: HTMLInputElement; + spawnAgentCli: HTMLSelectElement; + spawnAgentModel: HTMLInputElement; + spawnAgentTask: HTMLTextAreaElement; + spawnModalCancel: HTMLButtonElement; + spawnModalSubmit: HTMLButtonElement; } export interface SpawnedAgent { diff --git a/src/dashboard/server.ts b/src/dashboard/server.ts index 9ecfb5e3a..45ac49789 100644 --- a/src/dashboard/server.ts +++ b/src/dashboard/server.ts @@ -63,7 +63,17 @@ interface AgentSummary { context?: string; } -export async function startDashboard(port: number, dataDir: string, teamDir: string, dbPath?: string): Promise { +export interface DashboardOptions { + port: number; + dataDir: string; + teamDir: string; + dbPath?: string; + enableSpawner?: boolean; + projectRoot?: string; +} + +export async function startDashboard(options: DashboardOptions): Promise { + const { port, dataDir, teamDir, dbPath, enableSpawner, projectRoot } = options; console.log('Starting dashboard...'); console.log('__dirname:', __dirname); const publicDir = path.join(__dirname, 'public'); diff --git a/src/dashboard/start.ts b/src/dashboard/start.ts index 6cf26a6a1..ec8449394 100644 --- a/src/dashboard/start.ts +++ b/src/dashboard/start.ts @@ -13,4 +13,9 @@ console.log(`Starting dashboard for project: ${paths.projectRoot}`); console.log(`Data dir: ${paths.dataDir}`); console.log(`Database: ${paths.dbPath}`); -startDashboard(port, paths.dataDir, paths.teamDir, paths.dbPath).catch(console.error); +startDashboard({ + port, + dataDir: paths.dataDir, + teamDir: paths.teamDir, + dbPath: paths.dbPath, +}).catch(console.error);