Skip to content

fix(all): always report missing gems on stderr; only wait on a dialog without a tty - #1544

Open
simtel12 wants to merge 1 commit into
elanthia-online:mainfrom
simtel12:fix/gemcheck-tty-alert
Open

fix(all): always report missing gems on stderr; only wait on a dialog without a tty#1544
simtel12 wants to merge 1 commit into
elanthia-online:mainfrom
simtel12:fix/gemcheck-tty-alert

Conversation

@simtel12

@simtel12 simtel12 commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #1543.

On Linux, alert_linux opened a GUI dialog whenever zenity/kdialog/xmessage was on PATH, and run_with_timeout then waited on it for up to ALERT_TIMEOUT_SECONDS (120) with the child's stdout and stderr sent to File::NULL. The message existed only inside that dialog. A dialog raised from a terminal launch is easy to miss — another workspace, behind other windows, or not rendering at all — so from the terminal Lich appeared to hang for two minutes and then exit 1 having printed nothing.

It lands hardest on the early-exit CLI commands: GemCheck.verify! runs at lich.rbw:39, but lib/main/argv_options.rb is not required until lich.rbw:133. So --help, --version, --active-sessions, --session-info, --link-to-sge and the rest are all unreachable while the dialog blocks — including the --help that would have told the user to run bundle install.

Easy to hit right now: following the 4.0.3 → 4.0.5 bump from #1529 with a fresh rbenv install leaves you on an empty gem home, which is exactly the triggering condition.

Change

The reporting and the waiting used to be the same act. Separating them is the whole fix:

  • Always warn on stderr, unconditionally. It costs nothing, it carries the whole message rather than a pointer to it, and when stderr is captured (a launcher's output, a service log) it is the only record that survives. This is the part that makes the failure legible.
  • Only wait on a dialog when there was no terminal that report could reach. A launcher start has no other channel, so it keeps the dialog and its timeout exactly as before. A terminal launch already has the message and no longer blocks two minutes to deliver it a second time.

So nobody loses information relative to today, and the GUI path is untouched for the launches that actually depend on it. Both $stdout and $stderr are probed, since a terminal launch may redirect either; $stdout.isatty is already the idiom for this in lib/main/argv_options.rb (--link-to-sge, --unlink-from-sge, …).

The trailing no-dialog-tool else warn branch is removed — the unconditional warn is now the fallback it used to provide.

One deliberate non-change: a terminal launch no longer pops the dialog at all, rather than popping it and not waiting. Firing it off unwaited would leave an orphaned window behind an exited process, which is precisely what run_with_timeout was written to avoid ("the spawned child keeps running as an orphan; spawning it ourselves lets us kill it directly"). If you'd rather terminal launches still get a window, the natural shape is a short bounded wait rather than fire-and-forget — happy to switch if you prefer that trade.

Scoped to Linux, matching the issue. alert_macos has the same shape and would benefit from the same treatment — happy to extend it here or in a follow-up. I left alert_windows alone deliberately: it is bound up with the Ruby4Lich5 self-healing flow and I have no way to test it.

Test plan

  • bundle exec rspec (full suite): 6338 examples, 0 failures
  • bundle exec rubocop on both touched files: no offenses
  • New specs: warn happens in both branches, a tty on stdout suppresses the dialog wait, a tty on stderr alone counts as interactive, and the no-dialog-tool case still reports. Confirmed the three key examples fail against unmodified main and pass with the fix
  • Existing alert_linux specs now stub both streams explicitly rather than inheriting the runner's — rspec's stdout is a tty when run directly in a terminal but a pipe under CI, so they would otherwise pass or fail by accident
  • End-to-end against a simulated desktop (cmd_available? always true, run_with_timeout sleeping the full timeout): under a pty the message prints in 0.000s and no dialog is spawned; with output redirected the full alert lands on stderr before the dialog wait begins, and the process still blocks on the dialog — confirming the launcher path is genuinely unchanged

@coderabbitai

coderabbitai Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: d2e32c58-da2c-4a5e-a557-7870f26d2c40

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

… without a tty

On Linux, alert_linux showed a GUI dialog whenever zenity/kdialog/xmessage was
on PATH and then waited on it for up to ALERT_TIMEOUT_SECONDS with the child's
output sent to /dev/null. The message existed only inside that dialog, so a
terminal launch where the dialog is missed -- another workspace, behind other
windows, or not rendering at all -- looked like a silent two-minute hang ending
in exit 1, with no indication of the cause.

This lands hardest on the early-exit CLI commands. GemCheck.verify! runs at
lich.rbw:39, but the argv dispatcher is not required until lich.rbw:133, so
--help, --version, --active-sessions and the rest are all unreachable while
the dialog blocks -- including the --help that would have explained the fix.

Separate the reporting from the waiting, which were previously the same act:

- Always warn on stderr. It costs nothing, it carries the whole message rather
  than a pointer to it, and when stderr is captured it is the only record that
  survives. This is what makes the failure legible, and it is unconditional.
- Only wait on a dialog when there was no terminal that report could reach.
  Launcher starts have no other channel, so they keep the dialog and its
  timeout unchanged; a terminal launch already has the message and no longer
  blocks for two minutes to deliver it a second time.

The trailing no-dialog-tool branch goes away: the unconditional warn is now
the fallback it used to provide.
@simtel12
simtel12 force-pushed the fix/gemcheck-tty-alert branch from 3c2a0dc to 6e4a6d4 Compare August 23, 2026 23:16
@simtel12 simtel12 changed the title fix(all): print the missing-gem alert to the terminal when one is attached fix(all): always report missing gems on stderr; only wait on a dialog without a tty Aug 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GemCheck blocks 120s on a GUI dialog and exits silently for CLI invocations on Linux (--help/--version/--active-sessions unusable when gems are missing)

1 participant