Hmbown/CodeWhale · error

stdin is not a terminal; pass --yes to confirm the…

Error message

stdin is not a terminal; pass --yes to confirm the disclosed plan

What it means

Thrown by the `confirm` helper in crates/tui/src/integrations/cli.rs when a DSH integration command requires an interactive y/N confirmation but stdin is not a TTY and `--yes` was not passed. The library refuses to read a confirmation from a non-interactive stream, so the destructive/disclosed operation is aborted.

Solutions

  1. Pass the `--yes` flag to skip interactive confirmation (after reviewing the disclosed plan)
  2. Run the command in an interactive terminal instead of a script/pipe
  3. Drive the plan through a non-interactive API if automation needs programmatic approval

Example fix

// before (non-interactive, no flag)
$ codewhale dsh connect < /dev/null
// after
$ codewhale dsh connect --yes
Defensive patterns

Strategy: fallback

Validate before calling

// shell
[ -t 0 ] || echo "stdin is not a TTY; --yes required"

Try / catch

match result {
    Err(e) if e.to_string().contains("stdin is not a terminal") => {
        // either add --yes or surface the plan for manual interactive approval
    },
    other => return other,
}

Prevention

When it happens

Trigger: Running a `dsh` CLI subcommand that prompts for confirmation (e.g. connect/update) from a script, CI job, or piped stdin without the `--yes` flag.

Common situations: Automating `codewhale ... dsh connect` in CI or a shell script; piping input into the command; running under a supervisor where stdin is /dev/null.

Understand the failure class

Background: "--flag is required" and "must specify" CLI errors: how missing-required-flag validation works and how to fix it — this error's family across 20 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/895488c245f911c5. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/integrations/cli.rs:49

    let paths = DshPaths::from_process()?;
    let detection = detect_now();
    let identity = dsh::codewhale_route_identity(config, workspace);
    let report = dsh::compute_status(
        &paths,
        detection,
        identity,
        allow_full_access,
        dsh::bundle_availability_now(),
    )?;
    Ok((paths, report))
}

fn confirm(yes: bool, question: &str) -> Result<()> {
    if yes {
        return Ok(());
    }
    if !std::io::stdin().is_terminal() {
        anyhow::bail!("stdin is not a terminal; pass --yes to confirm the disclosed plan");
    }
    print!("{question} [y/N] ");
    use std::io::Write;
    std::io::stdout().flush().ok();
    let mut answer = String::new();
    std::io::stdin()
        .read_line(&mut answer)
        .context("read confirmation")?;
    if !matches!(answer.trim().to_ascii_lowercase().as_str(), "y" | "yes") {
        anyhow::bail!("not confirmed; nothing was written");
    }
    Ok(())
}

fn print_status(report: &DshStatusReport) {
    println!("DeepSeek Harness (dsh) — {}", RELATIONSHIP_LABEL);
    println!("  state: {}", report.state.label());
    println!("  summary: {}", dsh::status_line(report));

View on GitHub (pinned to 73e0f67d83)