fix(tui): detect missing TTY and show helpful error instead of Bubbletea crash#905
fix(tui): detect missing TTY and show helpful error instead of Bubbletea crash#905decode2 wants to merge 1 commit into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughAdds a ChangesTTY Guard for TUI Launch
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related issues
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@internal/update/upgrade/executor.go`:
- Around line 521-524: The effectiveMethod function is being called multiple
times during a single tool execution—at line 521 for the spinner message, at
line 576 for result metadata, and again in runStrategy within
internal/update/upgrade/strategy.go at line 72—which causes unnecessary process
overhead and can result in inconsistent routing if one probe fails while another
succeeds. Resolve effectiveMethod once at the start of the tool execution
(before line 521), store the result in a variable, and then pass this resolved
method value through the execution chain instead of calling effectiveMethod
again at line 576. Additionally, update the runStrategy function and any related
execution functions to accept the pre-resolved method as a parameter rather than
computing it internally, eliminating the redundant call at strategy.go line 72.
🪄 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: Repository UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 044909ec-e20b-449f-9ebd-589a3bb637fc
📒 Files selected for processing (8)
internal/app/app.gointernal/app/app_test.gointernal/app/parity_test.gointernal/cli/run.gointernal/cli/run_component_paths_test.gointernal/update/upgrade/executor.gointernal/update/upgrade/strategy.gointernal/update/upgrade/strategy_test.go
| method := effectiveMethod(ctx, r.Tool, profile) | ||
| msg := fmt.Sprintf("Upgrading %s via %s (%s → %s)", r.Tool.Name, method, r.InstalledVersion, r.LatestVersion) | ||
| sp := NewSpinner(pw, msg) | ||
| toolResult := executeOne(ctx, r, profile, dryRun) |
There was a problem hiding this comment.
Avoid recomputing effectiveMethod multiple times per tool execution.
Line 521 resolves method for spinner text, Line 576 resolves it again for result metadata, and runStrategy resolves it a third time (internal/update/upgrade/strategy.go Line 72). Since effectiveMethod now performs an external brew probe, this adds avoidable process overhead and can yield inconsistent routing if one probe fails/cancels while another succeeds. Resolve once per tool and pass the resolved method through execution.
Suggested refactor sketch
--- a/internal/update/upgrade/executor.go
+++ b/internal/update/upgrade/executor.go
@@
- method := effectiveMethod(ctx, r.Tool, profile)
+ method := effectiveMethod(ctx, r.Tool, profile)
msg := fmt.Sprintf("Upgrading %s via %s (%s → %s)", r.Tool.Name, method, r.InstalledVersion, r.LatestVersion)
sp := NewSpinner(pw, msg)
- toolResult := executeOne(ctx, r, profile, dryRun)
+ toolResult := executeOne(ctx, r, profile, dryRun, method)
@@
-func executeOne(ctx context.Context, r update.UpdateResult, profile system.PlatformProfile, dryRun bool) ToolUpgradeResult {
+func executeOne(ctx context.Context, r update.UpdateResult, profile system.PlatformProfile, dryRun bool, method update.InstallMethod) ToolUpgradeResult {
@@
- Method: effectiveMethod(ctx, r.Tool, profile),
+ Method: method,
@@
- exitReq, err := runStrategy(ctx, r, profile)
+ exitReq, err := runStrategy(ctx, r, profile, method)--- a/internal/update/upgrade/strategy.go
+++ b/internal/update/upgrade/strategy.go
@@
-func runStrategy(ctx context.Context, r update.UpdateResult, profile system.PlatformProfile) (bool, error) {
+func runStrategy(ctx context.Context, r update.UpdateResult, profile system.PlatformProfile, method update.InstallMethod) (bool, error) {
@@
- method := effectiveMethod(ctx, r.Tool, profile)
-
switch method {Also applies to: 576-577
🤖 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 `@internal/update/upgrade/executor.go` around lines 521 - 524, The
effectiveMethod function is being called multiple times during a single tool
execution—at line 521 for the spinner message, at line 576 for result metadata,
and again in runStrategy within internal/update/upgrade/strategy.go at line
72—which causes unnecessary process overhead and can result in inconsistent
routing if one probe fails while another succeeds. Resolve effectiveMethod once
at the start of the tool execution (before line 521), store the result in a
variable, and then pass this resolved method value through the execution chain
instead of calling effectiveMethod again at line 576. Additionally, update the
runStrategy function and any related execution functions to accept the
pre-resolved method as a parameter rather than computing it internally,
eliminating the redundant call at strategy.go line 72.
…tea crash When gentle-ai launches the interactive TUI without a terminal attached (scripts, CI/CD, non-interactive SSH), Bubbletea panics with a confusing 'could not open a new TTY' error. Added a TTY guard that checks stdin before launching the TUI. When no TTY is available, returns a clear error listing non-interactive commands (--version, --help, update, install, sync, doctor) instead of crashing. The guard uses the existing isattyFn seam from selfupdate.go for testability. Info commands (version, help) continue to work without a TTY since they are dispatched before the guard. Closes Gentleman-Programming#95
9219528 to
1fb584f
Compare
Alan-TheGentleman
left a comment
There was a problem hiding this comment.
Scoped, linked to the approved issue, and the guard runs before Bubbletea starts while keeping help/version usable without a TTY. The no-TTY message duplicates a bit of help copy, but that is not blocking for this bugfix. Approving.
Summary
Detects missing TTY before launching the interactive TUI and shows a helpful error listing available non-interactive commands, instead of crashing with a confusing Bubbletea panic.
Problem
When
gentle-aiis launched without a terminal attached (scripts, CI/CD, non-interactive SSH), Bubbletea panics with:This gives no guidance on what to do instead.
Fix
Added
stdinIsTerminal()helper that reuses the existingisattyFnseam fromselfupdate.gofor testability.Added
ErrNoTTYForTUIerror with a clear message listing non-interactive commands:gentle-ai --versiongentle-ai --helpgentle-ai updategentle-ai installgentle-ai syncgentle-ai doctorInserted the TTY guard in
RunArgsimmediately before the TUI launch block, after info commands (version, help) are dispatched — so those continue to work without a TTY.Tests
TestRunArgs_NoTTY_ReturnsErrNoTTYForTUI— verifies the error is returned with the expected messageTestRunArgs_NoTTY_StillAllowsVersionAndHelp— verifies info commands work without TTYstdinIsTerminal = func() bool { return true }so the guard doesn't block themCloses #95
Summary by CodeRabbit
Bug Fixes
Tests