fix: terminal process isolation between parallel Cline tasks

These changes ensure proper isolation by preventing terminal process
output from one Cline task appearing in another task's context when
multiple Cline instances are running in parallel.

- Add taskId parameter to TerminalRegistry.getTerminals to filter terminals by Cline task ID
- Update Cline.ts to use taskId-filtered terminals

Signed-off-by: Eric Wheeler <roo-code@z.ewheeler.org>
This commit is contained in:
Eric Wheeler 2025-03-07 12:48:30 -08:00
parent 25e46a244d
commit e27c6aadc1
3 changed files with 30 additions and 7 deletions

View file

@ -3472,8 +3472,8 @@ export class Cline {
details += "\n(No open tabs)"
}
const busyTerminals = TerminalRegistry.getTerminals(true)
const inactiveTerminals = TerminalRegistry.getTerminals(false)
const busyTerminals = TerminalRegistry.getTerminals(true, this.taskId)
const inactiveTerminals = TerminalRegistry.getTerminals(false, this.taskId)
if (busyTerminals.length > 0 && this.didEditFile) {
await delay(300) // delay after saving file to let terminals catch up
@ -3522,7 +3522,7 @@ export class Cline {
}
}
// First check if any inactive terminals have completed processes with output
// First check if any inactive terminals in this task have completed processes with output
const terminalsWithOutput = inactiveTerminals.filter((terminal) => {
const completedProcesses = terminal.getProcessesWithOutput()
return completedProcesses.length > 0

View file

@ -93,8 +93,19 @@ export class Terminal {
/**
* Cleans the process queue by removing processes that no longer have unretrieved output
* or don't belong to the current task
*/
public cleanCompletedProcessQueue(): void {
// If this terminal has no task ID, it's not associated with any active task
// In this case, we should remove all processes to prevent their output from appearing
// in any task's context
if (this.taskId === undefined) {
this.completedProcesses = []
return
}
// If the terminal is associated with a task, keep only processes with unretrieved output
// This ensures that when a task is active, it only sees output from its own processes
this.completedProcesses = this.completedProcesses.filter((process) => process.hasUnretrievedOutput())
}

View file

@ -167,14 +167,26 @@ export class TerminalRegistry {
}
return terminal.process ? terminal.process.isHot : false
}
/**
* Gets terminals filtered by busy state
* Gets terminals filtered by busy state and optionally by task ID
* @param busy Whether to get busy or non-busy terminals
* @param taskId Optional task ID to filter terminals by
* @returns Array of Terminal objects
*/
static getTerminals(busy: boolean): Terminal[] {
return this.getAllTerminals().filter((t) => t.busy === busy)
static getTerminals(busy: boolean, taskId?: string): Terminal[] {
return this.getAllTerminals().filter((t) => {
// Filter by busy state
if (t.busy !== busy) {
return false
}
// If taskId is provided, also filter by taskId
if (taskId !== undefined && t.taskId !== taskId) {
return false
}
return true
})
}
static cleanup() {