fix: single-key TTY menu UX for the Gitea config menu (#36) #37

Closed
jcwalker3 wants to merge 0 commits from fix/issue-36-config-menu-ux into master
Owner

Closes #36. Refs #31, #34.

What

Make the interactive profile menu (./scripts/gitea-config-menu) feel like a real terminal menu, via a new injectable MenuIO. No menu logic, no MCP runtime, no auth/secret-storage changes.

UX

  • Single-key top-level actions in a TTY (stdlib termios/tty raw read) — no Enter. Non-TTY/test runs fall back to line input.
  • Enter backs out: Enter (or 0) on the main menu quits; Enter cancels any submenu / profile prompt and returns.
  • Profile chooser: numbered list, pick by key 19, explicit m) type a name manually, Enter cancels; empty config handled gracefully.
  • Clear screen before redrawing the main menu + chooser — TTY only; never emits clear codes in non-TTY/test runs.
  • Result + pause: validate / test-auth / whoami / eligibility print a concise result then Press any key to continue in a TTY; non-TTY never blocks.

Helpers: read_key (via default_io), choose_menu_option, choose_profile, clear_screen, pause_for_key, and MenuIO(is_tty, clear_enabled). TTY detected via sys.stdin.isatty() + sys.stdout.isatty(); stdlib only.

Safety (unchanged)

No tokens/passwords printed; no raw config dumps; no .env.personal; no change to auth behavior or secret storage. Secret scan of changed files: clean.

Tests

Rewrote menu tests around a scripted _FakeIO (no real terminal/keychain/network): single-key select + clear-called, main-menu Enter/0 quit, submenu Enter cancel leaves config unchanged, chooser lists/selects-by-key/no-profiles/manual-entry/out-of-range, non-TTY line fallback (default_io), clear-only-when-enabled, pause never hangs in non-TTY, and an add-flow asserting the token value never reaches disk or stdout.

Checks

  • Full suite: 278 passed, 0 failures, 0 errors (JUnit XML; harness swallows pytest stdout on multi-file runs).
  • py_compile clean.
  • Non-interactive smoke: printf '0\n' | ./scripts/gitea-config-menu → renders menu, quits cleanly, no hang, no clear codes.

Files changed

gitea_config_menu.py, tests/test_config_menu.py, docs/llm-workflow-runbooks.md. scripts/gitea-config-menu unchanged.


⚠️ Authored by me — do not self-merge. Needs review by another author.

Closes #36. Refs #31, #34. ## What Make the interactive profile menu (`./scripts/gitea-config-menu`) feel like a real terminal menu, via a new injectable `MenuIO`. No menu logic, no MCP runtime, no auth/secret-storage changes. ## UX - **Single-key** top-level actions in a TTY (stdlib `termios`/`tty` raw read) — no Enter. Non-TTY/test runs fall back to line input. - **Enter backs out**: Enter (or `0`) on the main menu quits; Enter cancels any submenu / profile prompt and returns. - **Profile chooser**: numbered list, pick by key `1`–`9`, explicit `m) type a name manually`, Enter cancels; empty config handled gracefully. - **Clear screen** before redrawing the main menu + chooser — **TTY only**; never emits clear codes in non-TTY/test runs. - **Result + pause**: validate / test-auth / whoami / eligibility print a concise result then `Press any key to continue` in a TTY; non-TTY never blocks. Helpers: `read_key` (via `default_io`), `choose_menu_option`, `choose_profile`, `clear_screen`, `pause_for_key`, and `MenuIO(is_tty, clear_enabled)`. TTY detected via `sys.stdin.isatty()` + `sys.stdout.isatty()`; stdlib only. ## Safety (unchanged) No tokens/passwords printed; no raw config dumps; no `.env.personal`; no change to auth behavior or secret storage. Secret scan of changed files: clean. ## Tests Rewrote menu tests around a scripted `_FakeIO` (no real terminal/keychain/network): single-key select + clear-called, main-menu Enter/`0` quit, submenu Enter cancel leaves config unchanged, chooser lists/selects-by-key/no-profiles/manual-entry/out-of-range, non-TTY line fallback (`default_io`), clear-only-when-enabled, pause never hangs in non-TTY, and an add-flow asserting the token value never reaches disk or stdout. ## Checks - Full suite: **278 passed, 0 failures, 0 errors** (JUnit XML; harness swallows pytest stdout on multi-file runs). - `py_compile` clean. - Non-interactive smoke: `printf '0\n' | ./scripts/gitea-config-menu` → renders menu, quits cleanly, no hang, no clear codes. ## Files changed `gitea_config_menu.py`, `tests/test_config_menu.py`, `docs/llm-workflow-runbooks.md`. `scripts/gitea-config-menu` unchanged. --- ⚠️ Authored by me — do **not** self-merge. Needs review by another author.
jcwalker3 added 1 commit 2026-07-02 01:34:50 -05:00
Make the interactive profile menu feel like a real terminal menu, via a new
injectable MenuIO abstraction (no menu logic change, no auth/secret-storage
change).

- Single-key top-level actions in a TTY (termios/tty raw read); no Enter
  needed. Non-TTY / test runs fall back to line input.
- Enter backs out: Enter (or 0) on the main menu quits; Enter cancels any
  submenu/profile prompt and returns.
- Profile chooser: everywhere a profile is needed, show a numbered list and
  pick by key (1-9), with an explicit 'm) type a name manually' path and Enter
  to cancel. Empty config handled gracefully.
- Clear screen before redrawing the main menu and chooser — TTY only; never
  emits clear codes in non-TTY/test runs.
- Result actions (validate/test-auth/whoami/eligibility) print a concise result
  then pause for a keypress in a TTY; non-TTY never blocks.

Helpers: read_key (via default_io) / choose_menu_option / choose_profile /
clear_screen / pause_for_key, plus MenuIO(is_tty, clear_enabled). TTY detected
with sys.stdin.isatty() and sys.stdout.isatty(); stdlib only.

Safety unchanged: no tokens/passwords printed, no raw config dumps, no
.env.personal, no change to auth behavior or secret storage.

Tests: rewrote menu tests around a scripted _FakeIO (no real terminal): single-
key select + clear, main-menu Enter/0 quit, submenu Enter cancel (no change),
chooser lists/selects/no-profiles/manual/out-of-range, non-TTY line fallback,
clear-only-when-enabled, pause never hangs non-TTY, and add-flow proving the
token value never reaches disk or stdout.

Docs: runbook note on single-key nav / Enter back-out / numbered chooser.
scripts/gitea-config-menu unchanged.

Closes #36. Refs #31, #34.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jcwalker3 closed this pull request 2026-07-02 01:39:35 -05:00
jcwalker3 deleted branch fix/issue-36-config-menu-ux 2026-07-02 01:39:35 -05:00

Pull request closed

Sign in to join this conversation.