fix(workflows): render gate show_file contents in the interactive prompt by doquanghuy · Pull Request #2810 · github/spec-kit (original) (raw)

@doquanghuy @claude

The gate step read and recorded show_file but never displayed its contents at the interactive prompt, so the operator approved/rejected without seeing the referenced file. Render the file inside the prompt when stdin is a TTY, with a graceful notice for missing/unreadable files. Non-interactive PAUSED behaviour, exit codes, resume semantics, and no-show_file output are unchanged.

Closes github#2809.

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

@doquanghuy

@doquanghuy @claude

…le reads

The gate prompt rendered show_file by passing it as a third positional argument to _prompt. A test that stubs _prompt with a two-argument lambda (test_gate_abort_still_halts_with_continue_on_error) then failed once the branch caught up to main, because the call site passed three arguments to the two-argument stub.

Compose the show_file material into the displayed message in execute() and keep _prompt to its (message, options) contract. Display data no longer widens the interactive seam, so stubbing _prompt stays stable and future review material can be added without breaking callers. _prompt now renders a multi-line message inside the gate box.

Also catch ValueError in _read_show_file so a path the OS rejects outright (e.g. an embedded NUL byte) degrades to a notice instead of crashing the prompt, matching the helper's stated contract.

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

@doquanghuy @claude

The multi-line render loop split the message on newlines, which assumes a str. A non-string message (e.g. a YAML numeric literal) previously rendered fine through the old f-string and would now raise on .split. Coerce with str() to preserve that tolerance, and add a regression test.

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

@doquanghuy @claude

… typing

Address review feedback on the gate tests and helper:

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

@doquanghuy @claude

…s non-TTY

Address review feedback:

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

@doquanghuy @claude

_force_gate_stdin rebinds the gate module's sys name to a stand-in whose stdin has a fixed isatty() and which delegates every other attribute to the real sys, instead of mutating the process-wide sys.stdin. This keeps the patch local to the gate module and leaves real stdin untouched. The gate abort test, which used the same process-wide swap, now shares the helper, so the pattern exists in exactly one place.

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

@doquanghuy @claude

…content

Control characters were stripped from show_file contents but the path was still printed verbatim as the header (f"{show_file}:") and echoed in the read-error notice, so a show_file path containing ANSI escapes could still inject terminal sequences. Centralize stripping in _sanitize_for_display and apply it to every show_file-derived string that reaches the terminal — the displayed path, each file line, and the error notice — while still opening the file with the original path. Add a test for path sanitization.

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

@doquanghuy @claude

Reuse the existing _CONTROL_CHARS regex directly at the three display sites instead of wrapping it in a one-line helper.

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

@doquanghuy @claude

…play

The control-char class skipped LF (so an embedded newline in a show_file path could break the boxed layout) and the C1 range (so \x9b CSI and other 8-bit controls survived). Widen the class to [\x00-\x08\x0a-\x1f\x7f-\x9f] (still keeping tab).

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters

[ Show hidden characters]({{ revealButtonHref }})