Skip to content

feat: spinners, summaries and colors; keep secrets off the terminal - #30

Merged
iamralch merged 2 commits into
mainfrom
feat/console-ui
Oct 6, 2026
Merged

iamralch merged 2 commits into
mainfrom
feat/console-ui

Conversation

@iamralch

@iamralch iamralch commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

Output

All on stderr. stdout and the shell integration's fd 3 are unchanged.

$ keysafe load -p work -e 8h
⠙ Fetching API_KEY from 1password…                       ← spinner while op runs
✓ Loaded 5 secrets from work  (3 from the keychain, 2 from 1password)
✓ Added 2 SSH keys to ssh-agent  (expire in 8h)

$ keysafe unload -p work
✓ Unloaded 5 secrets and 2 SSH keys from work
  • Libraries: console for styling and terminal detection, indicatif for the spinner. Warnings printed while a spinner runs appear above it.
  • Colors:
    • errors (red), warnings (yellow), debug lines (dim),
    • ✓ / ! / ✗ in doctor,
    • states in status (set / in agent green, not set dim, problems yellow),
    • bold profile headings in status and profile show.
  • Plain output when it should be: no spinner or colors when the output isn't a terminal, with -q, or with NO_COLOR (also CLICOLOR and CLICOLOR_FORCE). stdout is only styled when main turns it on, so captured output, as in tests, stays plain.
  • Summaries: profile clear, config init and config edit print ✓ summaries too.
  • Why not ratatui: keysafe's commands are short-lived and often run under eval or at shell start, so a full-screen interface doesn't fit.

Terminal without the shell integration

#28 refused load and unload outright in this case. Now they do what doesn't need the shell, and only refuse the variables:

load unload
SSH keys added removed
Variables not fetched, not printed not unset; their files stay
Result error with the hint, e.g. "1 variable not set: the shell integration isn't active here; add eval "$(keysafe init zsh)" to ~/.zshrc, or run eval "$(keysafe load)"" same

keysafe load github-key (SSH key only) now works on a plain terminal.

Testing

  • 150 tests (119 unit, 31 integration). New ones cover:
    • load on a terminal: adds keys, doesn't fetch or print variables;
    • SSH keys alone on a terminal;
    • unload on a terminal: removes keys, keeps variables and files;
    • pluralization, and plain output by default.
  • Manual checks in a real terminal, using script and a stub op:
    • the spinner and ✓ summary when fetching,
    • no spinner when reading from the keychain,
    • load without the integration not calling op at all.
  • The demo's keychain entries were cleared afterwards.
  • Clippy and formatting are clean.

Known edge: if op itself asks for input on the terminal (setups without the desktop app's biometric unlock), its prompt and the spinner share the line. keysafe checks the sign-in first, so this needs a setup where op prompts anyway.

Output now uses console and indicatif, all on stderr:
- a spinner while a secret is fetched from its provider
- one-line summaries, e.g. "✓ Loaded 5 secrets from work (3 from the
  keychain, 2 from 1password)" and "✓ Added 2 SSH keys to ssh-agent
  (expire in 8h)"
- colored errors, warnings and debug lines
- colored marks in `doctor`, and states and headings in `status` and
  `profile show`

Nothing is animated or colored when the output isn't a terminal, with
-q, or with NO_COLOR.

On a terminal without the shell integration, `load` and `unload` now
handle SSH keys as usual and skip only the variables, which they can't
set and won't print: they fail with a hint instead of refusing
everything.
@iamralch iamralch self-assigned this Oct 6, 2026
@iamralch iamralch added the enhancement New feature or request label Oct 6, 2026
…oader

`Loader` counted cached and fetched secrets in `Cell`s, mutable state
behind `&self` that also counted SSH keys the summary doesn't report.
Now `load` returns the value with its origin (keychain or provider),
and `resolve` returns the variables with how many came from where and
how many failed. The loader keeps no state.
@iamralch
iamralch merged commit 7bd99e0 into main Oct 6, 2026
8 checks passed
@iamralch
iamralch deleted the feat/console-ui branch October 6, 2026 07:27
@ralch ralch Bot mentioned this pull request Oct 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant