Skip to content

Commit e3adee4

Browse files
author
Eric Wheeler
committed
fix: allow background terminals to broadcast output across tasks
Fix issue where background processes (like compilers) couldn't broadcast their output to new tasks after the launching task was closed. Previously commit 851a4cd prevented terminals from responding to any task except the one that started them. The fix allows background terminals (taskId undefined) to act as broadcast sources that can update any task through getEnvironmentDetails, while still maintaining proper isolation for task-specific terminals. This enables common workflows where: 1. A task launches a background compiler 2. That task is closed and a new task is started 3. The new task can still receive compiler errors when making changes This gives us the best of both worlds: - Task isolation: Active tasks only see their own terminal output - Background broadcasting: Background processes can inform any task that needs their output Signed-off-by: Eric Wheeler <[email protected]>
1 parent 0b4fa0b commit e3adee4

File tree

3 files changed

+65
-13
lines changed

3 files changed

+65
-13
lines changed

src/core/Cline.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3503,8 +3503,15 @@ export class Cline {
35033503
details += "\n(No open tabs)"
35043504
}
35053505

3506-
const busyTerminals = TerminalRegistry.getTerminals(true, this.taskId)
3507-
const inactiveTerminals = TerminalRegistry.getTerminals(false, this.taskId)
3506+
// Get task-specific and background terminals
3507+
const busyTerminals = [
3508+
...TerminalRegistry.getTerminals(true, this.taskId),
3509+
...TerminalRegistry.getBackgroundTerminals(true),
3510+
]
3511+
const inactiveTerminals = [
3512+
...TerminalRegistry.getTerminals(false, this.taskId),
3513+
...TerminalRegistry.getBackgroundTerminals(false),
3514+
]
35083515

35093516
if (busyTerminals.length > 0 && this.didEditFile) {
35103517
await delay(300) // delay after saving file to let terminals catch up

src/integrations/terminal/Terminal.ts

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ export class Terminal {
7575
*/
7676
public shellExecutionComplete(exitDetails: ExitCodeDetails): void {
7777
this.running = false
78+
this.busy = false
7879

7980
if (this.process) {
8081
// Add to the front of the queue (most recent first)
@@ -106,16 +107,7 @@ export class Terminal {
106107
* or don't belong to the current task
107108
*/
108109
public cleanCompletedProcessQueue(): void {
109-
// If this terminal has no task ID, it's not associated with any active task
110-
// In this case, we should remove all processes to prevent their output from appearing
111-
// in any task's context
112-
if (this.taskId === undefined) {
113-
this.completedProcesses = []
114-
return
115-
}
116-
117-
// If the terminal is associated with a task, keep only processes with unretrieved output
118-
// This ensures that when a task is active, it only sees output from its own processes
110+
// Keep only processes with unretrieved output
119111
this.completedProcesses = this.completedProcesses.filter((process) => process.hasUnretrievedOutput())
120112
}
121113

@@ -129,6 +121,32 @@ export class Terminal {
129121
return [...this.completedProcesses]
130122
}
131123

124+
/**
125+
* Gets all unretrieved output from both active and completed processes
126+
* @returns Combined unretrieved output from all processes
127+
*/
128+
public getUnretrievedOutput(): string {
129+
let output = ""
130+
131+
// First check completed processes to maintain chronological order
132+
for (const process of this.completedProcesses) {
133+
const processOutput = process.getUnretrievedOutput()
134+
if (processOutput) {
135+
output += processOutput
136+
}
137+
}
138+
139+
// Then check active process for most recent output
140+
const activeOutput = this.process?.getUnretrievedOutput()
141+
if (activeOutput) {
142+
output += activeOutput
143+
}
144+
145+
this.cleanCompletedProcessQueue()
146+
147+
return output
148+
}
149+
132150
public runCommand(command: string): TerminalProcessResultPromise {
133151
this.busy = true
134152

src/integrations/terminal/TerminalRegistry.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ export class TerminalRegistry {
153153
if (!terminal) {
154154
return ""
155155
}
156-
return terminal.process ? terminal.process.getUnretrievedOutput() : ""
156+
return terminal.getUnretrievedOutput()
157157
}
158158

159159
/**
@@ -190,6 +190,33 @@ export class TerminalRegistry {
190190
})
191191
}
192192

193+
/**
194+
* Gets background terminals (taskId undefined) that have unretrieved output or are still running
195+
* @param busy Whether to get busy or non-busy terminals
196+
* @returns Array of Terminal objects
197+
*/
198+
/**
199+
* Gets background terminals (taskId undefined) filtered by busy state
200+
* @param busy Whether to get busy or non-busy terminals
201+
* @returns Array of Terminal objects
202+
*/
203+
static getBackgroundTerminals(busy?: boolean): Terminal[] {
204+
return this.getAllTerminals().filter((t) => {
205+
// Only get background terminals (taskId undefined)
206+
if (t.taskId !== undefined) {
207+
return false
208+
}
209+
210+
// If busy is undefined, return all background terminals
211+
if (busy === undefined) {
212+
return t.getProcessesWithOutput().length > 0 || t.process?.hasUnretrievedOutput()
213+
} else {
214+
// Filter by busy state
215+
return t.busy === busy
216+
}
217+
})
218+
}
219+
193220
static cleanup() {
194221
this.disposables.forEach((disposable) => disposable.dispose())
195222
this.disposables = []

0 commit comments

Comments
 (0)