Skip to content

feat(desktop): install GitHub CLI from onboarding terminal and add gh dialog end states - #6117

Merged
Kitenite merged 7 commits into
mainfrom
hoakiet98/super-1729-gh-install-dialog
Aug 2, 2026
Merged

Kitenite merged 7 commits into
mainfrom
hoakiet98/super-1729-gh-install-dialog

Conversation

@Kitenite

@Kitenite Kitenite commented Aug 1, 2026 •

Copy link
Copy Markdown
Member

Part of SUPER-1729 — https://linear.app/superset-sh/issue/SUPER-1729

What

  • system.detectBrew: new tRPC procedure detecting Homebrew via execWithShellEnv("brew", ["--version"]) on the login-shell PATH (explicit BrewDetectResult interface).
  • Onboarding Install action: when brew is present, the Install button now opens the terminal dialog in install mode running brew install gh && gh auth login --hostname github.com --git-protocol https --web (title "Install GitHub CLI"). When brew is absent, it keeps the existing external link to https://cli.github.com/.
  • GhAuthDialog end states: on PTY exit the dialog re-runs detectGhCli. Installed + authenticated → brief success state, auto-close after 1.5s (row still refetches via onExit). Otherwise the dialog stays open with "Sign-in canceled or failed." and a Retry button that respawns a fresh terminal (new paneId via remount). The stream's exit payload does carry exitCode, but success is decided solely from detectGhCli since the auth outcome is what matters.
  • Device-code copy chip: the output stream is buffered, ANSI-stripped (strip-ansi, already a desktop dep), and matched against /one-time code: ([A-Z0-9]{4}-[A-Z0-9]{4})/; the code renders above the terminal with a copy button. Regex verified against gh's actual output shape (! First copy your one-time code: XXXX-XXXX with the code bold-wrapped, across chunk boundaries).
  • Outside-click protection: the shared Dialog defaults to modal={false}, so a stray outside click unmounted the terminal and killed the PTY mid-auth. While the process is running/checking, onInteractOutside/onFocusOutside are prevented.
  • Copy fix: description now matches gh's real prompt sequence (first prompt is ? Authenticate Git with your GitHub credentials? (Y/n)).

Deliberately unchanged: Continue is still not gated on gh state (PR #4834); page.tsx diff kept minimal since row status rendering is being reworked on another branch.

Verification

  • bun run lint:fix + bun run lint → exit 0
  • apps/desktop bun run typecheck → clean
  • one-time-code regex sanity-checked against simulated chunked/ANSI gh output

Summary by CodeRabbit

  • New Features
    • Added automatic Homebrew detection during onboarding.
    • Added an in-app GitHub CLI installation flow when Homebrew is available.
    • Added dedicated GitHub authentication and installation modes with terminal progress, one-time code display, copy support, and status updates.
    • Added retry options and verification after installation or authentication.
  • Improvements
    • Onboarding now provides an external GitHub CLI installation link when Homebrew is unavailable.
    • Improved compatibility with different GitHub CLI authentication environments.

Screenshot evidence (CDP-verified)

Before (SUPER-1729 walkthrough): device code buried in a bare terminal with no copy affordance; Ctrl+C left a dead ^C with no feedback —

Before: device code with no copy button

Before: dead terminal after Ctrl+C

After:

Behavior Screenshot
Install mode: brew → gh auth chained in one dialog, one-time code extracted into a copy chip (clipboard verified)
Failure end state: clear message + Retry
Retry respawns a fresh terminal
Outside click no longer kills the PTY mid-auth
Success state before auto-close

Images live on the evidence/super-1729 branch (never merge; deletable after the PRs land).

Screenshots (current UI, CDP-verified in the dev app)

Guided single-strip layout: title + one morphing status strip + terminal.

Running — follow the prompts (install mode, full 752px width)
running

Code ready — auto-copied, terminal dims (Copy fallback shown when the clipboard write is rejected, e.g. window unfocused)
code

Failure — strip turns red, Retry inline (respawns a fresh pane)
failure

Modal overlay — background dimmed while the flow runs
overlay

Success — auto-closes after ~1.5s, row refetches to Connected
success

@coderabbitai

coderabbitai Bot commented Aug 1, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The desktop onboarding flow detects Homebrew and GitHub CLI authentication, supports GitHub CLI installation and authentication modes, streams terminal output, handles one-time codes, checks authentication status, and manages success, failure, retry, and dialog reset states.

Changes

GitHub CLI onboarding

Layer / File(s) Summary
Homebrew and GitHub CLI detection
apps/desktop/src/lib/trpc/routers/system.ts
The system router exposes detectBrew, parses brew --version, handles execution failures, and retries GitHub authentication detection without --active.
Mode-aware terminal dialog
apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/*
GhAuthDialog supports installation and authentication phases, one-time-code extraction and copying, terminal output, status checks, retries, and result states. GhAuthTerminal runs caller-provided commands and forwards output.
Onboarding mode selection
apps/desktop/src/renderer/routes/_authenticated/onboarding/page.tsx, apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/index.ts
The onboarding page stores the installation or authentication mode. Homebrew availability determines whether installation uses the dialog or an external link. The barrel export exposes GhAuthDialogMode.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Sequence Diagram(s)

sequenceDiagram
  participant OnboardingPage
  participant SystemRouter
  participant GhAuthDialog
  participant GhAuthTerminal
  participant GitHubCLI
  OnboardingPage->>SystemRouter: query Homebrew availability
  SystemRouter-->>OnboardingPage: return installation status
  OnboardingPage->>GhAuthDialog: open install or auth mode
  GhAuthDialog->>GhAuthTerminal: provide mode-specific command
  GhAuthTerminal->>GitHubCLI: start command
  GitHubCLI-->>GhAuthTerminal: stream output and exit
  GhAuthTerminal-->>GhAuthDialog: forward output and exit
  GhAuthDialog->>GitHubCLI: check authentication status
  GitHubCLI-->>GhAuthDialog: return authentication result
  GhAuthDialog-->>OnboardingPage: close after success
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title uses conventional commit format and clearly describes the GitHub CLI installation and dialog state changes.
Description check ✅ Passed The description explains the changes, testing, screenshots, verification details, and intended behavior in sufficient detail.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch hoakiet98/super-1729-gh-install-dialog

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.

@Kitenite

Kitenite commented Aug 2, 2026

Copy link
Copy Markdown
Member Author

End-to-end CDP verification (dev app, worktree renderer on vite port 8065, CDP 9612)

Drove the real onboarding flow in the dev desktop app with onboarded_at nulled for the test account (restored after). gh ran sandboxed via a temporary uncommitted GH_CONFIG_DIR=/tmp/t2-gh-sim prefix so the machine's real gh auth was never touched; the browser device-flow authorization was never completed. A temporary uncommitted shim let detectGhCli read /tmp/t2-sim.json to simulate gh-missing / unauthenticated / authenticated states. Both shims reverted; working tree matches the committed branch.

End-to-end checks (real button clicks, real PTY, real brew + gh):

  • Install mode — with detectGhCli simulating gh missing and real brew detected, the row's Install button opened the dialog titled "Install GitHub CLI"; the chained brew install gh && gh auth login … ran in the embedded terminal (brew completed, gh reached its first prompt ? Authenticate Git with your GitHub credentials? (Y/n) — which also confirms the corrected description copy). 01-install-mode-dialog.png
  • Device-code chip — answered Y + Enter in the terminal; when gh printed ! First copy your one-time code: 16CC-1A3A, the chip rendered the code above the terminal. Clicking Copy with the window focused put 16CC-1A3A on the system clipboard (verified via pbpaste). 02-device-code-chip.png
  • Outside-click protection — while gh sat at the device-code stage, a real CDP Input.dispatchMouseEvent click outside the dialog did not dismiss it, and the gh auth login PID survived. 05-outside-click-still-open.png
  • Failure end state — Ctrl+C into the terminal → gh exited → dialog stayed open showing "Install or sign-in canceled or failed." with Retry. 03-failure-state-retry.png
  • Retry — clicking Retry cleared the failure banner and stale chip and respawned a fresh terminal with a new gh process (new PID observed), running the chained command again. 04-retry-fresh-terminal.png

Synthetic-assisted check:

  • Success end state — real auth was off-limits, so the auth command was temporarily swapped to true while the sim reported installed+authenticated: dialog showed the green "Signed in to GitHub" panel, auto-closed ~1.5s later, and the row behind refetched to Connected. The success path's trigger (command exit → detectGhCli) is the real code path; only the process outcome was simulated. 06-success-state.png

Screenshots in /tmp/super-1729-t2-verify/ (01–06). One niggle observed (pre-existing, not from this PR): the shared DialogContent's base sm:max-w-lg beats the max-w-[752px] override, so the dialog renders 512px wide.

Cleanup done: shims reverted, /tmp/t2-gh-sim + sim file removed, onboarded_at restored, dev stack for this worktree stopped.

@Kitenite
Kitenite marked this pull request as ready for review August 2, 2026 00:18

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
`@apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/GhAuthDialog.tsx`:
- Around line 191-195: Add the select-text and cursor-text classes to the error
message paragraph rendered in GhAuthDialog, preserving its existing text styling
and conditional message content.
- Line 112: Update the dialog className in GhAuthDialog so the 752px maximum
width is applied with the sm breakpoint variant, ensuring it overrides the
existing sm:max-w-lg rule while preserving the current gap styling.

In `@apps/desktop/src/renderer/routes/_authenticated/onboarding/page.tsx`:
- Around line 30-35: Update the onboarding installation flow around detectBrew
and the Install action to wait until the brewStatus query has resolved before
choosing an installation path. Disable the Install action or show its loading
state while detection is pending, and only use the external fallback after
detection explicitly reports Homebrew unavailable; preserve the existing
Homebrew path once availability is confirmed.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f3483a12-a659-46c2-84d9-be2c380758fd

📥 Commits

Reviewing files that changed from the base of the PR and between f0be47c and 121511e.

📒 Files selected for processing (5)
  • apps/desktop/src/lib/trpc/routers/system.ts
  • apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/GhAuthDialog.tsx
  • apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/GhAuthTerminal.tsx
  • apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/onboarding/page.tsx

Comment on lines 30 to +35
const {
data: ghStatus,
refetch: refetchGh,
isFetching: isFetchingGh,
} = electronTrpc.system.detectGhCli.useQuery();
const { data: brewStatus } = electronTrpc.system.detectBrew.useQuery();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Wait for Homebrew detection before selecting the installation path.

Until detectBrew resolves, brewAvailable is false. A user can click Install during that interval and open the external website even when Homebrew is installed. Disable the Install action or show a loading state until the query resolves. Use the external fallback only after detection reports Homebrew unavailable.

Also applies to: 53-80

🤖 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 `@apps/desktop/src/renderer/routes/_authenticated/onboarding/page.tsx` around
lines 30 - 35, Update the onboarding installation flow around detectBrew and the
Install action to wait until the brewStatus query has resolved before choosing
an installation path. Disable the Install action or show its loading state while
detection is pending, and only use the external fallback after detection
explicitly reports Homebrew unavailable; preserve the existing Homebrew path
once availability is confirmed.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 5 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/desktop/src/renderer/routes/_authenticated/onboarding/page.tsx">

<violation number="1" location="apps/desktop/src/renderer/routes/_authenticated/onboarding/page.tsx:53">
P2: `brewAvailable` is derived straight from `brewStatus?.installed`, which is `false` while the `detectBrew` query is still loading. If a user clicks Install before the query resolves, `openGitHubInstall` will open the external cli.github.com link even when Homebrew is actually installed, instead of launching the in-app install terminal. Consider disabling the action or showing a loading state until `detectBrew` settles.</violation>
</file>

<file name="apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/GhAuthDialog.tsx">

<violation number="1" location="apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/GhAuthDialog.tsx:78">
P2: Reopening during a previous status check can have the old check mark the new auth attempt successful and auto-close it. Guard this completion with a per-open/per-attempt token (or cancel it) before updating phase or scheduling the close.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant UI as Onboarding Page
    participant Dialog as GhAuthDialog
    participant Terminal as GhAuthTerminal
    participant PTY as PTY Process
    participant TRPC as tRPC System Router
    participant Shell as Shell Environment

    Note over UI,Shell: GitHub CLI Setup Flow

    UI->>UI: Detect brew status
    UI->>TRPC: detectBrew.query()
    TRPC->>Shell: execWithShellEnv("brew", ["--version"])
    Shell-->>TRPC: stdout + version
    TRPC-->>UI: { installed: boolean }

    alt Brew available
        UI->>UI: Set dialog mode = "install"
        UI->>Dialog: Open with GH_INSTALL_COMMAND
    else Brew not available
        UI->>UI: window.open("https://cli.github.com/")
    end

    Note over Dialog,PTY: Dialog Lifecycle

    Dialog->>Dialog: Reset state (phase="running", attempt++)
    Dialog->>Terminal: Create with key={attempt}
    Terminal->>PTY: spawn (command)
    PTY-->>Terminal: onData (chunks)
    Terminal->>Dialog: onOutput(data)

    Note over Dialog,Terminal: One-time code detection
    Dialog->>Dialog: Buffer output, strip ANSI
    Dialog->>Dialog: Match /one-time code: ([A-Z0-9]{4}-[A-Z0-9]{4})/
    alt Code found
        Dialog->>UI: Render code with copy button
        UI->>UI: navigator.clipboard.writeText(code)
    end

    Note over Dialog,PTY: Process exit
    PTY-->>Terminal: onExit(exitCode)
    Terminal->>Dialog: handleTerminalExit()
    Dialog->>Dialog: Set phase = "checking"
    Dialog->>TRPC: detectGhCli.query()
    TRPC->>Shell: gh --version + gh auth status
    Shell-->>TRPC: status
    TRPC-->>Dialog: { installed, authenticated }
    alt Success (installed && authenticated)
        Dialog->>Dialog: Set phase = "success"
        Dialog->>Dialog: Auto-close after 1.5s
        Dialog->>UI: onExit()
        UI->>TRPC: refetchGh()
    else Failure
        Dialog->>Dialog: Set phase = "failed"
        alt Retry clicked
            Dialog->>Dialog: handleRetry()
            Dialog->>Terminal: New terminal (key=attempt+1)
        end
    end

    Note over Dialog,UI: Outside-click protection
    alt Process active (running/checking)
        UI->>UI: onInteractOutside.preventDefault()
        UI->>UI: onFocusOutside.preventDefault()
    end
Loading

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

!!anthropicStatus?.authenticated && !anthropicStatus.issue;
const codexConnected = !!openAIStatus?.authenticated && !openAIStatus.issue;

const brewAvailable = brewStatus?.installed === true;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: brewAvailable is derived straight from brewStatus?.installed, which is false while the detectBrew query is still loading. If a user clicks Install before the query resolves, openGitHubInstall will open the external cli.github.com link even when Homebrew is actually installed, instead of launching the in-app install terminal. Consider disabling the action or showing a loading state until detectBrew settles.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/renderer/routes/_authenticated/onboarding/page.tsx, line 53:

<comment>`brewAvailable` is derived straight from `brewStatus?.installed`, which is `false` while the `detectBrew` query is still loading. If a user clicks Install before the query resolves, `openGitHubInstall` will open the external cli.github.com link even when Homebrew is actually installed, instead of launching the in-app install terminal. Consider disabling the action or showing a loading state until `detectBrew` settles.</comment>

<file context>
@@ -47,7 +50,13 @@ function OnboardingDashboardPage() {
 		!!anthropicStatus?.authenticated && !anthropicStatus.issue;
 	const codexConnected = !!openAIStatus?.authenticated && !openAIStatus.issue;
 
+	const brewAvailable = brewStatus?.installed === true;
+
 	const openGitHubInstall = () => {
</file context>

onExitRef.current();
void electronTrpcClient.system.detectGhCli
.query()
.then((status) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Reopening during a previous status check can have the old check mark the new auth attempt successful and auto-close it. Guard this completion with a per-open/per-attempt token (or cancel it) before updating phase or scheduling the close.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/GhAuthDialog.tsx, line 78:

<comment>Reopening during a previous status check can have the old check mark the new auth attempt successful and auto-close it. Guard this completion with a per-open/per-attempt token (or cancel it) before updating phase or scheduling the close.</comment>

<file context>
@@ -1,38 +1,203 @@
+		onExitRef.current();
+		void electronTrpcClient.system.detectGhCli
+			.query()
+			.then((status) => {
+				if (status.installed && status.authenticated) {
+					setPhase("success");
</file context>

… dialog end states

- system.detectBrew procedure (Homebrew detection via login-shell PATH)
- Install action opens the terminal dialog running brew install gh + gh auth
  login when brew is present; external link fallback otherwise
- GhAuthDialog end states: re-run detectGhCli on PTY exit, brief success
  state with 1.5s auto-close, failure message with Retry (fresh paneId)
- one-time device code chip with copy button, parsed from stripped output
- block outside-click dismissal while the process is running (non-modal
  Dialog default would kill the PTY mid-auth)
- description copy matches gh's actual prompt sequence
…strip

One morphing strip under the title replaces description paragraph, code
card, and loose state rows: prompts hint -> auto-copied one-time code ->
red failure with inline Retry. Fix dialog width (sm:max-w-lg was beating
max-w-[752px]), dim terminal once the code appears, refocus terminal
after manual Copy so Enter reaches gh.
@Kitenite
Kitenite force-pushed the hoakiet98/super-1729-gh-install-dialog branch from 121511e to a99b464 Compare August 2, 2026 02:42

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
`@apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/GhAuthDialog.tsx`:
- Around line 131-139: Update the DialogContent configuration in GhAuthDialog to
add an onEscapeKeyDown handler that prevents the default dismissal when
processActive is true, matching the existing onInteractOutside and
onFocusOutside guards.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f6703f02-cd60-41e0-8a80-5db976286812

📥 Commits

Reviewing files that changed from the base of the PR and between 121511e and a99b464.

📒 Files selected for processing (5)
  • apps/desktop/src/lib/trpc/routers/system.ts
  • apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/GhAuthDialog.tsx
  • apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/GhAuthTerminal.tsx
  • apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/onboarding/page.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/index.ts
  • apps/desktop/src/lib/trpc/routers/system.ts
  • apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/GhAuthTerminal.tsx
  • apps/desktop/src/renderer/routes/_authenticated/onboarding/page.tsx

Comment on lines +131 to +139
<DialogContent
className="gap-3 sm:max-w-[752px]"
aria-describedby={undefined}
onInteractOutside={(event) => {
if (processActive) event.preventDefault();
}}
onFocusOutside={(event) => {
if (processActive) event.preventDefault();
}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

path="apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/GhAuthDialog.tsx"
if [ ! -f "$path" ]; then
  echo "Missing file: $path"
  git ls-files | rg 'GhAuthDialog\.tsx|GhAuthDialog' || true
  exit 0
fi

echo "== file outline =="
ast-grep outline "$path" --view expanded || true

echo "== relevant source =="
wc -l "$path"
sed -n '1,180p' "$path" | cat -n

echo "== all dialog dismissal handler references in file =="
rg -n "onEscapeKeyDown|onInteractOutside|onFocusOutside|processActive|setPhase|detectGhCli|GhAuthTerminal|handleTerminalExit" "$path"

Repository: superset-sh/superset

Length of output: 8389


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== inspect Dialog implementation =="
git ls-files | rg '`@superset/ui/dialog`|dialog' | sed -n '1,80p' || true

if [ -f "apps/desktop/src/lib/ui/index.ts" ]; then
  echo "== ui index excerpt =="
  sed -n '1,220p' apps/desktop/src/lib/ui/index.ts | cat -n
fi

if [ -d "apps/desktop/src/lib/ui" ]; then
  echo "== ui dialog files =="
  git ls-files "apps/desktop/src/lib/ui" | rg -i 'dialog|ui|components' || true
fi

echo "== package imports maybe linked via source =="
rg -n 'DialogContent|useDialog|AlertDialog|Radix.*Dialog|`@radix-ui/react-dialog`' apps/desktop/src || true

echo "== inspect local package metadata if present =="
for f in package.json bun.lockb bun.lock pnpm-lock.yaml yarn.lock; do
  [ -f "$f" ] && echo "-- $f --" && (rg -n '"`@radix-ui/react-dialog`"|`@radix-ui/react-dialog`|DialogContent' "$f" || true)
done

Repository: superset-sh/superset

Length of output: 50377


🌐 Web query:

Radix UI Dialog Content onEscapeKeyDown default behavior Escape key props example

💡 Result:

The default behavior of the Radix UI Dialog Content component is to close the dialog and return focus to the trigger element when the Escape key is pressed [1][2][3]. To customize or prevent this behavior, you can use the onEscapeKeyDown prop on the Dialog.Content component [1][2]. By calling event.preventDefault within the handler, you can stop the dialog from closing [4][5][6]. Example of preventing the Escape key from closing the dialog: <Dialog.Content onEscapeKeyDown={(event) => { event.preventDefault; }} > {/* Dialog content */} </Dialog.Content> You can also use this prop to execute custom logic before or instead of the default close action, such as showing a confirmation prompt or checking conditions before allowing the dialog to close [5][6].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== local dialog component =="
sed -n '1,220p' packages/ui/src/components/ui/dialog.tsx | cat -n

echo "== local DialogContent exports/usages =="
rg -n "export const DialogContent|DialogContent|DialogContentContent|onEscapeKeyDown|onInteractOutside|onFocusOutside" packages/ui/src/components/ui/dialog.tsx packages/ui/src/components/ui/alert-dialog.tsx || true

echo "== GhAuthTerminal source =="
file="apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/GhAuthTerminal.tsx"
if [ -f "$file" ]; then
  wc -l "$file"
  ast-grep outline "$file" --view expanded || true
  sed -n '1,240p' "$file" | cat -n
fi

Repository: superset-sh/superset

Length of output: 10050


Guard Escape dismissal while a shell process is active.

GhAuthTerminal mounts a terminal and calls terminal.kill.mutate on unmount, and handleTerminalExit starts detectGhCli.query(). Since DialogContent accepts dialog dismissal props, add onEscapeKeyDown that calls event.preventDefault() when processActive is true, matching the outside-escape handlers.

🔒 Proposed fix to guard the Escape key
 				onFocusOutside={(event) => {
 					if (processActive) event.preventDefault();
 				}}
+				onEscapeKeyDown={(event) => {
+					if (processActive) event.preventDefault();
+				}}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<DialogContent
className="gap-3 sm:max-w-[752px]"
aria-describedby={undefined}
onInteractOutside={(event) => {
if (processActive) event.preventDefault();
}}
onFocusOutside={(event) => {
if (processActive) event.preventDefault();
}}
<DialogContent
className="gap-3 sm:max-w-[752px]"
aria-describedby={undefined}
onInteractOutside={(event) => {
if (processActive) event.preventDefault();
}}
onFocusOutside={(event) => {
if (processActive) event.preventDefault();
}}
onEscapeKeyDown={(event) => {
if (processActive) event.preventDefault();
}}
🤖 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
`@apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/GhAuthDialog.tsx`
around lines 131 - 139, Update the DialogContent configuration in GhAuthDialog
to add an onEscapeKeyDown handler that prevents the default dismissal when
processActive is true, matching the existing onInteractOutside and
onFocusOutside guards.

- run the dialog modal so the overlay dims the onboarding page behind it
- queue renderer->pty input until createOrAttach resolves: xterm's
  automatic query replies (OSC 11, DSR) could hit a not-yet-created pane,
  and the terminal service synthesizes an exit for dead-pane writes,
  flipping the dialog to the failure state while the command was starting
- stash a pre-ready exit and replay it after create resolves so instant
  commands still resolve end states
@Kitenite

Kitenite commented Aug 2, 2026

Copy link
Copy Markdown
Member Author

Redesign + rebase update

Rebased onto main after #6115 merged — page.tsx resolved as a merge with main's UI winning: polling/isPending row states, status labels + dots, the "Detecting automatically" line, and the footer Provider docs link are all preserved; this branch only layers in the detectBrew query and the brew-gated Install action. PR is MERGEABLE again.

Dialog redesigned into a single guided status strip (per design review): title + one morphing strip + terminal, nothing else. Strip states: spinner "Follow the prompts below" → one-time code (auto-copied to clipboard on arrival, ✓ Copied, hint "Press Enter below, then paste this code on GitHub"; Copy button fallback when the clipboard write is rejected, which re-focuses the terminal so Enter reaches gh) → red failure strip with inline Retry. Success is a full check panel that auto-closes. Width fixed (sm:max-w-[752px] — base sm:max-w-lg was winning the tailwind-merge and wrapping gh output mid-word); terminal dims to 60% once the code is up; description paragraph removed.

Now modal: the dialog renders the fading overlay so the onboarding page behind it is dimmed — outside clicks are still hard-blocked while the process runs.

Race found and fixed during CDP verification: xterm auto-replies to terminal queries (OSC 11 / DSR) immediately at mount; if such a write reached the pane before createOrAttach resolved, the terminal service's dead-pane write path synthesized an exit event and flipped the dialog to the failure state while the command was actually starting (reproduced after Retry). Input is now queued until the pane exists, and a pre-ready exit is stashed and replayed so instant-exit commands still resolve.

Re-verified end-to-end via CDP (sandboxed GH_CONFIG_DIR, no real auth touched, device flow never completed): install mode reaches the gh prompt at full width; code strip + clipboard; 3× Ctrl+C→Retry cycles stay clean (race fix); modal overlay dims the background; success panel auto-closes ~1.5s and the row refetches to Connected. Screenshots in /tmp/super-1729-t2-verify/v2/ (01-running, 02-code, 03-failure, 04-overlay full-window, 06-success).

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
`@apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/GhAuthTerminal.tsx`:
- Around line 96-112: Update the createOrAttach promise flow in GhAuthTerminal
to track whether the effect has been disposed and whether the component is still
mounted. On creation failure, call fireExit() only while mounted so GhAuthDialog
can enter its retry state; when creation resolves after disposal, kill the newly
created pane instead of marking it ready or writing pending input, and retain
normal cleanup behavior otherwise.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 63e95086-689a-4379-b9e2-03ae901cdeec

📥 Commits

Reviewing files that changed from the base of the PR and between a99b464 and 1c41a40.

📒 Files selected for processing (2)
  • apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/GhAuthDialog.tsx
  • apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/GhAuthTerminal.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/GhAuthDialog.tsx

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 2 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

… escape hatch

gh auth status --active only exists on gh >= 2.40 (2023-12); retry
without the flag so older installs don't read as permanently signed out.
Install-mode failure strip gains an Install manually link to
cli.github.com as the exit from the embedded flow.
…anguage

Design audit pass: failure keeps the neutral strip surface with red only
on the icon, spinner strips drop to muted regular weight, success loses
the tinted circle badge, failure copy shortened to "didn't complete".
…g in gh dialog

Spinner strips read as subtitles (bg only, no border) per review. If
createOrAttach rejects, fire the exit path so the dialog lands on the
failure strip instead of running forever with a dead terminal.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/GhAuthTerminal.tsx">

<violation number="1" location="apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/GhAuthTerminal.tsx:115">
P3: The new `.catch(() => fireExit())` closes the dialog on a failed terminal create but silently discards the rejection reason, so a create failure (e.g. a bad command path or PTY spawn error) is unobservable and hard to diagnose. Consider logging the error with context before firing exit, e.g. `console.warn("gh auth terminal create failed", err)`, so repro attempts and support issues have a signal to trace.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

})
// A failed create would otherwise leave the dialog running forever
// with a dead terminal silently swallowing queued input.
.catch(() => fireExit());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The new .catch(() => fireExit()) closes the dialog on a failed terminal create but silently discards the rejection reason, so a create failure (e.g. a bad command path or PTY spawn error) is unobservable and hard to diagnose. Consider logging the error with context before firing exit, e.g. console.warn("gh auth terminal create failed", err), so repro attempts and support issues have a signal to trace.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/renderer/routes/_authenticated/onboarding/components/GhAuthDialog/GhAuthTerminal.tsx, line 115:

<comment>The new `.catch(() => fireExit())` closes the dialog on a failed terminal create but silently discards the rejection reason, so a create failure (e.g. a bad command path or PTY spawn error) is unobservable and hard to diagnose. Consider logging the error with context before firing exit, e.g. `console.warn("gh auth terminal create failed", err)`, so repro attempts and support issues have a signal to trace.</comment>

<file context>
@@ -109,7 +109,10 @@ export function GhAuthTerminal({
+			})
+			// A failed create would otherwise leave the dialog running forever
+			// with a dead terminal silently swallowing queued input.
+			.catch(() => fireExit());
 
 		return () => {
</file context>
Suggested change
.catch(() => fireExit());
.catch((err) => {
console.warn("gh auth terminal create failed", err);
fireExit();
});

…captured

gh waits for Enter only so the user can copy the code first; the dialog
already auto-copies it, so send Enter to the pty on detection and open
the browser immediately. Terminal keeps full opacity at the code step
(dim now only marks the dead failure state); hint copy updated to the
single remaining action.
@Kitenite
Kitenite merged commit e053bfc into main Aug 2, 2026
9 of 11 checks passed
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ⚠️ Neon database branch

Thank you for your contribution! 🎉

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.

1 participant