diff --git a/src/components/ai/CopilotPanel.vue b/src/components/ai/CopilotPanel.vue index a77756d..48a88bd 100644 --- a/src/components/ai/CopilotPanel.vue +++ b/src/components/ai/CopilotPanel.vue @@ -156,11 +156,30 @@ async function launchPreset(preset: LaunchPreset): Promise { if (!shell) return; selectedShell.value = shell; await launch(); - // After shell spawns, send the preset command + // Wait for the shell prompt before sending the command. + // Poll the scrollback for a prompt indicator (PS>, $, #, %, >) if (sessionId && connected.value) { - setTimeout(() => { - invoke("pty_write", { sessionId, data: preset.command + "\n" }).catch(() => {}); - }, 300); + const maxWait = 5000; + const start = Date.now(); + const poll = setInterval(async () => { + if (Date.now() - start > maxWait) { + clearInterval(poll); + // Send anyway after timeout + invoke("pty_write", { sessionId, data: preset.command + "\r" }).catch(() => {}); + return; + } + try { + const lines = await invoke("mcp_terminal_read", { sessionId, lines: 3 }); + const lastLine = lines.split("\n").pop()?.trim() || ""; + // Detect common shell prompts + if (lastLine.endsWith("$") || lastLine.endsWith("#") || lastLine.endsWith("%") || lastLine.endsWith(">") || lastLine.endsWith("PS>")) { + clearInterval(poll); + invoke("pty_write", { sessionId, data: preset.command + "\r" }).catch(() => {}); + } + } catch { + // Scrollback not ready yet, keep polling + } + }, 200); } }