Skip to content

stdio: no way to tell whether stdin or stdout is attached to a terminal #7088

Description

@filipfalcon

What is the problem this feature would solve?

Every CLI branches on whether it is talking to a person: prompt or fail on a missing value, spinner or plain lines, color or none. Nothing in the platform answers that.

Stdio exposes args, stdin, stdout(), stderr(). Terminal exposes columns, rows, readInput, readLine, display. Neither says whether those streams are attached to a terminal, and no platform implementation surfaces it.

The only route is process.stdin.isTTY, which reaches past the platform package entirely — the same code reads Node globals when running on the Deno or Bun layer — and cannot be substituted in a test, so the branch that most needs covering is the one that can't be exercised.

What is the feature you are proposing to solve the problem?

Add it to Stdio, beside the streams it already describes, in the same shape as args:

export interface Stdio {
  // ...
  readonly stdinIsTerminal: Effect.Effect<boolean>
  readonly stdoutIsTerminal: Effect.Effect<boolean>
}

### What alternatives have you considered?

- **Reading `process.stdin.isTTY` directly**  what we do now, confined to a single
  `Context.Reference` so the rest of the CLI branches on a value a test can substitute.
  It works, but it defeats the platform abstraction: nothing in the layer is doing the
  work, and the Deno and Bun layers inherit Node's globals by accident.
- **Inferring it from `Terminal.columns`**  on Node it happens to work, since
  `stdout.columns ?? 0` yields `0` for a pipe. That is an undocumented sentinel, it
  conflates "not a terminal" with "zero-width terminal", and it only ever answers for
  stdout  while stdin is what decides whether prompting is possible at all.
- **Putting it on `Terminal`**  TTY-ness is a property of the streams, which is what
  `Stdio` describes, and it has to be answerable when no `Terminal` is wired.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions