Skip to content

Setup: the questions from a terminal - #151

Merged
JacobStephens2 merged 5 commits into
mainfrom
issue-130
Sep 29, 2026
Merged

JacobStephens2 merged 5 commits into
mainfrom
issue-130

Conversation

@JacobStephens2

Copy link
Copy Markdown
Owner

Summary

thirdshift setup asks the Setup questions on stderr when stdin and stderr are both terminals, then writes the User config the same way as with no terminal: every key, with comments, edited in place.

 config::setup
   read the User config (a broken one is refused before any question)
   complete it, or start from DEFAULTS + the suggested address
+  if questions::has_terminal()
+    questions::ask(current values as default answers)
+      Every Run a Merge run? [y/N]                  -> merge.always
+      ... fast-forwards ... Base branch? [y/N]      -> launch.pull
+      Run notifications, an email ...? [y/N]        -> email.always
+        Send Run notifications to [<current|suggested>]:   (asked again until it has an @)
+        Send them from [<current|onboarding@resend.dev>]:
+        RESEND_API_KEY unset or empty -> print `export RESEND_API_KEY=re_...`
+        RESEND_API_KEY set            -> Send a test email now? [y/N]
+    with_answers: set each value in place, keeping its comment in the same column;
+                  an answered email.to replaces the commented-out `# to = ...` line
   write the file (nothing is written before the last answer, so Ctrl-C leaves none)
+  if a test email was asked for: email::send_test, as `email-test` does
 src/
+├── questions.rs        # the questions, on stderr; answers from stdin
 └── config.rs           # setup() asks when there is a terminal; with_answers edits the TOML
 tests/
 ├── support/mod.rs      # + Scenario::run_on_terminal: the binary on a libc::openpty pseudo-terminal,
 │                       #   the pty as its controlling terminal so Ctrl-C sends a real SIGINT
 └── setup.rs            # + 12 terminal-path tests

The README's User config section and the help line for setup now describe the questions.

Evidence

  • Before: cargo test --test setup with the new tests and no questions: 11 of the terminal tests fail. The terminal never showed "Merge run?"; setup wrote the defaults without asking.
    After: 28 of 28 pass. cargo test passes in full and clippy is clean.
on a terminal, Enter throughout          -> same file as `setup </dev/null`
answers y/yes/y, address, sender         -> values written, every key with a "default" comment, none commented out
Enter over an existing config            -> file byte for byte unchanged; [Y/n] and current values shown
hand-commented config                    -> comments survive; `# to =` line replaced by the answer
address without @                        -> asked 3 times
notifications off                        -> no address/sender/hint/test prompts, no email sent
RESEND_API_KEY unset / "" / set          -> hint / hint / test offer; key in neither file nor terminal
test email y / n / Enter                 -> 1 / 0 / 0 requests to the fake Resend
Ctrl-C mid-questions                     -> no file; an existing file unchanged
broken config                            -> exit 1, no question asked

Merge Danger

Door: two-way

Additive: with no terminal, setup behaves exactly as before, so scripted uses aren't affected.

Blast Radius: interactive-setup

Only thirdshift setup run from a terminal changes. Runs, email-test, update, version and help are untouched.

Unaddressed findings

Standards

  • Inject stdin, stderr and the key into questions::ask, so it can be tested in-process: skipped. The spec makes the binary the seam ("No new seam goes into the production code"), and the pty tests cover the behavior.
  • has_terminal() must be called before ask(); return Option<Answers> instead: skipped. The first-Run offer (a sibling issue) needs the terminal test on its own, before it asks anything.
  • Unit tests of private with_answers: kept. They pin formatting edge cases that are costly to reach end to end, as the module's existing complete() tests do.
  • Divergent Change in config::setup() (UI, email and TOML in one function) and its repeated parsing: deferred. The first-Run offer will reshape this entry point, and the right split is clearer then. The extra parses are of a small file.
  • Repeated branching on asked for the outcome message: skipped. It picks one of four distinct messages, and a match reads more plainly than an abstraction would.
  • Keys addressed as string pairs ("merge", "always"), so a new question touches several places: skipped. This matches DEFAULTS and parse, which name keys the same way.
  • Generic names answer/read/say, the Keystrokes tuple alias, TerminalResult repeating RunResult's fields, and the fully qualified DEFAULT_FROM in the tests: skipped. They are private helpers or test support, their doc comments say what they do, and the issue asks the helper to return the file alongside stdout, stderr and the exit code.

Spec

  • Pressing Enter at the sender keeps a custom email.from rather than going back to onboarding@resend.dev: kept. The spec also says "Each question's default answer is the current value", and with no custom sender, Enter keeps Resend's shared sender.
  • README and help text changed, which Setup: the questions from a terminal #130 doesn't ask for: kept. The docs have to match the new behavior, as thirdshift setup #126 asks.
  • Comment column kept when a value's width changes, and Ctrl-D ends Setup with nothing written: kept. Both are small and serve the spec's "comments survive" and "Ctrl-C writes no file".
  • A failed test email exits 1 after the file is written: kept. This matches email-test, and the file is already written by then.

Closes #130

🤖 Generated with Claude Code

JacobStephens2 and others added 5 commits September 29, 2026 23:28
thirdshift setup, with stdin and stderr on a terminal, asks on stderr
whether every Run is a Merge run, fast-forwards the Base branch and sends
Run notifications, and if so where to and from whom; then hints at
RESEND_API_KEY or offers a test email. Answers are written in place,
keeping comments. Tests drive the binary on a pseudo-terminal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ordering

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
macOS libc declares openpty's termios and winsize arguments as *mut;
Linux declares them *const. A *mut null coerces to either.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JacobStephens2
JacobStephens2 merged commit 04801ca into main Sep 29, 2026
13 checks passed
@JacobStephens2
JacobStephens2 deleted the issue-130 branch September 29, 2026 23:52
@JacobStephens2 JacobStephens2 mentioned this pull request Sep 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Setup: the questions from a terminal

1 participant