Skip to content

Commit 1d10f69

Browse files
ctemehmetsunkur
authored andcommitted
Terminal performance improvements (RooCodeInc#3119)
1 parent 74e539f commit 1d10f69

File tree

6 files changed

+159
-135
lines changed

6 files changed

+159
-135
lines changed

src/core/tools/executeCommandTool.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,15 +152,15 @@ export async function executeCommand(
152152

153153
const callbacks: RooTerminalCallbacks = {
154154
onLine: async (output: string, process: RooTerminalProcess) => {
155-
const compressed = Terminal.compressTerminalOutput(output, terminalOutputLineLimit)
156-
cline.say("command_output", compressed)
155+
const status: CommandExecutionStatus = { executionId, status: "output", output }
156+
clineProvider?.postMessageToWebview({ type: "commandExecutionStatus", text: JSON.stringify(status) })
157157

158158
if (runInBackground) {
159159
return
160160
}
161161

162162
try {
163-
const { response, text, images } = await cline.ask("command_output", compressed)
163+
const { response, text, images } = await cline.ask("command_output", "")
164164
runInBackground = true
165165

166166
if (response === "messageResponse") {
@@ -171,10 +171,11 @@ export async function executeCommand(
171171
},
172172
onCompleted: (output: string | undefined) => {
173173
result = Terminal.compressTerminalOutput(output ?? "", terminalOutputLineLimit)
174+
cline.say("command_output", result)
174175
completed = true
175176
},
176177
onShellExecutionStarted: (pid: number | undefined) => {
177-
const status: CommandExecutionStatus = { executionId, status: "running", pid }
178+
const status: CommandExecutionStatus = { executionId, status: "started", pid, command }
178179
clineProvider?.postMessageToWebview({ type: "commandExecutionStatus", text: JSON.stringify(status) })
179180
},
180181
onShellExecutionComplete: (details: ExitCodeDetails) => {

src/integrations/terminal/ExecaTerminalProcess.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { BaseTerminalProcess } from "./BaseTerminalProcess"
66
export class ExecaTerminalProcess extends BaseTerminalProcess {
77
private terminalRef: WeakRef<RooTerminal>
88
private controller?: AbortController
9+
private aborted = false
910

1011
constructor(terminal: RooTerminal) {
1112
super()
@@ -45,18 +46,48 @@ export class ExecaTerminalProcess extends BaseTerminalProcess {
4546
this.terminal.setActiveStream(stream, subprocess.pid)
4647

4748
for await (const line of stream) {
49+
if (this.aborted) {
50+
break
51+
}
52+
4853
this.fullOutput += line
4954

5055
const now = Date.now()
5156

52-
if (this.isListening && (now - this.lastEmitTime_ms > 250 || this.lastEmitTime_ms === 0)) {
57+
if (this.isListening && (now - this.lastEmitTime_ms > 500 || this.lastEmitTime_ms === 0)) {
5358
this.emitRemainingBufferIfListening()
5459
this.lastEmitTime_ms = now
5560
}
5661

5762
this.startHotTimer(line)
5863
}
5964

65+
if (this.aborted) {
66+
let timeoutId: NodeJS.Timeout | undefined
67+
68+
const kill = new Promise<void>((resolve) => {
69+
timeoutId = setTimeout(() => {
70+
try {
71+
subprocess.kill("SIGKILL")
72+
} catch (e) {}
73+
74+
resolve()
75+
}, 5_000)
76+
})
77+
78+
try {
79+
await Promise.race([subprocess, kill])
80+
} catch (error) {
81+
console.log(
82+
`[ExecaTerminalProcess] subprocess termination error: ${error instanceof Error ? error.message : String(error)}`,
83+
)
84+
}
85+
86+
if (timeoutId) {
87+
clearTimeout(timeoutId)
88+
}
89+
}
90+
6091
this.emit("shell_execution_complete", { exitCode: 0 })
6192
} catch (error) {
6293
if (error instanceof ExecaError) {
@@ -84,6 +115,7 @@ export class ExecaTerminalProcess extends BaseTerminalProcess {
84115
}
85116

86117
public override abort() {
118+
this.aborted = true
87119
this.controller?.abort()
88120
}
89121

src/schemas/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,14 @@ export type CustomSupportPrompts = z.infer<typeof customSupportPromptsSchema>
293293
export const commandExecutionStatusSchema = z.discriminatedUnion("status", [
294294
z.object({
295295
executionId: z.string(),
296-
status: z.literal("running"),
296+
status: z.literal("started"),
297297
pid: z.number().optional(),
298+
command: z.string(),
299+
}),
300+
z.object({
301+
executionId: z.string(),
302+
status: z.literal("output"),
303+
output: z.string(),
298304
}),
299305
z.object({
300306
executionId: z.string(),

src/shared/combineCommandSequences.ts

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -77,35 +77,3 @@ export function combineCommandSequences(messages: ClineMessage[]): ClineMessage[
7777
return msg
7878
})
7979
}
80-
81-
export const splitCommandOutput = (text: string) => {
82-
const outputIndex = text.indexOf(COMMAND_OUTPUT_STRING)
83-
84-
if (outputIndex === -1) {
85-
return { command: text, output: "" }
86-
}
87-
88-
return {
89-
command: text.slice(0, outputIndex).trim(),
90-
91-
output: text
92-
.slice(outputIndex + COMMAND_OUTPUT_STRING.length)
93-
.trim()
94-
.split("")
95-
.map((char) => {
96-
switch (char) {
97-
case "\t":
98-
return "→ "
99-
case "\b":
100-
return "⌫"
101-
case "\f":
102-
return "⏏"
103-
case "\v":
104-
return "⇳"
105-
default:
106-
return char
107-
}
108-
})
109-
.join(""),
110-
}
111-
}

webview-ui/src/components/chat/ChatRow.tsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import deepEqual from "fast-deep-equal"
55
import { VSCodeBadge, VSCodeButton } from "@vscode/webview-ui-toolkit/react"
66

77
import { ClineApiReqInfo, ClineAskUseMcpServer, ClineMessage, ClineSayTool } from "@roo/shared/ExtensionMessage"
8-
import { splitCommandOutput, COMMAND_OUTPUT_STRING } from "@roo/shared/combineCommandSequences"
8+
import { COMMAND_OUTPUT_STRING } from "@roo/shared/combineCommandSequences"
99
import { safeJsonParse } from "@roo/shared/safeJsonParse"
1010

1111
import { useCopyToClipboard } from "@src/utils/clipboard"
@@ -979,19 +979,13 @@ export const ChatRowContent = ({
979979
</>
980980
)
981981
case "command":
982-
const { command, output } = splitCommandOutput(message.text || "")
983-
984982
return (
985983
<>
986984
<div style={headerStyle}>
987985
{icon}
988986
{title}
989987
</div>
990-
<CommandExecution
991-
executionId={message.progressStatus?.id}
992-
command={command}
993-
output={output}
994-
/>
988+
<CommandExecution executionId={message.progressStatus?.id} text={message.text} />
995989
</>
996990
)
997991
case "use_mcp_server":

0 commit comments

Comments
 (0)