Uh oh!
There was an error while loading. Please reload this page.
Polish CLI UX - #392
Conversation
ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughThis PR adds a comprehensive CLI user experience layer to the relayburn CLI: TTY-aware progress spinners (TaskProgress), structured tracing-based logging, interactive dialoguer prompts, and a ux module for formatted status/error messages. These render helpers are wired into command flows (compare, hotspots, ingest, overhead, state, summary) and the main entrypoint. ChangesCLI UX and Progress Reporting System
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
| let _ = tracing_subscriber::fmt() | ||
| .with_env_filter(filter) | ||
| .with_ansi(ux::colors_enabled(globals)) |
There was a problem hiding this comment.
🟡 Tracing ANSI codes leak into piped/redirected stderr
logging.rs:26 passes ux::colors_enabled(globals) to .with_ansi(...), but colors_enabled (ux.rs:42-47) never checks whether stderr is actually a terminal — it only checks the --no-color flag, NO_COLOR, CLICOLOR, and TERM=dumb. When a user enables debug logging (RELAYBURN_LOG=debug) and redirects stderr (e.g. burn summary 2>log.txt), ANSI escape codes will appear in the log file because colors_enabled returns true for a piped stream. The standard practice (and what stderr_is_pretty in ux.rs:50 does correctly for spinners) is to also gate on io::stderr().is_terminal().
| .with_ansi(ux::colors_enabled(globals)) | |
| .with_ansi(ux::colors_enabled(globals) && std::io::stderr().is_terminal()) |
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/relayburn-cli/src/commands/summary.rs`:
- Around line 217-219: run_inner currently returns early via the ? operator and
can bypass progress.finish_and_clear(), leaving a stale spinner; update
run_inner (and any early-return sites called by run_ingest) to always call
progress.finish_and_clear() before propagating an error—either by invoking
progress.finish_and_clear() in each error branch, by using a scope guard/defer
pattern that calls finish_and_clear() on drop, or by mapping errors (e.g.
.map_err(|e| { progress.finish_and_clear(); e })) so that any early ?-returns
from run_inner/run_ingest ensure the spinner is cleaned up (also fix the similar
early-? paths in the nearby block referenced by 238-255).
In `@crates/relayburn-cli/src/render/progress.rs`:
- Around line 69-75: The non-pretty branch of the warn method emits a Unicode
warning glyph which is not script-safe; update the else path inside
Progress::warn (the closure passed to self.suspend) to use the CLI's plain,
script-friendly prefix instead of "⚠ {body}" — e.g. print "burn: warning:
{body}" (or the equivalent formatted string) via eprintln! to match other
plain-message conventions while leaving the pretty_warnings path and surrounding
suspend call unchanged.
In `@crates/relayburn-cli/src/render/prompt.rs`:
- Around line 49-51: When non-interactive (the branch in select that checks if
!interactive(globals)), clamp the provided default index before returning so
callers don't get an out-of-range value; compute a clamped index from the
passed-in default bounded to 0..=options.len().saturating_sub(1) (or use
default.clamp(0, options.len().saturating_sub(1))) and return that instead of
returning default as-is, keeping the same early-return behavior in select while
referencing interactive(globals), the default parameter, and the options length
for the bounds.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 8be1aa19-18c3-40ca-9c4b-20230647112d
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (15)
crates/relayburn-cli/Cargo.tomlcrates/relayburn-cli/src/commands/compare.rscrates/relayburn-cli/src/commands/hotspots.rscrates/relayburn-cli/src/commands/ingest.rscrates/relayburn-cli/src/commands/overhead.rscrates/relayburn-cli/src/commands/state.rscrates/relayburn-cli/src/commands/summary.rscrates/relayburn-cli/src/main.rscrates/relayburn-cli/src/render/error.rscrates/relayburn-cli/src/render/logging.rscrates/relayburn-cli/src/render/mod.rscrates/relayburn-cli/src/render/progress.rscrates/relayburn-cli/src/render/prompt.rscrates/relayburn-cli/src/render/table.rscrates/relayburn-cli/src/render/ux.rs
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
| if !interactive(globals) { | ||
| return Ok(default); | ||
| } |
There was a problem hiding this comment.
Clamp select default in non-interactive mode
select currently returns default as-is when non-interactive, so callers can receive an out-of-range index. Interactive mode already clamps this, so the non-interactive branch should do the same.
Suggested fix
pub fn select(
globals: &GlobalArgs,
prompt: &str,
items: &[impl AsRef<str>],
default: Option<usize>,
) -> io::Result<Option<usize>> {
if items.is_empty() {
return Ok(None);
}
if !interactive(globals) {
- return Ok(default);+ return Ok(default.map(|d| d.min(items.len() - 1)));
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@crates/relayburn-cli/src/render/prompt.rs` around lines 49 - 51, When
non-interactive (the branch in select that checks if !interactive(globals)),
clamp the provided default index before returning so callers don't get an
out-of-range value; compute a clamped index from the passed-in default bounded
to 0..=options.len().saturating_sub(1) (or use default.clamp(0,
options.len().saturating_sub(1))) and return that instead of returning default
as-is, keeping the same early-return behavior in select while referencing
interactive(globals), the default parameter, and the options length for the
bounds.
Uh oh!
There was an error while loading. Please reload this page.
Summary
Testing