From cb28f75fff3747214c8f53f25eeb23f6abc4ddfc Mon Sep 17 00:00:00 2001 From: Hannes Rudolph Date: Tue, 27 Jan 2026 18:30:56 -0700 Subject: [PATCH] feat: add stdin support for ExecaTerminalProcess - Add writeStdin method to RooTerminalProcess interface - Add abstract writeStdin to BaseTerminalProcess - Implement writeStdin in ExecaTerminalProcess using stdin pipe - Implement writeStdin in TerminalProcess using terminal.sendText - Change ExecaTerminalProcess from stdin: 'ignore' to stdin: 'pipe' - Update WriteStdinTool to use unified process.writeStdin() method This enables write_stdin tool to work with both VSCode terminals and Execa terminals, providing consistent interactive terminal support. --- src/core/tools/WriteStdinTool.ts | 19 +++++---------- .../terminal/BaseTerminalProcess.ts | 7 ++++++ .../terminal/ExecaTerminalProcess.ts | 24 +++++++++++++++++-- src/integrations/terminal/TerminalProcess.ts | 22 +++++++++++++++++ src/integrations/terminal/types.ts | 5 ++++ 5 files changed, 62 insertions(+), 15 deletions(-) diff --git a/src/core/tools/WriteStdinTool.ts b/src/core/tools/WriteStdinTool.ts index 3b7d17bc7a..6c870ae1b8 100644 --- a/src/core/tools/WriteStdinTool.ts +++ b/src/core/tools/WriteStdinTool.ts @@ -4,7 +4,6 @@ import { Task } from "../task/Task" import { ToolUse } from "../../shared/tools" import { formatResponse } from "../prompts/responses" import { ProcessManager } from "../../integrations/terminal/ProcessManager" -import { Terminal } from "../../integrations/terminal/Terminal" import { t } from "../../i18n" import { BaseTool, ToolCallbacks } from "./BaseTool" @@ -122,22 +121,16 @@ export class WriteStdinTool extends BaseTool<"write_stdin"> { // Process escape sequences in input const processedChars = this.processEscapeSequences(chars) - // Write to stdin + // Write to stdin using the unified writeStdin interface const { terminal, process } = entry let writeSuccess = false try { - if (terminal instanceof Terminal) { - // VSCode terminal - use sendText - // Note: sendText automatically adds a newline by default, so we pass false - // to prevent double newlines when the input already ends with \n - terminal.terminal.sendText(processedChars, false) - writeSuccess = true - } else { - // Execa terminal - would need stdin pipe support - // For now, we'll indicate this isn't supported for execa - // TODO: Implement stdin support for ExecaTerminalProcess - const errorMsg = `Session ${session_id} is using a non-interactive terminal. Interactive stdin is only supported for VSCode terminals.` + // Use the process writeStdin method which works for both VSCode and Execa terminals + writeSuccess = process.writeStdin(processedChars) + + if (!writeSuccess) { + const errorMsg = `Failed to write to session ${session_id}: stdin is not available` await task.say("error", errorMsg) pushToolResult(`Error: ${errorMsg}`) return diff --git a/src/integrations/terminal/BaseTerminalProcess.ts b/src/integrations/terminal/BaseTerminalProcess.ts index c1e26d51ee..d9b55a024a 100644 --- a/src/integrations/terminal/BaseTerminalProcess.ts +++ b/src/integrations/terminal/BaseTerminalProcess.ts @@ -137,6 +137,13 @@ export abstract class BaseTerminalProcess extends EventEmitter boolean getUnretrievedOutput: () => string trimRetrievedOutput: () => void + /** + * Write characters to stdin. Returns true if write was successful. + * May return false if stdin is not available (e.g., stdin: "ignore"). + */ + writeStdin: (chars: string) => boolean } export type RooTerminalProcessResultPromise = RooTerminalProcess & Promise