Skip to content

Sign in to a CLI-backed account from a button that runs its login command - #323

Open
rafaelbarea wants to merge 1 commit into
vinzdg:mainfrom
rafaelbarea:pr/sign-in-from-settings
Open

rafaelbarea wants to merge 1 commit into
vinzdg:mainfrom
rafaelbarea:pr/sign-in-from-settings

Conversation

@rafaelbarea

Copy link
Copy Markdown
Contributor

What

Grok, Kimi, Kiro, OpenCode, GitHub Copilot, Codex profiles and named Claude profiles all signed in the same way: a sentence in the Accounts row asking the reader to open a terminal and type a command. Every other account has a button. Now these do too.

  • New SignInRoute.command(command, name:, install:). The Accounts row shows Sign in to {tool}.
  • The button runs the login command in a new window of the first installed terminal (Ghostty, iTerm2, Terminal) via TerminalCommand.run. The tool prints its URL, opens the browser and waits for the callback the way it was written to.
  • When the tool is not installed, the same button opens its install page and the row's guidance says so, instead of describing a command that would fail. TerminalCommand.isInstalled looks at the usual install directories and then the login shell's PATH; the answer is cached for a minute since the row asks on every redraw.
  • The eight guidance sentences those providers no longer show are removed from the catalog. Three new strings, with pt-BR.

Related to #195 (moving sign-in out of the menu and into Settings): this makes the Settings side complete for the CLI-backed accounts.

Why in the terminal

These tools bind a local port and expect to be interactive; running them detached from Codenotch would lose the prompt (kimi signs in with /login inside the tool). The terminal is where they already work.

Tests

  • Tests/TerminalSignInTests.swift: button title, the three guidance variants (installed with login, installed without, missing tool), env-prefix handling in isInstalled, switch hint and sign-out caveat still present.
  • CodexProfileTests updated for the new route.
  • make test: 1740 tests, 0 failures.

This is the first of a series of small pull requests from my fork (rafaelbarea/codenotch); each stands alone.

🤖 Generated with Claude Code

…mand

Grok, Kimi, Kiro, OpenCode, GitHub Copilot, Codex profiles and named Claude
profiles all signed in the same way: a sentence in the Accounts row asking
the reader to open a terminal and type a command. Every other account has
a button. Now these do too.

`SignInRoute.command` names the login command and, when the tool is not on
this Mac, its install page. The button runs the command in a new window of
the first installed terminal (Ghostty, iTerm2 or Terminal), where the tool
prints its URL, opens the browser and waits for the callback the way it
was written to. Without the tool the same button opens the install page,
and the row's guidance says so instead of describing a command that would
fail.

The eight guidance sentences those providers no longer show leave the
catalog with them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@rafaelbarea
rafaelbarea requested a review from vinzdg as a code owner September 22, 2026 18:35
@vinzdg

vinzdg commented Sep 23, 2026

Copy link
Copy Markdown
Owner

Thanks @rafaelbarea. I've merged #324, #325 and #327 today — #325 in particular is a real bug I'm glad you found, and #324 is exactly the right shape. This one needs another pass.

It duplicates #324. ClaudeOAuthProvider.swift:175-193 carries the same fix, in a variant (hasSeveralProfiles) that can't be tested the way #324's pure cliEstimateApplies(slug:loginCount:) can. Since #324 is merged, please rebase and drop that hunk.

Two things block the rest:

  1. ClaudeOAuthProvider.swift:469 builds claude auth login. Claude Code has no auth login subcommand — it's /login inside the REPL. And because ProviderAccount.swift:66-69 picks its explanation from command.hasSuffix("login"), the row then also promises the browser will open. So the button would run a command that fails and say something untrue while doing it.
  2. TerminalCommand.isInstalled spawns /bin/zsh -lc and calls waitUntilExit() (TerminalCommand.swift:39-45), and it's reached from SignInRoute.explanation (ProviderAccount.swift:64) — which is a SwiftUI view body, on the main thread. The 60-second cache doesn't help the first evaluation, which is the one that hitches.

And a loss I'd rather not take: the PR is net-negative mostly because it deletes eight catalog keys with ten translations each and replaces them with three pt-BR-only ones. The prose went with them, and some of it was load-bearing — "connect Go inside OpenCode" is the only reason OpenCode usage reads at all, and "then enable GitHub Copilot" is a step people miss. Two template sentences chosen by hasSuffix("login") can't carry that.

The underlying idea — a button that runs the login command instead of telling you to — is good, and I'd like it. It just needs to keep the provider-specific guidance alongside the button rather than instead of it.

See my note on the sequencing across your eight PRs; I'll put it on #328 so it's in one place.

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.

2 participants