mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-06 08:18:39 +00:00
fix: terminal output not showing after command completion
Fix an issue where background running terminals that complete their execution do not report the final output of their command. Previously, output was reported while the command was active, but after termination the remaining output was not provided within the 'inactive terminals' section of environment details. - Implement terminal process queue system to track completed processes - Store command and output retrieval state per process - Add helper methods to manage the process queue efficiently - Update getEnvironmentDetails to properly display output from completed processes Signed-off-by: Eric Wheeler <roo-code@z.ewheeler.org>
This commit is contained in:
parent
24d8ef91ce
commit
25e46a244d
3 changed files with 84 additions and 20 deletions
|
|
@ -3512,7 +3512,7 @@ export class Cline {
|
|||
// terminals are cool, let's retrieve their output
|
||||
terminalDetails += "\n\n# Actively Running Terminals"
|
||||
for (const busyTerminal of busyTerminals) {
|
||||
terminalDetails += `\n## Original command: \`${busyTerminal.lastCommand}\``
|
||||
terminalDetails += `\n## Original command: \`${busyTerminal.getLastCommand()}\``
|
||||
const newOutput = TerminalRegistry.getUnretrievedOutput(busyTerminal.id)
|
||||
if (newOutput) {
|
||||
terminalDetails += `\n### New Output\n${newOutput}`
|
||||
|
|
@ -3521,24 +3521,40 @@ export class Cline {
|
|||
}
|
||||
}
|
||||
}
|
||||
// only show inactive terminals if there's output to show
|
||||
if (inactiveTerminals.length > 0) {
|
||||
const inactiveTerminalOutputs = new Map<number, string>()
|
||||
for (const inactiveTerminal of inactiveTerminals) {
|
||||
const newOutput = TerminalRegistry.getUnretrievedOutput(inactiveTerminal.id)
|
||||
if (newOutput) {
|
||||
inactiveTerminalOutputs.set(inactiveTerminal.id, newOutput)
|
||||
}
|
||||
}
|
||||
if (inactiveTerminalOutputs.size > 0) {
|
||||
terminalDetails += "\n\n# Inactive Terminals"
|
||||
for (const [terminalId, newOutput] of inactiveTerminalOutputs) {
|
||||
const inactiveTerminal = inactiveTerminals.find((t) => t.id === terminalId)
|
||||
if (inactiveTerminal) {
|
||||
terminalDetails += `\n## ${inactiveTerminal.lastCommand}`
|
||||
terminalDetails += `\n### New Output\n${newOutput}`
|
||||
|
||||
// First check if any inactive terminals have completed processes with output
|
||||
const terminalsWithOutput = inactiveTerminals.filter((terminal) => {
|
||||
const completedProcesses = terminal.getProcessesWithOutput()
|
||||
return completedProcesses.length > 0
|
||||
})
|
||||
|
||||
// Only add the header if there are terminals with output
|
||||
if (terminalsWithOutput.length > 0) {
|
||||
terminalDetails += "\n\n# Inactive Terminals with Completed Process Output"
|
||||
|
||||
// Process each terminal with output
|
||||
for (const inactiveTerminal of terminalsWithOutput) {
|
||||
let terminalOutputs: string[] = []
|
||||
|
||||
// Get output from completed processes queue
|
||||
const completedProcesses = inactiveTerminal.getProcessesWithOutput()
|
||||
for (const process of completedProcesses) {
|
||||
const output = process.getUnretrievedOutput()
|
||||
if (output) {
|
||||
terminalOutputs.push(`Command: \`${process.command}\`\n${output}`)
|
||||
}
|
||||
}
|
||||
|
||||
// Clean the queue after retrieving output
|
||||
inactiveTerminal.cleanCompletedProcessQueue()
|
||||
|
||||
// Add this terminal's outputs to the details
|
||||
if (terminalOutputs.length > 0) {
|
||||
terminalDetails += `\n## Terminal ${inactiveTerminal.id}`
|
||||
terminalOutputs.forEach((output, index) => {
|
||||
terminalDetails += `\n### New Output\n${output}`
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,19 +5,18 @@ import { ExitCodeDetails, mergePromise, TerminalProcess, TerminalProcessResultPr
|
|||
export class Terminal {
|
||||
public terminal: vscode.Terminal
|
||||
public busy: boolean
|
||||
public lastCommand: string
|
||||
public id: number
|
||||
private stream?: AsyncIterable<string>
|
||||
public running: boolean
|
||||
private streamClosed: boolean
|
||||
public process?: TerminalProcess
|
||||
public taskId?: string
|
||||
public completedProcesses: TerminalProcess[] = []
|
||||
|
||||
constructor(id: number, terminal: vscode.Terminal) {
|
||||
this.id = id
|
||||
this.terminal = terminal
|
||||
this.busy = false
|
||||
this.lastCommand = ""
|
||||
this.running = false
|
||||
this.streamClosed = false
|
||||
}
|
||||
|
|
@ -68,18 +67,56 @@ export class Terminal {
|
|||
this.running = false
|
||||
|
||||
if (this.process) {
|
||||
// Add to the front of the queue (most recent first)
|
||||
if (this.process.hasUnretrievedOutput()) {
|
||||
this.completedProcesses.unshift(this.process)
|
||||
}
|
||||
|
||||
this.process.emit("shell_execution_complete", this.id, exitDetails)
|
||||
this.process = undefined
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last executed command
|
||||
* @returns The last command string or empty string if none
|
||||
*/
|
||||
public getLastCommand(): string {
|
||||
// Return the command from the active process or the most recent process in the queue
|
||||
if (this.process) {
|
||||
return this.process.command || ""
|
||||
} else if (this.completedProcesses.length > 0) {
|
||||
return this.completedProcesses[0].command || ""
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans the process queue by removing processes that no longer have unretrieved output
|
||||
*/
|
||||
public cleanCompletedProcessQueue(): void {
|
||||
this.completedProcesses = this.completedProcesses.filter((process) => process.hasUnretrievedOutput())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all processes with unretrieved output
|
||||
* @returns Array of processes with unretrieved output
|
||||
*/
|
||||
public getProcessesWithOutput(): TerminalProcess[] {
|
||||
// Clean the queue first to remove any processes without output
|
||||
this.cleanCompletedProcessQueue()
|
||||
return [...this.completedProcesses]
|
||||
}
|
||||
|
||||
public runCommand(command: string): TerminalProcessResultPromise {
|
||||
this.busy = true
|
||||
this.lastCommand = command
|
||||
|
||||
// Create process immediately
|
||||
const process = new TerminalProcess(this)
|
||||
|
||||
// Store the command on the process for reference
|
||||
process.command = command
|
||||
|
||||
// Set process on terminal
|
||||
this.process = process
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ export class TerminalProcess extends EventEmitter<TerminalProcessEvents> {
|
|||
private fullOutput: string = ""
|
||||
private lastRetrievedIndex: number = 0
|
||||
isHot: boolean = false
|
||||
command: string = ""
|
||||
constructor(terminal: Terminal) {
|
||||
super()
|
||||
|
||||
|
|
@ -155,6 +156,7 @@ export class TerminalProcess extends EventEmitter<TerminalProcessEvents> {
|
|||
private hotTimer: NodeJS.Timeout | null = null
|
||||
|
||||
async run(command: string) {
|
||||
this.command = command
|
||||
const terminal = this.terminalInfo.terminal
|
||||
|
||||
if (terminal.shellIntegration && terminal.shellIntegration.executeCommand) {
|
||||
|
|
@ -332,6 +334,15 @@ export class TerminalProcess extends EventEmitter<TerminalProcessEvents> {
|
|||
this.emit("continue")
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this process has unretrieved output
|
||||
* @returns true if there is output that hasn't been fully retrieved yet
|
||||
*/
|
||||
hasUnretrievedOutput(): boolean {
|
||||
// If the process is still active or has unretrieved content, return true
|
||||
return this.lastRetrievedIndex < this.fullOutput.length
|
||||
}
|
||||
|
||||
// Returns complete lines with their carriage returns.
|
||||
// The final line may lack a carriage return if the program didn't send one.
|
||||
getUnretrievedOutput(): string {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue