mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 12:21:13 -05:00
Fix issue where sending message to stdin during non-interactive long-running process would not relinquish control back over the exit command button
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import defaultShell from "default-shell"
|
||||
import * as diff from "diff"
|
||||
import { execa, ExecaError } from "execa"
|
||||
import { execa, ExecaError, ResultPromise } from "execa"
|
||||
import fs from "fs/promises"
|
||||
import os from "os"
|
||||
import osName from "os-name"
|
||||
@@ -631,20 +631,10 @@ export class ClaudeDev {
|
||||
}
|
||||
return "The user denied this operation."
|
||||
}
|
||||
try {
|
||||
let result = ""
|
||||
// execa by default tries to convert bash into javascript, so need to specify `shell: true` to use sh on unix or cmd.exe on windows
|
||||
// also worth noting that execa`input` and the execa(command) have nuanced differences like the template literal version handles escaping for you, while with the function call, you need to be more careful about how arguments are passed, especially when using shell: true.
|
||||
// execa returns a promise-like object that is both a promise and a Subprocess that has properties like stdin
|
||||
const subprocess = execa({ shell: true })`${command}`
|
||||
|
||||
const sendCommandOutput = async (subprocess: ResultPromise, line: string): Promise<void> => {
|
||||
try {
|
||||
for await (const chunk of subprocess) {
|
||||
const line = chunk.toString()
|
||||
// stream output to user in realtime
|
||||
// do not await as we are not waiting for a response
|
||||
this.ask("command_output", line)
|
||||
.then(({ response, text }) => {
|
||||
const { response, text } = await this.ask("command_output", line)
|
||||
// if this ask promise is not ignored, that means the user responded to it somehow either by clicking primary button or by typing text
|
||||
if (response === "yesButtonTapped") {
|
||||
// SIGINT is typically what's sent when a user interrupts a process (like pressing Ctrl+C)
|
||||
@@ -661,11 +651,27 @@ export class ClaudeDev {
|
||||
// if the user sent some input, we send it to the command stdin
|
||||
// add newline as cli programs expect a newline after each input
|
||||
subprocess.stdin?.write(text + "\n")
|
||||
// Recurse with an empty string to continue listening for more input
|
||||
sendCommandOutput(subprocess, "") // empty strings are effectively ignored by the webview, this is done solely to relinquish control over the exit command button
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
// this can only happen if this ask promise was ignored, so ignore this error
|
||||
})
|
||||
} catch {
|
||||
// This can only happen if this ask promise was ignored, so ignore this error
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
let result = ""
|
||||
// execa by default tries to convert bash into javascript, so need to specify `shell: true` to use sh on unix or cmd.exe on windows
|
||||
// also worth noting that execa`input` and the execa(command) have nuanced differences like the template literal version handles escaping for you, while with the function call, you need to be more careful about how arguments are passed, especially when using shell: true.
|
||||
// execa returns a promise-like object that is both a promise and a Subprocess that has properties like stdin
|
||||
const subprocess = execa({ shell: true })`${command}`
|
||||
|
||||
try {
|
||||
for await (const chunk of subprocess) {
|
||||
const line = chunk.toString()
|
||||
// stream output to user in realtime
|
||||
// do not await as we are not waiting for a response
|
||||
sendCommandOutput(subprocess, line)
|
||||
result += `${line}\n`
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
@@ -41,7 +41,11 @@ export function combineCommandSequences(messages: ClaudeMessage[]): ClaudeMessag
|
||||
combinedText += `\n${COMMAND_OUTPUT_STRING}`
|
||||
didAddOutput = true
|
||||
}
|
||||
combinedText += "\n" + (messages[j].text || "")
|
||||
// handle cases where we receive empty command_output (ie when extension is relinquishing control over exit command button)
|
||||
const output = messages[j].text || ""
|
||||
if (output.length > 0) {
|
||||
combinedText += "\n" + output
|
||||
}
|
||||
}
|
||||
j++
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user