From f9c4e2af35d77cb07e12b1f93c0d954cf5e0d323 Mon Sep 17 00:00:00 2001 From: Vantz Stockwell Date: Wed, 25 Mar 2026 00:37:35 -0400 Subject: [PATCH] fix: launch presets wait for shell prompt before sending command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Was sending the command after a blind 300ms delay with \n — too early for PowerShell startup banner, and \n caused a blank line before the command. Fix: poll mcp_terminal_read every 200ms until a prompt is detected ($, #, %, >, PS>), then send the command with \r (carriage return, not newline). Falls back to sending after 5s timeout. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/components/ai/CopilotPanel.vue | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) 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); } }