fix(desktop): claim the t3code:// scheme default on Linux at startup - #5054
Conversation
The AppImage's integrated .desktop entry now advertises MimeType=x-scheme-handler/t3code, so the app shows up in the browser's "Choose an application" dialog — but nothing records it as the default handler, so every OAuth callback prompts the user again (and the entry's filename is decided by the integration tool, e.g. AppImageLauncher's appimagekit_<hash>-….desktop, so Electron's setAsDefaultProtocolClient cannot claim it via setDesktopName). Write a dedicated t3code-url-handler.desktop into $XDG_DATA_HOME/applications pointing at the current $APPIMAGE and set it as the scheme default via xdg-mime — the same association the file manager's "set as default" checkbox records. Registration is best-effort and never blocks startup. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
There was a problem hiding this comment.
Reviewed the new DesktopLinuxUrlHandler service against the Effect service conventions. The service/tag/make/layer shape, namespace imports, dependency acquisition (yield* Foo.Foo), and Effect.catch on a fully-handled channel all look right. Two error-modeling issues below.
Posted via Macroscope — Effect Service Conventions
…on errors Add desktopEntryPath and exitCode fields to DesktopLinuxUrlHandlerRegistrationError so failures log the resolved entry path and the xdg-mime exit status instead of burying them in a synthetic Error cause; cause is now optional for the domain failure. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Implementations unescape a desktop entry's Exec value twice: the general string-value rules first, then the Exec quoting rules. Writing therefore has to apply Exec quoting first and general string escaping on top, so a literal backslash in the AppImage path lands as four backslashes in the file, a double quote as \\" and a dollar sign as \\$. The previous single-layer escaping produced a malformed command for paths containing those characters. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ApprovabilityVerdict: Needs human review This PR introduces a new Linux-specific feature that writes .desktop files and executes xdg-mime commands at startup to claim URL scheme defaults. While well-scoped and defensive (failures don't block startup), new features with filesystem/process interactions warrant human review. You can customize Macroscope's approvability policy. Learn more. |
## What's Changed * fix(desktop): claim the t3code:// scheme default on Linux at startup by @juliusmarminge in pingdotgg/t3code#5054 **Full Changelog**: pingdotgg/t3code@v0.0.32-nightly.20260802.980...v0.0.32-nightly.20260803.985 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.32-nightly.20260803.985
Brings in 17 upstream commits (base e60821f). Headline changes: - Upgrade Effect to beta.103 (pingdotgg#5331), which removes the `Schema.UnknownFromJsonString` export and drops the positional actual argument from `SchemaIssue.InvalidValue`. - Replace the hand-rolled gzip path with `HttpMiddleware.compression()`, deleting apps/server/src/httpCompression/ entirely (pingdotgg#5331). - Extract desktop base/state dir resolution into DesktopStatePaths.ts, and add Linux secret storage, URL-scheme claiming, and early-startup modules (pingdotgg#2916, pingdotgg#5054). - Mobile provider icons for Grok, Cursor, and OpenCode (pingdotgg#4586). - Web polish: chat code blocks, tooltip z-index, spacing, loading screen, terminal cursor blink, terminal close-shortcut guard. Manual resolution and why: - apps/desktop/src/app/DesktopEnvironment.ts — semantic. Upstream deleted the `configuredBaseDir` local that the fork's branding override sat on top of, moving that logic into resolveDesktopBaseDir/resolveDesktopStateDir. Took upstream's extraction wholesale and re-applied the fork's displayNameOverride intent on it. The fork additionally gains upstream's trimming of a blank T3_HOME, which the old inline version did not do. - apps/mobile/src/components/ProviderIcon.tsx — the fork had replaced raw `props.provider === ...` checks with a resolveProviderIconKind seam; upstream's three new icons used the raw form. Routed them through the seam instead of mixing both styles, extended ProviderIconKind, and added test coverage so the new kinds cannot silently fall back to the OpenAI icon. - apps/server/src/textGeneration/CodexTextGeneration.ts — mechanical. Took upstream's one-line Schema change, kept the fork's rewrite of the rest. Merge-caused fixes beyond the conflicts: - Swept 15 fork-only call sites from `Schema.UnknownFromJsonString` to `Schema.fromJsonString(Schema.Unknown)`. These produced no conflict markers; the export simply no longer exists in beta.103. Upstream's own OrchestrationEventStore.ts survives only because it defines a local alias of the same name. Verified: pnpm install, pnpm typecheck (15/15 projects clean), pnpm test. Five failures remain in packages/shared (relayClient, logging); those four files are byte-identical to both upstream/main and the pre-merge backup, and assert POSIX-only behavior (linux-x64 fixture paths, forward-slash path comparisons, ENAMETOOLONG). They cannot pass on Windows and are unrelated to this merge. Backup of the pre-merge tip: backup/dev-before-merge-20260804
Summary
Follow-up to #5015. Linux users still get the "Choose an application to open 't3code'" prompt on every OAuth callback (and Firefox flows keep failing), even though the scheme registration from #5015 shipped — the app now appears in the chooser but is never recorded as the default handler for
x-scheme-handler/t3code.Why the OS keeps prompting
Linux ships as an AppImage, so the integrated
.desktopentry's filename is decided by whatever integration tool the user runs (AppImageLauncher names itappimagekit_<hash>-….desktop). Electron'sapp.setAsDefaultProtocolClientresolves the desktop id fromsetDesktopName(t3code.desktop), which can never match those files — so there is no reliable built-in way to claim the default.The fix
On packaged Linux startup, the new
DesktopLinuxUrlHandlerservice:t3code-url-handler.desktopinto$XDG_DATA_HOME/applications(default~/.local/share/applications) withExec="$APPIMAGE" %U,MimeType=x-scheme-handler/t3code;, andNoDisplay=true. Pointing at$APPIMAGEmatters:process.execPathlives in the transient/tmp/.mount_*squashfs (it is used only as a fallback outside an AppImage). Exec values use freedesktop quoting (%doubled,"`$\escaped).xdg-mime default t3code-url-handler.desktop x-scheme-handler/t3code— the same association the file manager's "set as default app" checkbox records inmimeapps.list.Registration is best-effort: any failure (missing
xdg-utils, read-only home) logs a warning and never blocks startup; the OS chooser remains as fallback. Re-running on every launch keeps theExecpath current when the AppImage moves, and lets whichever channel (stable/nightly) launched last own the scheme — matching macOS semantics.Supporting changes:
DesktopConfigreadsXDG_DATA_HOME, andDesktopEnvironmentexposeslinuxApplicationsDir+appImagePath(already parsed from$APPIMAGE).User impact
After updating and launching the app once, browser OAuth redirects open T3 Code directly — no chooser dialog in Chrome/Chromium, and Firefox shows its standard one-time confirmation with T3 Code preselected instead of failing.
Test plan
DesktopLinuxUrlHandler.test.ts: desktop-entry rendering incl. Exec quoting, AppImage vs. executable fallback, xdg-mime invocation, platform/packaged gating, and that write/xdg-mime failures never fail startup🤖 Generated with Claude Code
Note
Low Risk
Linux-only, packaged-only startup side effect with failures logged and startup never blocked; writes one user desktop file and runs xdg-mime.
Overview
Packaged Linux builds now register
t3code://as the default URL handler at startup so OAuth callbacks do not keep opening the system “choose an application” dialog.A new
DesktopLinuxUrlHandlerservice writes a hiddent3code-url-handler.desktopunder$XDG_DATA_HOME/applications(fromXDG_DATA_HOME, default~/.local/share/applications) withMimeType=x-scheme-handler/t3code;,Execpointing at$APPIMAGEwhen set (not the transient AppImage mount path), then runsxdg-mime defaultto claim the scheme. Registration is best-effort (warnings only) and is skipped on non-Linux or unpackaged runs.DesktopAppstartup invokeslinuxUrlHandler.registerafterwhenReady.Reviewed by Cursor Bugbot for commit 76e80dd. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Claim the
t3code://URL scheme default on Linux at app startup.desktopentry file and invokesxdg-mime defaultto register the app as the default handler for thet3code://scheme.XDG_DATA_HOMEfrom the environment (falling back to~/.local/share) to determine where to write the.desktopfile, exposed viaDesktopEnvironment.DesktopLinuxUrlHandlerRegistrationErrorand logged without crashing startup.Macroscope summarized 76e80dd.