|
1 | 1 | import fs from "fs" |
2 | 2 | import path from "path" |
| 3 | +import { createInterface } from "readline" |
3 | 4 | import { fileURLToPath } from "url" |
4 | 5 |
|
5 | 6 | import { createElement } from "react" |
@@ -30,6 +31,24 @@ import { ExtensionHost, ExtensionHostOptions } from "@/agent/index.js" |
30 | 31 |
|
31 | 32 | const __dirname = path.dirname(fileURLToPath(import.meta.url)) |
32 | 33 |
|
| 34 | +async function* readPromptsFromStdinLines(): AsyncGenerator<string> { |
| 35 | + const lineReader = createInterface({ |
| 36 | + input: process.stdin, |
| 37 | + crlfDelay: Infinity, |
| 38 | + terminal: false, |
| 39 | + }) |
| 40 | + |
| 41 | + try { |
| 42 | + for await (const line of lineReader) { |
| 43 | + if (line.trim()) { |
| 44 | + yield line |
| 45 | + } |
| 46 | + } |
| 47 | + } finally { |
| 48 | + lineReader.close() |
| 49 | + } |
| 50 | +} |
| 51 | + |
33 | 52 | export async function run(promptArg: string | undefined, flagOptions: FlagOptions) { |
34 | 53 | setLogger({ |
35 | 54 | info: () => {}, |
@@ -185,15 +204,42 @@ export async function run(promptArg: string | undefined, flagOptions: FlagOption |
185 | 204 | // Output format only works with --print mode |
186 | 205 | if (outputFormat !== "text" && !flagOptions.print && isTuiSupported) { |
187 | 206 | console.error("[CLI] Error: --output-format requires --print mode") |
188 | | - console.error("[CLI] Usage: roo <prompt> --print --output-format json") |
| 207 | + console.error("[CLI] Usage: roo --print --output-format json") |
189 | 208 | process.exit(1) |
190 | 209 | } |
191 | 210 |
|
| 211 | + if (flagOptions.stdinPromptStream && !flagOptions.print) { |
| 212 | + console.error("[CLI] Error: --stdin-prompt-stream requires --print mode") |
| 213 | + console.error("[CLI] Usage: roo --print --stdin-prompt-stream [options]") |
| 214 | + process.exit(1) |
| 215 | + } |
| 216 | + |
| 217 | + if (flagOptions.stdinPromptStream && process.stdin.isTTY) { |
| 218 | + console.error("[CLI] Error: --stdin-prompt-stream requires piped stdin") |
| 219 | + console.error("[CLI] Example: printf '1+1=?\\n10!=?\\n' | roo --print --stdin-prompt-stream [options]") |
| 220 | + process.exit(1) |
| 221 | + } |
| 222 | + |
| 223 | + if (flagOptions.stdinPromptStream && prompt) { |
| 224 | + console.error("[CLI] Error: cannot use positional prompt or --prompt-file with --stdin-prompt-stream") |
| 225 | + console.error("[CLI] Usage: roo --print --stdin-prompt-stream [options]") |
| 226 | + process.exit(1) |
| 227 | + } |
| 228 | + |
| 229 | + const useStdinPromptStream = flagOptions.stdinPromptStream |
| 230 | + |
192 | 231 | if (!isTuiEnabled) { |
193 | | - if (!prompt) { |
194 | | - console.error("[CLI] Error: prompt is required in print mode") |
195 | | - console.error("[CLI] Usage: roo <prompt> --print [options]") |
196 | | - console.error("[CLI] Run without -p for interactive mode") |
| 232 | + if (!prompt && !useStdinPromptStream) { |
| 233 | + if (flagOptions.print) { |
| 234 | + console.error("[CLI] Error: no prompt provided") |
| 235 | + console.error("[CLI] Usage: roo --print [options] <prompt>") |
| 236 | + console.error("[CLI] For stdin control mode: roo --print --stdin-prompt-stream [options]") |
| 237 | + } else { |
| 238 | + console.error("[CLI] Error: prompt is required in non-interactive mode") |
| 239 | + console.error("[CLI] Usage: roo <prompt> [options]") |
| 240 | + console.error("[CLI] Run without -p for interactive mode") |
| 241 | + } |
| 242 | + |
197 | 243 | process.exit(1) |
198 | 244 | } |
199 | 245 |
|
@@ -258,7 +304,22 @@ export async function run(promptArg: string | undefined, flagOptions: FlagOption |
258 | 304 | jsonEmitter.attachToClient(host.client) |
259 | 305 | } |
260 | 306 |
|
261 | | - await host.runTask(prompt!) |
| 307 | + if (useStdinPromptStream) { |
| 308 | + let hasReceivedStdinPrompt = false |
| 309 | + |
| 310 | + for await (const stdinPrompt of readPromptsFromStdinLines()) { |
| 311 | + hasReceivedStdinPrompt = true |
| 312 | + await host.runTask(stdinPrompt) |
| 313 | + jsonEmitter?.clear() |
| 314 | + } |
| 315 | + |
| 316 | + if (!hasReceivedStdinPrompt) { |
| 317 | + throw new Error("no prompt provided via stdin") |
| 318 | + } |
| 319 | + } else { |
| 320 | + await host.runTask(prompt!) |
| 321 | + } |
| 322 | + |
262 | 323 | jsonEmitter?.detach() |
263 | 324 | await host.dispose() |
264 | 325 | process.exit(0) |
|
0 commit comments