From 2962282b4f2a2eaf8dd2618f0b4d2f99697ff197 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Tue, 4 Nov 2025 13:25:20 +0000 Subject: [PATCH] fix: improve terminal output capture for first command in new terminals - Add 200ms delay for first command in newly created terminals to ensure shell integration is ready - Improve stream data handling to recover from missing shell integration markers - Track whether terminal is newly created and if first command has been executed - Add fallback logic to treat accumulated data as output if markers aren't found after 500 chars This fixes the race condition where the first command's output might not be captured properly in freshly created terminals, especially with chained commands. Fixes #9019 --- src/integrations/terminal/Terminal.ts | 15 ++++++++++++- src/integrations/terminal/TerminalProcess.ts | 22 +++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/integrations/terminal/Terminal.ts b/src/integrations/terminal/Terminal.ts index 8bf2072f3d..d32578d916 100644 --- a/src/integrations/terminal/Terminal.ts +++ b/src/integrations/terminal/Terminal.ts @@ -9,6 +9,8 @@ import { mergePromise } from "./mergePromise" export class Terminal extends BaseTerminal { public terminal: vscode.Terminal + private isNewlyCreated: boolean = false + private firstCommandExecuted: boolean = false public cmdCounter: number = 0 @@ -19,6 +21,9 @@ export class Terminal extends BaseTerminal { const iconPath = new vscode.ThemeIcon("rocket") this.terminal = terminal ?? vscode.window.createTerminal({ cwd, name: "Roo Code", iconPath, env }) + // Mark if this is a newly created terminal + this.isNewlyCreated = terminal === undefined + if (Terminal.getTerminalZdotdir()) { ShellIntegrationManager.terminalTmpDirs.set(id, env.ZDOTDIR) } @@ -71,10 +76,18 @@ export class Terminal extends BaseTerminal { pWaitFor(() => this.terminal.shellIntegration !== undefined, { timeout: Terminal.getShellIntegrationTimeout(), }) - .then(() => { + .then(async () => { // Clean up temporary directory if shell integration is available, zsh did its job: ShellIntegrationManager.zshCleanupTmpDir(this.id) + // For newly created terminals on the first command, add a small delay + // to ensure the shell integration stream is fully ready + if (this.isNewlyCreated && !this.firstCommandExecuted) { + console.log(`[Terminal ${this.id}] Adding delay for first command in new terminal`) + await new Promise((resolve) => setTimeout(resolve, 200)) + this.firstCommandExecuted = true + } + // Run the command in the terminal process.run(command) }) diff --git a/src/integrations/terminal/TerminalProcess.ts b/src/integrations/terminal/TerminalProcess.ts index eb0424fe8d..be3aac2605 100644 --- a/src/integrations/terminal/TerminalProcess.ts +++ b/src/integrations/terminal/TerminalProcess.ts @@ -158,6 +158,7 @@ export class TerminalProcess extends BaseTerminalProcess { let preOutput = "" let commandOutputStarted = false + let streamDataReceived = false /* * Extract clean output from raw accumulated output. FYI: @@ -171,6 +172,8 @@ export class TerminalProcess extends BaseTerminalProcess { // Process stream data for await (let data of stream) { + streamDataReceived = true + // Check for command output start marker if (!commandOutputStarted) { preOutput += data @@ -182,7 +185,24 @@ export class TerminalProcess extends BaseTerminalProcess { this.fullOutput = "" // Reset fullOutput when command actually starts this.emit("line", "") // Trigger UI to proceed } else { - continue + // For the first chunk of data, if we don't see markers yet, + // wait a bit more to see if they arrive in the next chunk + if (!streamDataReceived && preOutput.length < 100) { + continue + } + // If we have accumulated enough preOutput without finding markers, + // treat it as command output to avoid losing data + if (preOutput.length > 500) { + console.warn( + `[Terminal Process] No start markers found after ${preOutput.length} chars, treating as output`, + ) + commandOutputStarted = true + data = preOutput + this.fullOutput = "" + this.emit("line", "") + } else { + continue + } } }