Skip to content

Target server settings by environment - #4559

Open
colonelpanic8 wants to merge 13 commits into
pingdotgg:mainfrom
colonelpanic8:t3code/client-only-environment-settings
Open

Target server settings by environment#4559
colonelpanic8 wants to merge 13 commits into
pingdotgg:mainfrom
colonelpanic8:t3code/client-only-environment-settings

Conversation

@colonelpanic8

@colonelpanic8 colonelpanic8 commented Jul 26, 2026

Copy link
Copy Markdown

What Changed

  • Add one shared environment selector across General, Providers, Keybindings, Source Control, and Diagnostics settings.
  • Route server-backed settings to the selected environment while keeping client-only preferences in local client storage.
  • Use the active saved environment for global keybindings, provider updates, and server presentation when no primary environment exists.
  • Resolve new-thread defaults, worktree behavior, editors, and keybindings from the project or thread environment.
  • Incorporate per-environment provider configuration and environment-scoped diagnostics behavior.
  • Disable server-backed controls while the selected environment is disconnected.

Why

Client-only desktop mode deliberately has no PrimaryConnectionTarget, but several settings surfaces still read and wrote exclusively through primary-server atoms and hooks. Those controls therefore displayed defaults and silently failed to persist.

Settings now resolve an explicit selection first, then the managed primary environment, the active saved environment, and finally the first available environment. This preserves existing managed-client behavior while making client-only and multi-environment operation explicit.

UI Changes

  • General Settings now starts with a Server Settings environment row showing connection state and the selected environment.
  • Providers, Keybindings, Source Control, and Diagnostics use the same shared selection.
  • Client-local settings remain available when an environment is disconnected; server-backed controls are disabled until it reconnects.
  • Provider accounts and authorization state are shown only for the selected environment.

This PR is stacked on desktop-client-only-discovery, the branch behind #4444. It also carries the environment-scoped provider and diagnostics work needed by the complete settings flow.

Checklist

  • vp test run apps/web/src/components/settings/SettingsPanels.logic.test.ts apps/web/src/components/settings/DiagnosticsSettings.logic.test.ts apps/web/src/hooks/useSettings.test.ts — 31 tests passed
  • Targeted vp lint --report-unused-disable-directives for all changed files
  • vp run --filter @t3tools/web build
  • Integrated authenticated browser verification across General, Providers, Keybindings, Source Control, and Diagnostics
  • Confirmed assistant output, provider update checks, and the add-project base path persist through reload
  • vp run --filter @t3tools/web typecheck remains blocked by pre-existing unrelated errors in BranchToolbarBranchSelector, ModelPickerContent, PreviewAutomationHosts, and the atom command/query helpers

Note

High Risk
Touches desktop startup/shutdown, custom protocol static serving, and relaunch; web surfaces now depend on per-environment connection state instead of always-available primary server atoms.

Overview
Introduces a managed vs client-only desktop backend mode (--backend-mode, persisted backendMode, IPC + Connections UI). In client-only, startup skips the backend pool, registers the custom protocol as static (packaged renderer) or dev proxy, opens the window via handleRendererReady, and omits local bootstraps; shutdown skips pool teardown. Managed mode keeps proxying to the backend but drops the separate backendOrigin on protocol registration.

Electron protocol gains source: "proxy" | "static" with path-normalized static serving (SPA fallback, HEAD, traversal guards). Relaunch schedules the replacement process earlier, surfaces DesktopLifecycleRelaunchError, and setBackendMode rolls back settings if relaunch fails.

On the web side, server-backed settings (General, Providers, Keybindings, Source Control, Diagnostics) use a shared environment selector and useSettingsEnvironment / per-environment settings hooks instead of primary-only reads. Diagnostics is scoped to the selected environment with connection notices, disabled refresh when offline, and per-environment pending process signals. Chat, sidebar, and command palette stop using primaryServer* atoms for keybindings, providers, and config—useDefaultServerConfig and thread/project environment config drive defaults; remote thread labeling uses EnvironmentPresenceScope / ownsLocalEnvironment rather than comparing only to the primary id.

Reviewed by Cursor Bugbot for commit 13a79c6. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Scope settings panels and server config reads to target environment with desktop client-only mode support

  • Settings panels (General, Providers, Source Control, Keybindings, Diagnostics) now include an environment selector and scope server-side reads and writes to the chosen environment; controls are disabled when the selected environment is not connected.
  • Adds a client-only desktop backend mode that skips local backend startup, serves the renderer from either a dev proxy or packaged static assets, and hides local backend management UI.
  • New useDefaultServerConfig and useDefaultEnvironmentId hooks replace direct reads from primaryServer* atoms across sidebar, command palette, and chat components.
  • buildSidebarProjectSnapshots and remote-thread indicators now use isRemoteEnvironmentId with an EnvironmentPresenceScope instead of direct primary environment ID comparisons.
  • DesktopLifecycle.relaunch now propagates typed DesktopLifecycleRelaunchError failures to callers; setBackendMode rolls back settings when a triggered relaunch fails.
  • Risk: Components that previously read from global primary-server atoms now depend on per-environment config availability; surfaces will show defaults or be disabled when no environment is connected.

Macroscope summarized 13a79c6.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

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 UI

Review profile: CHILL

Plan: Pro Plus

Run ID: aad25f0c-63bf-47b6-98ec-13cf5784b5c5

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
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Jul 26, 2026
Comment thread apps/web/src/components/settings/SettingsPanels.tsx
Comment thread apps/web/src/components/settings/KeybindingsSettings.tsx
Comment thread apps/web/src/components/settings/SettingsPanels.tsx
Comment thread apps/desktop/src/ipc/methods/backendMode.ts
Comment thread apps/web/src/components/settings/DiagnosticsSettings.tsx
@macroscopeapp

macroscopeapp Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a new "client-only" desktop mode that fundamentally changes how the app can operate - allowing it to run without managing a local backend. The changes span startup behavior, settings scoping, IPC contracts, and environment handling. Given this is a significant new feature affecting core app behavior, human review is warranted.

You can customize Macroscope's approvability policy. Learn more.

colonelpanic8 added a commit to colonelpanic8/t3code that referenced this pull request Jul 26, 2026
# Conflicts:
#	apps/desktop/src/ipc/methods/backendMode.test.ts
#	apps/desktop/src/ipc/methods/backendMode.ts
#	apps/web/src/components/CommandPalette.tsx
#	apps/web/src/components/Sidebar.tsx
#	apps/web/src/components/SidebarV2.tsx
#	apps/web/src/components/settings/DiagnosticsSettings.tsx
#	apps/web/src/hooks/useSettings.ts
#	apps/web/src/routes/_chat.tsx
#	apps/web/src/state/environments.ts
@colonelpanic8
colonelpanic8 force-pushed the t3code/client-only-environment-settings branch from bf1d0ee to d17eb8a Compare July 28, 2026 02:08
Comment thread apps/web/src/components/settings/SettingsPanels.tsx
Comment thread apps/web/src/hooks/useHandleNewThread.ts Outdated
Comment thread apps/web/src/components/AppSidebarLayout.tsx
Comment thread apps/desktop/src/ipc/methods/backendMode.ts Outdated
Comment thread apps/web/src/components/settings/SettingsPanels.tsx Outdated
Comment thread apps/web/src/state/entities.ts

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit beb4f20. Configure here.

Comment thread apps/web/src/state/entities.ts
colonelpanic8 and others added 13 commits July 27, 2026 19:47
Let the desktop app run as a pure client for remote or independently
managed backends, instead of always owning a local backend process.

- Add a persisted `managed` / `client-only` backend mode with a
  launch-only `--backend-mode` override, exposed over IPC.
- In client-only mode, bootstrap skips the backend pool entirely and
  serves the renderer from packaged static assets (or the dev proxy),
  opening the window on renderer readiness rather than backend
  readiness, and skipping backend shutdown on quit.
- `ElectronProtocol` takes an explicit `source: "proxy" | "static"`.
  Static serving adds path-safe file resolution, SPA fallback, MIME
  types, CSP and HEAD support.
- Web routing treats client-only like hosted static, and local
  environment bootstraps are empty, so a client-only desktop is never
  stranded on a dead primary-backend state.

Co-Authored-By: Claude <noreply@anthropic.com>
The sidebar decided a thread or project was remote by comparing its
environment against the primary environment id. A client-only desktop
(and the hosted static web app) never registers a primary, so that id is
always null and every row read as local: no cloud/server icon, and no
environment name on the project header.

Make the comparison explicit about the two different meanings of a null
primary id. `isRemoteEnvironmentId` now takes an `ownsLocalEnvironment`
flag: when the app can never serve an environment from its own backend,
every environment is remote; when it can, a null primary id still means
"the local backend has not registered yet" and nothing is flagged remote.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The diagnostics environment picker made three pieces of panel-local state
lie about which machine they belong to:

- `openLogsDirectoryError` / `isOpeningLogsDirectory` kept showing an
  environment A failure (or spinner) after switching to environment B.
  They are now stored together with the environment they belong to, so
  they only render for that environment and a late completion can only
  update its own request.
- `signalingPid` was a single shared value, so completing a signal on
  environment A re-enabled the signal controls for an in-flight signal on
  environment B and allowed a duplicate SIGKILL. Pending signals are now
  identified by environment id plus pid.
- Diagnostics queries only run while the selected environment's
  supervisor is connected, so a disconnected machine showed permanent
  "Loading..." placeholders with the refresh buttons disabled. The panel
  now derives a connection notice and renders it instead of the loading
  state.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Follow-up to the review feedback on the previous commit:

- `DiagnosticsRefreshButton` used a single `isPending` prop for both the
  spinner and `disabled`, so suppressing the spinner while the selected
  environment is disconnected also made the button clickable even though
  the query cannot run. It now takes an explicit `isDisabled` prop.
- The open-logs completion matched on environment id alone, so returning
  to an environment and starting a second open while the first was still
  in flight let the older completion clear the newer pending state. The
  completion now matches the request by identity.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@colonelpanic8
colonelpanic8 force-pushed the t3code/client-only-environment-settings branch from 0f957cc to 13a79c6 Compare July 28, 2026 02:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant