shout/STDIN.md

1.8 KiB

Stdin / Prompt Support

The challenge

Currently, the shell's stdin is consumed by the script itself (buildScript writes all commands at once, then proc.stdin.end()). There's no channel left to feed stdin to individual commands.

Simplest design: heredoc injection

Add a < prefix for stdin lines in .shout files. At script-build time, transform the command into a heredoc pipe. No runtime changes needed.

Syntax:

$ read -p "Name: " name && echo "Hello, $name"
< Chris
Name: Hello, Chris

$ cat
< line one
< line two
line one
line two

$ grep -c foo
< foo bar
< baz
< foo baz
2

Implementation: In parse.ts, collect < lines as a new stdin: string[] field on Command. In buildScript, when cmd.stdin is non-empty, wrap the command:

# instead of:
some_command
# generate:
some_command <<'__SHOUT_STDIN__'
line one
line two
__SHOUT_STDIN__

This is ~30 lines of change across parse + run, and fits cleanly into the existing architecture.

What it wouldn't handle

  • Interactive prompts with branching (send input, read output, decide next input) — would require per-command execution, a much bigger refactor
  • Timing-sensitive input (send after a delay) — same issue
  • Binary stdin — heredocs are text-only

Alternative: named pipes (more complex)

For each command needing stdin, create a FIFO in the temp dir and redirect from it. Shout would write to the FIFO from the Node side at the right time. This could support interactive flows but adds significant complexity to the sentinel-based output parsing — you'd need to synchronize "when to write the next stdin chunk."

Recommendation

The heredoc approach covers the 90% case (testing CLIs that read input, cat, read, piped filters) with minimal change.