Skip to content

Revert Claude per-account folders (#24434, #26405) before release - #26638

Merged
Jinwoo-H merged 2 commits into
mainfrom
jinwoo/revert-24434
Oct 8, 2026
Merged

Jinwoo-H merged 2 commits into
mainfrom
jinwoo/revert-24434

Conversation

@Jinwoo-H

@Jinwoo-H Jinwoo-H commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 98 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​12143 $\color{#cf222e}{\Huge{\mathbf{−}}}$​3115 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​9028
Prod 169 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​7712 $\color{#cf222e}{\Huge{\mathbf{−}}}$​2378 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​5334

ELI5

Two recent changes moved each saved Claude account into its own folder. After updating, anyone with a saved Claude account was signed out of every Claude feature in Orca until they signed in again. This takes both changes back out before the next release, so Claude accounts work the way they did before: Orca copies the selected account's login into place when you switch.

What Changed

Terminal daemon protocol: 43. Main was still on 42, and only #24434 had used it. Dev builds already run v42 daemons that give every pane the claude function, so the version can't go back down to 41: the app would then treat a v42 daemon as newer than itself. Keeping 42 would let new panes keep attaching to those daemons and inherit the function. Moving to 43 starts a fresh daemon without it. v41 and v42 daemons stay attachable, so open terminals survive. CLAUDE_ACCOUNT_FUNCTION_DAEMON_PROTOCOL_VERSION is removed.

Why

Signing every user with a saved Claude account out of Claude in Orca is too disruptive to ship. Reverting is the smallest safe step. The upgrade path will be reworked and re-landed separately.

Linked Issue

N/A (maintainer revert)

Visual Proof

N/A. This restores the UI from before #24434, which is already shipping in the current release.

Testing

  • pnpm tc passes.
  • vitest on src/main/{claude,claude-accounts,ipc,daemon,runtime}, src/cli, the renderer settings/status-bar/native-chat/terminal-pane components, and i18n: 33,681 pass and 2 fail. Both failures are in repro-13767-shell-ready-marker-lost-to-exec.test.ts (PTY timeout), and they fail the same way on origin/main.
  • oxlint on the changed files: clean. Localization, extraction, coverage, and RPC param catalog checks pass.
  • check:code-quality:changed reports 342 findings. Every flagged line is a verbatim line restored from before fix(claude): activate account profiles and remove credential replay (Step 4 of 4) #24434, mostly type casts in the restored tests. They fail the gate only because the gate counts restored lines as new. They were left as they were so the revert restores the old code exactly. revert: take the 26 Phase 3 (#16741 port) PRs back out of main #24559 merged with the same failure.
  • I manually tested these changes locally
  • Automated tests added/updated, or explained why not below (revert; the restored tests come back with the code)

Review

Data safety for dev users who ran #24434:

Agent skill upstream boundary

  • Not applicable

Notes

Cross-platform: the restored code is what shipped before #24434 on macOS, Linux, Windows, and WSL. SSH panes are unaffected by the daemon bump.

Checklist

  • This PR is small and focused (it's a revert)
  • I explained what changed and why
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (typecheck and targeted tests pass; changed-code quality is red on restored lines, as noted)

…nu and name the right Settings page" (#26405)

Users with a saved Claude account were signed out of every Claude feature in Orca until they signed in again; reverting before release to rework the upgrade path.
…replay (Step 4 of 4)" (#24434)

Users with a saved Claude account were signed out of every Claude feature in Orca until they signed in again; reverting before release to rework the upgrade path.
@Jinwoo-H
Jinwoo-H requested a review from brennanb2025 as a code owner October 8, 2026 18:14
@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

📝 Walkthrough

Walkthrough

Claude account flows now import credentials into managed storage, synchronize selected authentication, and restore saved state when operations fail. The changes also add OAuth token refresh, shared-credential reconciliation, rate-limit retrieval through OAuth and a hidden PTY, and live-session tracking that defers some refresh work. Claude profile-routing and sign-in interfaces are removed or disabled in several paths. A Windows spawn reproduction script and Codex shared-server banner changes are also included.

Priority: ⬆️ High

Merge Risk: 🔵 Low · up to 466db

This revert restores copy-based Claude account switching. A few edge-case failure paths need attention. Removing an account can leave a credential-less saved account if a later usage refresh fails. A transient Keychain write failure can force an inactive account to sign in again. These issues are narrow and recoverable, so the change is mergeable with follow-up.

🚥 Pre-merge checks | ✅ 4 | ❓ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ❓ Inconclusive Docstring coverage is 22.12% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 113 functions across 50 files. (151 skipp… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: reverting Claude per-account folders and the related changes before release.
Description check ✅ Passed The description covers the required sections, explains the user impact and rationale, documents retained changes and compatibility details, and reports test results and known failures. The N/A linked …
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.
Full details: Docstring Coverage

Explanation

Docstring coverage is 22.12% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 113 functions across 50 files. (151 skipped: 9 unsupported, 142 over the file limit.)

✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@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: 4

🧹 Nitpick comments (1)
src/main/claude-accounts/runtime-auth-service-snapshot-validation.test.ts (1)

185-185: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Rename the line 236 test to match its assertions.

The test at line 185 correctly asserts that runtime auth is cleared. The test at line 236 preserves OAuth metadata and keychain values, so its title should describe preservation.

Suggested title fix
-  it('clears missing-managed oauth metadata when only keychain proves ownership', async () => {
+  it('preserves missing-managed oauth metadata when only keychain proves ownership', async () => {

If clearing is required, update the assertions instead.


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 91274478-7559-4b6f-b39b-6733bf2e6ff9
📥 Commits

Reviewing files that changed from the base of the PR and between d997ef0 and 466dbe1.

⛔ Files ignored due to path filters (1)
  • src/shared/rpc-contract/rpc-params-catalog.generated.ts is excluded by !**/*.generated.*
📒 Files selected for processing (266)
  • .github/workflows/pr.yml
  • config/scripts/claude-account-windows-spawn-repro.mjs
  • config/scripts/node-pty-windows-pty-teardown-patch.test.mjs
  • src/cli/handlers/account-list-format.ts
  • src/cli/handlers/account.test.ts
  • src/cli/handlers/account.ts
  • src/main/__fixtures__/shell-wrapper-snapshots/daemon-bash-rcfile.txt
  • src/main/__fixtures__/shell-wrapper-snapshots/daemon-fish-init.txt
  • src/main/__fixtures__/shell-wrapper-snapshots/daemon-zsh-zshenv.txt
  • src/main/__fixtures__/shell-wrapper-snapshots/local-bash-rcfile.txt
  • src/main/__fixtures__/shell-wrapper-snapshots/local-fish-init.txt
  • src/main/__fixtures__/shell-wrapper-snapshots/local-zsh-zshenv.txt
  • src/main/__fixtures__/shell-wrapper-snapshots/relay-zsh-zshenv.txt
  • src/main/agent-auth-restart-preservation.test.ts
  • src/main/agent-auth-restart-preservation.ts
  • src/main/claude-accounts/claude-account-folder.test.ts
  • src/main/claude-accounts/claude-account-folder.ts
  • src/main/claude-accounts/claude-account-registration.ts
  • src/main/claude-accounts/claude-account-selection.ts
  • src/main/claude-accounts/claude-account-service-account-selection.test.ts
  • src/main/claude-accounts/claude-account-service-add-account.test.ts
  • src/main/claude-accounts/claude-account-service-api-parity.test.ts
  • src/main/claude-accounts/claude-account-service-config-dir-capture.test.ts
  • src/main/claude-accounts/claude-account-service-credential-capture.test.ts
  • src/main/claude-accounts/claude-account-service-login-process.test.ts
  • src/main/claude-accounts/claude-account-service-reauth-rollback.test.ts
  • src/main/claude-accounts/claude-account-service-test-harness.ts
  • src/main/claude-accounts/claude-account-service.test.ts
  • src/main/claude-accounts/claude-auth-capture.ts
  • src/main/claude-accounts/claude-command-process.test.ts
  • src/main/claude-accounts/claude-command-process.ts
  • src/main/claude-accounts/claude-credential-persistence-ratchet.test.ts
  • src/main/claude-accounts/claude-login-completion.oracle.test.ts
  • src/main/claude-accounts/claude-login-session.ts
  • src/main/claude-accounts/claude-managed-auth-storage.ts
  • src/main/claude-accounts/claude-profile-installed-router.ts
  • src/main/claude-accounts/claude-profile-paths.test.ts
  • src/main/claude-accounts/claude-profile-paths.ts
  • src/main/claude-accounts/claude-profile-provisioning.test.ts
  • src/main/claude-accounts/claude-profile-provisioning.ts
  • src/main/claude-accounts/claude-profile-router.test.ts
  • src/main/claude-accounts/claude-profile-router.ts
  • src/main/claude-accounts/claude-profile-setup.test.ts
  • src/main/claude-accounts/claude-profile-setup.ts
  • src/main/claude-accounts/claude-profile-shell-composition.test.ts
  • src/main/claude-accounts/claude-profile-wsl-paths.ts
  • src/main/claude-accounts/claude-profile-wsl-router.test.ts
  • src/main/claude-accounts/claude-profile-wsl-router.ts
  • src/main/claude-accounts/claude-windows-interactive-login.test.ts
  • src/main/claude-accounts/environment.ts
  • src/main/claude-accounts/keychain.test.ts
  • src/main/claude-accounts/keychain.ts
  • src/main/claude-accounts/live-pty-gate.test.ts
  • src/main/claude-accounts/live-pty-gate.ts
  • src/main/claude-accounts/managed-auth-path.ts
  • src/main/claude-accounts/oauth-refresh.test.ts
  • src/main/claude-accounts/oauth-refresh.ts
  • src/main/claude-accounts/runtime-auth-path-materialization.test.ts
  • src/main/claude-accounts/runtime-auth-service-account-switching.test.ts
  • src/main/claude-accounts/runtime-auth-service-deselect-restore.test.ts
  • src/main/claude-accounts/runtime-auth-service-keychain-snapshots.test.ts
  • src/main/claude-accounts/runtime-auth-service-launch-refresh.test.ts
  • src/main/claude-accounts/runtime-auth-service-materialization.test.ts
  • src/main/claude-accounts/runtime-auth-service-readback-identity.test.ts
  • src/main/claude-accounts/runtime-auth-service-shared-credential-failures.test.ts
  • src/main/claude-accounts/runtime-auth-service-shared-credentials.test.ts
  • src/main/claude-accounts/runtime-auth-service-snapshot-validation.test.ts
  • src/main/claude-accounts/runtime-auth-service-test-harness.ts
  • src/main/claude-accounts/runtime-auth-service-wsl-runtime.test.ts
  • src/main/claude-accounts/runtime-auth-service.test.ts
  • src/main/claude-accounts/runtime-auth-service.ts
  • src/main/claude-accounts/runtime-auth-shared-credentials-fixture.ts
  • src/main/claude-accounts/runtime-auth/runtime-auth-credential-identity.ts
  • src/main/claude-accounts/runtime-auth/runtime-auth-credential-matching.ts
  • src/main/claude-accounts/runtime-auth/runtime-auth-file-storage.ts
  • src/main/claude-accounts/runtime-auth/runtime-auth-keychain-snapshots.ts
  • src/main/claude-accounts/runtime-auth/runtime-auth-managed-credentials.ts
  • src/main/claude-accounts/runtime-auth/runtime-auth-preparation.ts
  • src/main/claude-accounts/runtime-auth/runtime-auth-readback.ts
  • src/main/claude-accounts/runtime-auth/runtime-auth-runtime-state.ts
  • src/main/claude-accounts/runtime-auth/runtime-auth-snapshot-capture.ts
  • src/main/claude-accounts/runtime-auth/runtime-auth-snapshot-restore.ts
  • src/main/claude-accounts/runtime-auth/runtime-auth-state.ts
  • src/main/claude-accounts/runtime-auth/runtime-auth-sync.ts
  • src/main/claude-accounts/runtime-auth/runtime-auth-types.ts
  • src/main/claude-accounts/runtime-paths.test.ts
  • src/main/claude-accounts/runtime-paths.ts
  • src/main/claude-accounts/service.ts
  • src/main/claude-accounts/shared-credential-fields.test.ts
  • src/main/claude-accounts/shared-credential-fields.ts
  • src/main/claude-accounts/shared-credential-reconciliation.test.ts
  • src/main/claude/claude-model-catalog-probe.ts
  • src/main/claude/claude-stream-json-connection.test.ts
  • src/main/claude/claude-stream-json-connection.ts
  • src/main/claude/claude-structured-auth-parity.test.ts
  • src/main/claude/claude-structured-effort-default-at-rest.test.ts
  • src/main/claude/claude-structured-launch-account-routing.test.ts
  • src/main/claude/claude-structured-launch-home.ts
  • src/main/claude/claude-structured-launch-resolution.test.ts
  • src/main/claude/claude-structured-launch-resolution.ts
  • src/main/claude/claude-structured-session-acquisition.ts
  • src/main/daemon/daemon-foreground-confirmation-protocol.test.ts
  • src/main/daemon/daemon-init-provider-installation.test.ts
  • src/main/daemon/daemon-protocol-version.ts
  • src/main/daemon/daemon-provider-init.ts
  • src/main/daemon/daemon-provider-state.ts
  • src/main/daemon/pty-subprocess/shell-launch-plan.ts
  • src/main/ipc/claude-accounts.ts
  • src/main/ipc/pty-listener-teardown-and-orphans.test.ts
  • src/main/ipc/pty-spawn-env-terminal-basics.test.ts
  • src/main/ipc/pty/ipc/claude-old-terminal.test.ts
  • src/main/ipc/pty/ipc/claude-old-terminal.ts
  • src/main/ipc/pty/ipc/spawn-commit.ts
  • src/main/ipc/pty/ipc/spawn-env.ts
  • src/main/ipc/pty/ipc/spawn-preflight.ts
  • src/main/ipc/pty/provider/bind-listeners.ts
  • src/main/ipc/pty/provider/liveness.ts
  • src/main/ipc/pty/provider/local-configure.ts
  • src/main/ipc/pty/provider/state-cleanup.ts
  • src/main/ipc/pty/register-handlers.ts
  • src/main/ipc/pty/runtime/spawn-commit.ts
  • src/main/ipc/pty/runtime/spawn-preflight-requested-shell.test.ts
  • src/main/ipc/pty/runtime/spawn-preflight.ts
  • src/main/macos-keychain/generic-password.test.ts
  • src/main/macos-keychain/generic-password.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-adapter.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-failure-text.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-pre-spawn-first-answer.test.ts
  • src/main/native-chat/claude-structured-managed-account-support.test.ts
  • src/main/native-chat/claude-structured-managed-account-support.ts
  • src/main/native-chat/structured-agent-session-create-support.test.ts
  • src/main/native-chat/structured-agent-session-create-support.ts
  • src/main/persistence-worktree-lineage-and-backups.test.ts
  • src/main/persistence/leasing-ssh-ptys/ssh-target-state.ts
  • src/main/persistence/loading-store/normalize-loaded-profile-state.ts
  • src/main/persistence/loading-store/profile-state-direct-flush.test.ts
  • src/main/persistence/loading-store/ssh-profile-operations.ts
  • src/main/persistence/loading-store/store-domain-composition.ts
  • src/main/persistence/restoring-sessions/pane-alias-normalization.ts
  • src/main/providers/local-pty-windows-spawn-environment.ts
  • src/main/providers/windows-shell-args.test.ts
  • src/main/providers/windows-shell-args.ts
  • src/main/rate-limits/claude-active-usage-fetch.ts
  • src/main/rate-limits/claude-cli-usage-fetch.ts
  • src/main/rate-limits/claude-fetcher-cli-fallback.test.ts
  • src/main/rate-limits/claude-fetcher-extra-usage.test.ts
  • src/main/rate-limits/claude-fetcher-fable-usage.test.ts
  • src/main/rate-limits/claude-fetcher-keychain-credentials.test.ts
  • src/main/rate-limits/claude-fetcher-managed-account-usage.test.ts
  • src/main/rate-limits/claude-fetcher-test-harness.ts
  • src/main/rate-limits/claude-fetcher.ts
  • src/main/rate-limits/claude-managed-account-credentials.ts
  • src/main/rate-limits/claude-managed-account-usage.ts
  • src/main/rate-limits/claude-managed-usage-panel.ts
  • src/main/rate-limits/claude-oauth-credentials.ts
  • src/main/rate-limits/claude-oauth-recovery.ts
  • src/main/rate-limits/claude-profile-usage.test.ts
  • src/main/rate-limits/claude-pty-reset-parser.ts
  • src/main/rate-limits/claude-pty-stop-markers.ts
  • src/main/rate-limits/claude-pty-usage-parser.ts
  • src/main/rate-limits/claude-pty.test.ts
  • src/main/rate-limits/claude-pty.ts
  • src/main/rate-limits/claude-usage-error-classification.test.ts
  • src/main/rate-limits/claude-usage-error-classification.ts
  • src/main/rate-limits/claude-usage-refresh-plan.test.ts
  • src/main/rate-limits/claude-usage-refresh-plan.ts
  • src/main/rate-limits/claude-usage-result.ts
  • src/main/rate-limits/hidden-pty-cleanup.test.ts
  • src/main/rate-limits/hidden-pty-cleanup.ts
  • src/main/rate-limits/service-account-target-selection.test.ts
  • src/main/rate-limits/service-inactive-account-previews.test.ts
  • src/main/rate-limits/service-live-claude-usage.test.ts
  • src/main/rate-limits/service/service-account-refresh.ts
  • src/main/rate-limits/service/service-fetch-policy.ts
  • src/main/runtime/orca-runtime-get-structured-agent-session-create-support.ts
  • src/main/runtime/orca-runtime-get-worktree-ps.ts
  • src/main/runtime/orca-runtime-structured-claude-account-gate.test.ts
  • src/main/runtime/orca-runtime-structured-claude-gate-wiring.test.ts
  • src/main/runtime/rpc/methods/accounts.test.ts
  • src/main/runtime/rpc/methods/accounts.ts
  • src/main/runtime/runtime-account-controller.ts
  • src/main/runtime/runtime-service-command-surface.ts
  • src/main/runtime/structured-agent-create-support-opencode-rig.test.ts
  • src/main/runtime/structured-agent-launch-support.ts
  • src/main/runtime/structured-agent-runtime-registrations.ts
  • src/main/runtime/structured-agent-session-runtime.ts
  • src/main/runtime/structured-claude-runtime-adapter.ts
  • src/main/shell-wrapper-generated-file-snapshot.test.ts
  • src/main/startup/main-process-account-services.ts
  • src/main/startup/main-process-ready-foundation.ts
  • src/main/startup/main-process-ready-identity-write.test.ts
  • src/main/startup/main-window-core-services.test.ts
  • src/main/startup/main-window-core-services.ts
  • src/preload/api/pty-api.ts
  • src/preload/api/pty-bridge-stream-and-serialization.ts
  • src/renderer/src/app-shell/use-app-shell-services.ts
  • src/renderer/src/components/native-chat/NativeChatNoticeRow.tsx
  • src/renderer/src/components/native-chat/NativeChatStructuredSession.tsx
  • src/renderer/src/components/native-chat/agent-session-failure-words-text.ts
  • src/renderer/src/components/native-chat/native-chat-claude-sign-in.test.tsx
  • src/renderer/src/components/native-chat/native-chat-claude-sign-in.ts
  • src/renderer/src/components/native-chat/native-chat-structured-session-notices.ts
  • src/renderer/src/components/settings/accounts-pane-account-actions.ts
  • src/renderer/src/components/settings/accounts-pane-claude-section.test.tsx
  • src/renderer/src/components/settings/accounts-pane-claude-section.tsx
  • src/renderer/src/components/settings/accounts-pane-removal-dialogs.tsx
  • src/renderer/src/components/status-bar/ClaudeSwitcherMenu.tsx
  • src/renderer/src/components/status-bar/InlineProviderUsage.tsx
  • src/renderer/src/components/status-bar/StatusBarProviderSegment.tsx
  • src/renderer/src/components/status-bar/StatusBarSurface.tsx
  • src/renderer/src/components/status-bar/claude-status-sign-in.test.tsx
  • src/renderer/src/components/status-bar/inline-usage-bars.test.tsx
  • src/renderer/src/components/status-bar/status-bar-claude-accounts.ts
  • src/renderer/src/components/status-bar/status-bar-runtime-groups.test.ts
  • src/renderer/src/components/status-bar/status-bar-runtime-targets.ts
  • src/renderer/src/components/status-bar/tooltip.test.ts
  • src/renderer/src/components/status-bar/usage-error-copy.ts
  • src/renderer/src/components/status-bar/usage-provider-settings-target.test.ts
  • src/renderer/src/components/status-bar/usage-provider-settings-target.ts
  • src/renderer/src/components/status-bar/usage-roster-row-state.test.ts
  • src/renderer/src/components/status-bar/use-status-bar-controller.ts
  • src/renderer/src/components/terminal-pane/ClaudeOldTerminalBanner.tsx
  • src/renderer/src/components/terminal-pane/CodexOldTerminalDialog.tsx
  • src/renderer/src/components/terminal-pane/CodexSharedServerBanner.tsx
  • src/renderer/src/components/terminal-pane/OldTerminalDialog.tsx
  • src/renderer/src/components/terminal-pane/PaneTopWarningBanner.tsx
  • src/renderer/src/components/terminal-pane/TerminalPaneRuntimePortals.tsx
  • src/renderer/src/components/terminal-pane/claude-old-terminal-banner.test.tsx
  • src/renderer/src/components/terminal-pane/open-terminal-beside-tab.ts
  • src/renderer/src/i18n/en-runtime-required.json
  • src/renderer/src/i18n/locales/en.json
  • src/renderer/src/i18n/locales/es.json
  • src/renderer/src/i18n/locales/fr.json
  • src/renderer/src/i18n/locales/ja.json
  • src/renderer/src/i18n/locales/ko.json
  • src/renderer/src/i18n/locales/zh.json
  • src/renderer/src/lib/claude-account-sign-in-notice.test.ts
  • src/renderer/src/lib/claude-account-sign-in-notice.ts
  • src/renderer/src/lib/claude-account-sign-in.ts
  • src/renderer/src/store/slices/ui-notice-dismissals.test.ts
  • src/renderer/src/store/slices/ui/ui-slice-contract-contextual.ts
  • src/renderer/src/store/slices/ui/ui-slice-hydration-actions.ts
  • src/renderer/src/store/slices/ui/ui-slice-trust-actions.ts
  • src/renderer/src/web/preload-api/web-terminal-api.ts
  • src/shared/agent-session-failure-copy.ts
  • src/shared/agent-session-failure-words.ts
  • src/shared/agent-session-failure.ts
  • src/shared/agent-session-refusal-details.ts
  • src/shared/agent-session-refusal-reason-words.ts
  • src/shared/claude-profile-activation-contract.test.ts
  • src/shared/claude-profile-routing.ts
  • src/shared/claude-shell-function.test.ts
  • src/shared/claude-shell-function.ts
  • src/shared/constants.ts
  • src/shared/global-settings-types.ts
  • src/shared/local-build-compatibility-contract.json
  • src/shared/local-build-compatibility-contract.ts
  • src/shared/managed-account-types.ts
  • src/shared/persisted-state-types.ts
  • src/shared/persisted-ui-state-types.ts
  • src/shared/protocol-version.ts
  • src/shared/rate-limit-types.ts
  • src/shared/rpc-contract/accounts-params.ts
  • src/shared/rpc-contract/client-ui-params.ts
  • src/shared/structured-agent-session-dispatch-rejection.ts
  • src/shared/wsl-login-shell-command.ts
💤 Files with no reviewable changes (51)
  • src/shared/rpc-contract/client-ui-params.ts
  • src/main/ipc/pty/ipc/claude-old-terminal.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-adapter.ts
  • src/main/ipc/pty/register-handlers.ts
  • src/main/claude-accounts/claude-account-folder.test.ts
  • src/main/claude-accounts/runtime-auth-service.test.ts
  • src/main/claude-accounts/claude-credential-persistence-ratchet.test.ts
  • src/shared/global-settings-types.ts
  • src/preload/api/pty-api.ts
  • src/main/ipc/pty/ipc/claude-old-terminal.ts
  • src/main/claude/claude-structured-effort-default-at-rest.test.ts
  • src/renderer/src/web/preload-api/web-terminal-api.ts
  • src/main/ipc/pty/runtime/spawn-preflight-requested-shell.test.ts
  • src/shared/persisted-ui-state-types.ts
  • .github/workflows/pr.yml
  • src/shared/agent-session-refusal-details.ts
  • src/renderer/src/i18n/en-runtime-required.json
  • src/main/fixtures/shell-wrapper-snapshots/local-zsh-zshenv.txt
  • src/renderer/src/store/slices/ui/ui-slice-hydration-actions.ts
  • src/shared/agent-session-failure.ts
  • src/main/claude-accounts/claude-command-process.test.ts
  • src/shared/wsl-login-shell-command.ts
  • src/main/shell-wrapper-generated-file-snapshot.test.ts
  • src/main/claude-accounts/claude-account-service.test.ts
  • src/renderer/src/components/native-chat/agent-session-failure-words-text.ts
  • src/main/fixtures/shell-wrapper-snapshots/relay-zsh-zshenv.txt
  • src/shared/agent-session-refusal-reason-words.ts
  • src/renderer/src/components/terminal-pane/TerminalPaneRuntimePortals.tsx
  • src/main/fixtures/shell-wrapper-snapshots/local-bash-rcfile.txt
  • src/renderer/src/store/slices/ui-notice-dismissals.test.ts
  • src/renderer/src/store/slices/ui/ui-slice-contract-contextual.ts
  • src/preload/api/pty-bridge-stream-and-serialization.ts
  • src/main/fixtures/shell-wrapper-snapshots/daemon-zsh-zshenv.txt
  • src/renderer/src/app-shell/use-app-shell-services.ts
  • src/shared/structured-agent-session-dispatch-rejection.ts
  • src/renderer/src/components/status-bar/inline-usage-bars.test.tsx
  • src/renderer/src/components/status-bar/status-bar-runtime-targets.ts
  • src/shared/agent-session-failure-copy.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-pre-spawn-first-answer.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-failure-text.ts
  • src/shared/protocol-version.ts
  • src/main/claude-accounts/claude-account-folder.ts
  • src/renderer/src/store/slices/ui/ui-slice-trust-actions.ts
  • src/shared/agent-session-failure-words.ts
  • src/shared/rpc-contract/accounts-params.ts
  • src/renderer/src/components/status-bar/usage-provider-settings-target.ts
  • src/renderer/src/components/status-bar/status-bar-runtime-groups.test.ts
  • src/main/fixtures/shell-wrapper-snapshots/daemon-bash-rcfile.txt
  • src/renderer/src/components/native-chat/NativeChatNoticeRow.tsx
  • src/main/claude-accounts/claude-profile-wsl-paths.ts
  • src/shared/managed-account-types.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Comment on lines +241 to +244
if (restoredCredentials) {
this.dependencies.selection.restoreSettings(previousSettings)
await this.dependencies.runtimeAuth.forceMaterializeCurrentSelectionForRollback()
} else if (wroteCredentials) {

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 | 🟡 Minor | ⚡ Quick win

Guard the rematerialize call in the reauth rollback.

If restoreCredentials succeeds, rollbackReauthentication awaits forceMaterializeCurrentSelectionForRollback() with no guard. If that call throws, its error replaces the original reauth error. The caller then sees the wrong failure.

cleanupFailedAdd already guards the same call with a try/catch and console.warn. The add-account test notes that the unguarded version caused this exact problem on the add path. Use the same guard here.

Proposed fix
--- "a/src/main/claude-accounts/claude-account-registration.ts"
+++ "b/src/main/claude-accounts/claude-account-registration.ts"
@@ -238,10 +238,14 @@
         )
       }
     }
     if (restoredCredentials) {
       this.dependencies.selection.restoreSettings(previousSettings)
-      await this.dependencies.runtimeAuth.forceMaterializeCurrentSelectionForRollback()
+      try {
+        await this.dependencies.runtimeAuth.forceMaterializeCurrentSelectionForRollback()
+      } catch (rollbackError) {
+        console.warn('[claude-accounts] Rollback rematerialization failed:', rollbackError)
+      }
     } else if (wroteCredentials) {
       this.dependencies.store.updateSettings({ claudeManagedAccounts: nextAccounts })
     } else {
       this.dependencies.selection.restoreSettings(previousSettings)
📝 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
if (restoredCredentials) {
this.dependencies.selection.restoreSettings(previousSettings)
await this.dependencies.runtimeAuth.forceMaterializeCurrentSelectionForRollback()
} else if (wroteCredentials) {
if (restoredCredentials) {
this.dependencies.selection.restoreSettings(previousSettings)
try {
await this.dependencies.runtimeAuth.forceMaterializeCurrentSelectionForRollback()
} catch (rollbackError) {
console.warn('[claude-accounts] Rollback rematerialization failed:', rollbackError)
}
} else if (wroteCredentials) {

Comment on lines +62 to +67
await this.removeManagedAuth(accountId, account.managedAuthPath)
this.rateLimits.evictInactiveClaudeCache(accountId)
await this.rateLimits.refreshForClaudeAccountChange(
wasSelected ? accountId : undefined,
target
)

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.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

#!/bin/bash
# Check whether refreshForClaudeAccountChange can reject, or whether it catches errors internally.
ast-grep outline src/main/rate-limits/service.ts --match 'refreshForClaudeAccountChange' --view expanded 2>/dev/null
rg -nP -A30 '\brefreshForClaudeAccountChange\s*\(' src/main/rate-limits | head -80

Repository: stablyai/orca

Length of output: 8178


🏁 Script executed:

set -eu
printf '%s\n' '--- claude-account-selection.ts relevant declarations ---'
nl -ba src/main/claude-accounts/claude-account-selection.ts | sed -n '1,190p'
printf '%s\n' '--- service-account-refresh.ts refresh and fetch declarations ---'
rg -n -F -- 'async fetchClaudeOnly' src/main/rate-limits
rg -n -F -- 'fetchClaudeOnly(' src/main/rate-limits/service
nl -ba src/main/rate-limits/service/service-account-refresh.ts | sed -n '1,210p'

Repository: stablyai/orca

Length of output: 19158


🏁 Script executed:

set +e
printf '%s\n' '--- selection methods ---'
nl -ba src/main/claude-accounts/claude-account-selection.ts | sed -n '35,145p'
printf '%s\n' '--- fetchClaudeOnly bindings ---'
rg -n -F -- 'fetchClaudeOnly' src/main/rate-limits src/main | head -80
printf '%s\n' '--- Claude refresh implementation ---'
nl -ba src/main/rate-limits/service/service-account-refresh.ts | sed -n '140,180p'

Repository: stablyai/orca

Length of output: 8513


🏁 Script executed:

set -eu
nl -ba src/main/rate-limits/service/service-fetch-queue.ts | sed -n '90,180p'
rg -n -F -- 'fetchClaudeRateLimits' src/main/rate-limits src/main | head -40

Repository: stablyai/orca

Length of output: 8454


🏁 Script executed:

set -eu
nl -ba src/main/rate-limits/service/service-fetch-queue.ts | sed -n '115,175p'

Repository: stablyai/orca

Length of output: 2536


🏁 Script executed:

set -eu
rg -n -F -- 'runWithFetchAbortSignal' src/main/rate-limits/service
rg -n -F -- 'runFetchClaudeOnlyCycle' src/main/rate-limits/service

Repository: stablyai/orca

Length of output: 3035


🏁 Script executed:

set +e
printf '%s\n' '--- nested method locations ---'
rg -n -F -- 'runWithFetchAbortSignal' src/main/rate-limits/service
rg -n -F -- 'runFetchClaudeOnlyCycle' src/main/rate-limits/service

Repository: stablyai/orca

Length of output: 3067


🏁 Script executed:

set -eu
printf '%s\n' '--- service-fetch-control.ts ---'
nl -ba src/main/rate-limits/service/service-fetch-control.ts | sed -n '1,100p'
printf '%s\n' '--- service-provider-cycles.ts Claude cycle ---'
nl -ba src/main/rate-limits/service/service-provider-cycles.ts | sed -n '60,135p'

Repository: stablyai/orca

Length of output: 6311


🏁 Script executed:

set +e
printf '%s\n' '--- resolver declarations and assignments ---'
rg -n -F -- 'claudeAuthPreparationResolver' src/main/rate-limits src/main | head -100
printf '%s\n' '--- preparation resolver APIs ---'
rg -n -F -- 'setClaudeAuthPreparationResolver' src/main/rate-limits src/main | head -80

Repository: stablyai/orca

Length of output: 4133


🏁 Script executed:

set -eu
printf '%s\n' '--- resolver binding ---'
nl -ba src/main/startup/main-process-account-services.ts | sed -n '105,140p'
printf '%s\n' '--- configuration API ---'
nl -ba src/main/rate-limits/service/service-configuration.ts | sed -n '1,55p'
printf '%s\n' '--- resolver target methods ---'
rg -n -F -- 'prepareClaude' src/main | head -80

Repository: stablyai/orca

Length of output: 11278


🏁 Script executed:

set -eu
rg -n -F -- 'prepareForRateLimitFetch' src/main

Repository: stablyai/orca

Length of output: 8095


🏁 Script executed:

set -eu
nl -ba src/main/claude-accounts/runtime-auth-service.ts | sed -n '1,105p'

Repository: stablyai/orca

Length of output: 5062


Keep rate-limit refresh failures out of the removal rollback.

remove() restores the account settings after removeManagedAuth has deleted the credentials. The provider fetch catches fetchClaudeRateLimits errors, but prepareForRateLimitFetch can still propagate an authentication-preparation failure through syncForCurrentSelection. That rejection reaches the remove() catch and recreates an account with no credentials.

Catch this refresh failure locally after managed-auth deletion and log a warning. Keep rollback for failures before deletion. The select() rollback does not have this issue because it does not delete managed authentication.

🐛 Suggested fix
-      await this.rateLimits.refreshForClaudeAccountChange(
-        wasSelected ? accountId : undefined,
-        target
-      )
+      await this.rateLimits
+        .refreshForClaudeAccountChange(wasSelected ? accountId : undefined, target)
+        .catch((error: unknown) => {
+          console.warn('[rate-limits] Failed to refresh Claude usage after account removal:', error)
+        })
📝 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
await this.removeManagedAuth(accountId, account.managedAuthPath)
this.rateLimits.evictInactiveClaudeCache(accountId)
await this.rateLimits.refreshForClaudeAccountChange(
wasSelected ? accountId : undefined,
target
)
await this.removeManagedAuth(accountId, account.managedAuthPath)
this.rateLimits.evictInactiveClaudeCache(accountId)
await this.rateLimits
.refreshForClaudeAccountChange(wasSelected ? accountId : undefined, target)
.catch((error: unknown) => {
console.warn('[rate-limits] Failed to refresh Claude usage after account removal:', error)
})

controller.abort()
return true
})
const previousLegacyKeychain = await readActiveClaudeKeychainCredentials()

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 | 🟡 Minor | ⚡ Quick win

Move the legacy Keychain read inside the try block.

readActiveClaudeKeychainCredentials() runs after two setup steps but before the try/finally:

  • createTemporaryClaudeConfigDir has already run.
  • setCancel has already registered a cancel handler.

The read can throw, for example on a security timeout or a locked Keychain. If it throws, the finally block never runs, so:

  • The temporary config directory leaks. On WSL this is a leftover directory inside the distro.
  • cancelPendingClaudeLogin still points to the dead controller. The next supersedePendingLogin then logs a false "Cancelled a pending Claude login".

Read the value inside the try block. The finally block uses the value, so declare it before the try. Use let previousLegacyKeychain: string | null = null, and only restore when the read succeeded.

Comment on lines +56 to +61
if (refreshed) {
try {
await writeClaudeManagedCredentialsJson(location, refreshed)
} catch {
// Keep the refreshed token for this fetch; a later poll can persist it.
}

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.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

A failed persist drops the rotated refresh token.

Claude refresh tokens are single-use (see oauth-refresh.ts). After refreshClaudeOauthCredentials succeeds, the stored refresh token is already spent.

If writeClaudeManagedCredentialsJson throws (for example, a transient macOS Keychain write failure), the catch block discards the error. The refreshed blob is kept only in a local variable. The comment says "a later poll can persist it", but no later poll can: the next poll reads the old, spent refresh token from storage. The refresh then fails with invalid_grant, and the inactive account must re-authenticate.

Fix:

  • Retry the write once.
  • Log the failure at warn or error level.
  • Correct the comment so it does not promise recovery that does not happen.

Keeping the refreshed blob in memory per account would let the next poll persist it.

Minimal fix
--- "a/src/main/rate-limits/claude-managed-account-usage.ts"
+++ "b/src/main/rate-limits/claude-managed-account-usage.ts"
@@ -53,12 +53,17 @@
     if (options.signal?.aborted) {
       return abortedClaudeRateLimitResult()
     }
     if (refreshed) {
       try {
         await writeClaudeManagedCredentialsJson(location, refreshed)
-      } catch {
-        // Keep the refreshed token for this fetch; a later poll can persist it.
+      } catch (error) {
+        // Why: the previous refresh token is now spent; retry once so the rotation is not lost.
+        try {
+          await writeClaudeManagedCredentialsJson(location, refreshed)
+        } catch {
+          console.warn('[claude-rate-limits] Failed to persist rotated inactive-account credentials:', error)
+        }
       }
       credentialsJson = refreshed
       token = parseClaudeOAuthCredentialsJson(refreshed, 'credentials-file').token
     }
📝 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
if (refreshed) {
try {
await writeClaudeManagedCredentialsJson(location, refreshed)
} catch {
// Keep the refreshed token for this fetch; a later poll can persist it.
}
if (refreshed) {
try {
await writeClaudeManagedCredentialsJson(location, refreshed)
} catch (error) {
// Why: the previous refresh token is now spent; retry once so the rotation is not lost.
try {
await writeClaudeManagedCredentialsJson(location, refreshed)
} catch {
console.warn('[claude-rate-limits] Failed to persist rotated inactive-account credentials:', error)
}
}

@Jinwoo-H
Jinwoo-H merged commit 9ca9b4e into main Oct 8, 2026
37 of 41 checks passed
@OrcaWin OrcaWin mentioned this pull request Oct 9, 2026
9 tasks done
Jinwoo-H added a commit that referenced this pull request Oct 9, 2026
…and proxy fixes (#26801)

* Revert "Revert Claude per-account folders (#24434, #26405) before release (#26638)"

This reverts commit 9ca9b4e.

* Move the terminal daemon protocol to 44 for the re-landed claude function

v43 daemons (the revert) lack the claude account function, so new terminals must not reuse them. v42 and v43 stay attachable.

* Move the local build compatibility contract to daemon protocol 44

* Point the old-terminal test at daemon protocol 44

* Claude accounts re-land: never sign anyone out, keep proxies working, accounts mirror ~/.claude (#26769)

* Run a Claude account on System default until it has its own login

An account saved before per-account folders has no login in its folder. While System default (~/.claude, or the user's own CLAUDE_CONFIG_DIR) is signed in to the same email, the router sends every launch there and writes that choice into the pointer file, so nobody is logged out by the update. Once the account signs in to its own folder, the next launch uses it. The WSL router follows the same rule with the guest's ~/.claude.

* Refresh each Claude account folder from ~/.claude before every launch

~/.claude (or the user's own CLAUDE_CONFIG_DIR) is now the master copy. Each account folder gets its whole settings.json, including the proxy address and its key, and every .claude.json key except the login, Claude's account caches and install ids, so first-run questions are not asked again. Every other top-level entry is linked (folders) or copied (files), except Claude's per-folder daemon, jobs, live sessions, login files and throwaways. sessions is no longer shared, and an earlier link is undone.

The refresh runs before every Claude Orca starts, for each new terminal and on account switch. Orca never writes back to ~/.claude. The ledger that tracked selective sharing is gone.

* Route chat auth and unselected-account usage through the Claude router

Chats decided whether to drop inherited Anthropic auth from the selection alone, so an account running on System default lost the user's own key. They now ask the router, as terminals, AI commit messages, automations and usage already do. Usage for an unselected account is read where its launches would run. A test reads every entry point through the fallback and fails if a launch path outside the router reads the Claude selection or builds an account folder. The router's two launch errors move to their own file to keep it under the line limit.

* Show Claude account sign-in prompts only when an account cannot run

With the fallback, an account System default is signed in to already works, so:
- The one-time "Finish setting up your Claude accounts" toast is gone.
- Accounts System default covers no longer need a sign-in: no Sign in in the status bar menu or Settings, and they can be selected.
- The old-terminal banner shows only when claude in that terminal would run a different account than the selected one, and asks again after a switch. Its wording is unchanged.

The retired toast's saved flag stays in the paired-client schema so an older client's write is still accepted. The email comparison moves beside the login reader to keep the router under the line limit.

* Keep the user's shell Anthropic auth on Claude account launches

A signed-in account's launches used to drop ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN and CLAUDE_CODE_OAUTH_TOKEN from the inherited environment while ANTHROPIC_BASE_URL passed through, so a proxy set in the shell got the subscription login and answered 401. Host launches on an account now keep the shell's auth with its address, as System default does. Chats still name the account kind in a failed sign-in, now from the router rather than from whether auth was dropped.

* Share from ~/.claude only what Claude itself would seed into a new folder

The deny list missed much of Claude's runtime state, so tokens, locks and live files such as .session_ingress_token, server-sessions.json and remote-control were copied or linked over each account's own every launch. The list now mirrors the one Claude uses when it seeds a fresh config folder from ~/.claude: its runtime entries, every hidden entry, daemon files and agent memory. teams, ide, downloads and scratch are on it, so they stay per folder.

* Merge trusted folders and MCP servers into an account instead of replacing them

Each refresh replaced the account's projects and mcpServers with ~/.claude's, so folder trust and allowed tools recorded only in the account were lost, and a refresh landing between Orca's folder-trust write and Claude's start brought the trust dialog back. Both are now merged per folder path or server name: ~/.claude wins for entries it has, the account keeps the rest, and a folder trusted in the account stays trusted. Both writers take Claude's lock on the file, so the order no longer matters.

* Require the same organization before System default stands in for an account

The fallback compared emails only, so one email saved for two organizations made both accounts run on whichever organization System default was signed in to. When the saved account and System default's login both name an organization, it must now match too, on the host and in WSL, and the old-terminal banner uses the same comparison. The saved-account lookup the three checks repeated is now one helper.

* Treat v42 terminals as having the claude account function

v42 daemons shipped the same claude function and pointer path as v44, so claude in those terminals already follows the selected account. The old-terminal banner now shows only for daemons before v42 and for v43, the revert, which dropped the function.

* Fail the routing test when a new module resolves the claude binary

The census only caught code that read the Claude selection, not a new launcher that runs claude without asking the router. A second check now lists every module that resolves the claude binary or loads the Agent SDK, each with why it is routed, and fails on any new one, or on a listed one that no longer matches.

* Skip the account refresh on launches that run on System default

A launch that falls back to System default never uses the account folder, so starting a setup for it on every launch was wasted work. Account switches still set the folder up for a later sign-in.

* Give a terminal opened before the login shell's env only the account pointer

At startup, a pane could be routed before the login shell reported the user's own CLAUDE_CONFIG_DIR, so the fallback compared against ~/.claude.json instead. Until that env arrives a pane gets only the pointer, and the pointer is rewritten once it does, so claude typed there reads the right folder. The recent claude --version answer moves beside the version probe to keep the router under the line limit.

* Drop the chat-only Anthropic auth stripping and override refusal

Chats no longer drop the shell's Anthropic auth on any account, so the chat launch's override refusal and the policy's stripAuthEnv could only be reached from test fixtures. The structured auth policy is now just which login a failed sign-in names. Terminals keep their refusal, which still guards WSL launches; the failure reason stays in the shared vocabulary for older peers.

* Publish a new account state file whole

The first .claude.json write went straight to the target, so a crash mid-write could leave Claude a truncated state file. It is now written to a staged file and linked into place without replacing one Claude created meanwhile.

* Read an unselected WSL account's usage where the WSL router would run it

Usage for an unselected WSL account read its saved folder directly, so an account the guest's ~/.claude covers showed no usage, and the read bypassed the router. It now asks the WSL router, after the same check that the distro is already running.

* Keep the shell's Anthropic auth when the claude function runs an account

The claude shell function (POSIX, fish and PowerShell) unset ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN, CLAUDE_CODE_OAUTH_TOKEN, AWS_BEARER_TOKEN_BEDROCK and auth-like ANTHROPIC_CUSTOM_HEADERS before running Claude in an account folder, so a proxy set in the shell lost its key while keeping its address. It now only sets CLAUDE_CONFIG_DIR and Orca's marker, as on System default. Protocol 44 is unreleased, so no new bump; the shell-wrapper snapshots are regenerated.

* Never drop the user's Anthropic auth from a Claude launch

Orca's launches stripped ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN, CLAUDE_CODE_OAUTH_TOKEN, AWS_BEARER_TOKEN_BEDROCK and auth-like ANTHROPIC_CUSTOM_HEADERS for WSL terminals, terminal splits and through the preparation's stripAuthEnv flag, and refused a launch whose agent env set them. If the user's shell overrides the login, that is their setup: every launch now keeps it, on accounts, System default and WSL alike. The flag, the strip paths and the override refusal are gone; the refusal's reason stays in the shared vocabulary so older peers still decode it.

Orca's own process env and the claude --version probe still drop these variables: they are Orca's, not the user's launch.

* Leave out of an account's state everything Claude resets when it signs out

The .claude.json copy left out the login and keys matching cache patterns, but still carried account state such as additionalModelOptionsAnsweredAt, artifactRosterDenied, lastSeenOrgDefaultUpdatedAt and the subscription notices. The copy now leaves out the exact keys Claude resets on logout, beside the install ids, Console API key and first-token date; the cache patterns stay for account caches logout does not reset. Onboarding is still copied.

* Judge an old terminal's Claude banner by the pane's own runtime

The banner compared every old pane with the host selection and showed whenever only a WSL account was selected, so old host panes showed it with nothing to say and old WSL panes were judged by the host's account. The pane now names its runtime: a host pane is compared with the host selection, a WSL pane with its distro's selection through the WSL router, and a pane whose runtime is unknown, or with no account selected for it, stays hidden.

* Leave an account's settings file alone when only Orca's hooks differ from the default home's

* Reread a WSL account's Claude state only when the file changes

* Move tests merged from main onto the account-only Claude auth policy
brennanb2025 pushed a commit that referenced this pull request Oct 15, 2026
…and proxy fixes (#26801)

* Revert "Revert Claude per-account folders (#24434, #26405) before release (#26638)"

This reverts commit 9ca9b4e.

* Move the terminal daemon protocol to 44 for the re-landed claude function

v43 daemons (the revert) lack the claude account function, so new terminals must not reuse them. v42 and v43 stay attachable.

* Move the local build compatibility contract to daemon protocol 44

* Point the old-terminal test at daemon protocol 44

* Claude accounts re-land: never sign anyone out, keep proxies working, accounts mirror ~/.claude (#26769)

* Run a Claude account on System default until it has its own login

An account saved before per-account folders has no login in its folder. While System default (~/.claude, or the user's own CLAUDE_CONFIG_DIR) is signed in to the same email, the router sends every launch there and writes that choice into the pointer file, so nobody is logged out by the update. Once the account signs in to its own folder, the next launch uses it. The WSL router follows the same rule with the guest's ~/.claude.

* Refresh each Claude account folder from ~/.claude before every launch

~/.claude (or the user's own CLAUDE_CONFIG_DIR) is now the master copy. Each account folder gets its whole settings.json, including the proxy address and its key, and every .claude.json key except the login, Claude's account caches and install ids, so first-run questions are not asked again. Every other top-level entry is linked (folders) or copied (files), except Claude's per-folder daemon, jobs, live sessions, login files and throwaways. sessions is no longer shared, and an earlier link is undone.

The refresh runs before every Claude Orca starts, for each new terminal and on account switch. Orca never writes back to ~/.claude. The ledger that tracked selective sharing is gone.

* Route chat auth and unselected-account usage through the Claude router

Chats decided whether to drop inherited Anthropic auth from the selection alone, so an account running on System default lost the user's own key. They now ask the router, as terminals, AI commit messages, automations and usage already do. Usage for an unselected account is read where its launches would run. A test reads every entry point through the fallback and fails if a launch path outside the router reads the Claude selection or builds an account folder. The router's two launch errors move to their own file to keep it under the line limit.

* Show Claude account sign-in prompts only when an account cannot run

With the fallback, an account System default is signed in to already works, so:
- The one-time "Finish setting up your Claude accounts" toast is gone.
- Accounts System default covers no longer need a sign-in: no Sign in in the status bar menu or Settings, and they can be selected.
- The old-terminal banner shows only when claude in that terminal would run a different account than the selected one, and asks again after a switch. Its wording is unchanged.

The retired toast's saved flag stays in the paired-client schema so an older client's write is still accepted. The email comparison moves beside the login reader to keep the router under the line limit.

* Keep the user's shell Anthropic auth on Claude account launches

A signed-in account's launches used to drop ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN and CLAUDE_CODE_OAUTH_TOKEN from the inherited environment while ANTHROPIC_BASE_URL passed through, so a proxy set in the shell got the subscription login and answered 401. Host launches on an account now keep the shell's auth with its address, as System default does. Chats still name the account kind in a failed sign-in, now from the router rather than from whether auth was dropped.

* Share from ~/.claude only what Claude itself would seed into a new folder

The deny list missed much of Claude's runtime state, so tokens, locks and live files such as .session_ingress_token, server-sessions.json and remote-control were copied or linked over each account's own every launch. The list now mirrors the one Claude uses when it seeds a fresh config folder from ~/.claude: its runtime entries, every hidden entry, daemon files and agent memory. teams, ide, downloads and scratch are on it, so they stay per folder.

* Merge trusted folders and MCP servers into an account instead of replacing them

Each refresh replaced the account's projects and mcpServers with ~/.claude's, so folder trust and allowed tools recorded only in the account were lost, and a refresh landing between Orca's folder-trust write and Claude's start brought the trust dialog back. Both are now merged per folder path or server name: ~/.claude wins for entries it has, the account keeps the rest, and a folder trusted in the account stays trusted. Both writers take Claude's lock on the file, so the order no longer matters.

* Require the same organization before System default stands in for an account

The fallback compared emails only, so one email saved for two organizations made both accounts run on whichever organization System default was signed in to. When the saved account and System default's login both name an organization, it must now match too, on the host and in WSL, and the old-terminal banner uses the same comparison. The saved-account lookup the three checks repeated is now one helper.

* Treat v42 terminals as having the claude account function

v42 daemons shipped the same claude function and pointer path as v44, so claude in those terminals already follows the selected account. The old-terminal banner now shows only for daemons before v42 and for v43, the revert, which dropped the function.

* Fail the routing test when a new module resolves the claude binary

The census only caught code that read the Claude selection, not a new launcher that runs claude without asking the router. A second check now lists every module that resolves the claude binary or loads the Agent SDK, each with why it is routed, and fails on any new one, or on a listed one that no longer matches.

* Skip the account refresh on launches that run on System default

A launch that falls back to System default never uses the account folder, so starting a setup for it on every launch was wasted work. Account switches still set the folder up for a later sign-in.

* Give a terminal opened before the login shell's env only the account pointer

At startup, a pane could be routed before the login shell reported the user's own CLAUDE_CONFIG_DIR, so the fallback compared against ~/.claude.json instead. Until that env arrives a pane gets only the pointer, and the pointer is rewritten once it does, so claude typed there reads the right folder. The recent claude --version answer moves beside the version probe to keep the router under the line limit.

* Drop the chat-only Anthropic auth stripping and override refusal

Chats no longer drop the shell's Anthropic auth on any account, so the chat launch's override refusal and the policy's stripAuthEnv could only be reached from test fixtures. The structured auth policy is now just which login a failed sign-in names. Terminals keep their refusal, which still guards WSL launches; the failure reason stays in the shared vocabulary for older peers.

* Publish a new account state file whole

The first .claude.json write went straight to the target, so a crash mid-write could leave Claude a truncated state file. It is now written to a staged file and linked into place without replacing one Claude created meanwhile.

* Read an unselected WSL account's usage where the WSL router would run it

Usage for an unselected WSL account read its saved folder directly, so an account the guest's ~/.claude covers showed no usage, and the read bypassed the router. It now asks the WSL router, after the same check that the distro is already running.

* Keep the shell's Anthropic auth when the claude function runs an account

The claude shell function (POSIX, fish and PowerShell) unset ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN, CLAUDE_CODE_OAUTH_TOKEN, AWS_BEARER_TOKEN_BEDROCK and auth-like ANTHROPIC_CUSTOM_HEADERS before running Claude in an account folder, so a proxy set in the shell lost its key while keeping its address. It now only sets CLAUDE_CONFIG_DIR and Orca's marker, as on System default. Protocol 44 is unreleased, so no new bump; the shell-wrapper snapshots are regenerated.

* Never drop the user's Anthropic auth from a Claude launch

Orca's launches stripped ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN, CLAUDE_CODE_OAUTH_TOKEN, AWS_BEARER_TOKEN_BEDROCK and auth-like ANTHROPIC_CUSTOM_HEADERS for WSL terminals, terminal splits and through the preparation's stripAuthEnv flag, and refused a launch whose agent env set them. If the user's shell overrides the login, that is their setup: every launch now keeps it, on accounts, System default and WSL alike. The flag, the strip paths and the override refusal are gone; the refusal's reason stays in the shared vocabulary so older peers still decode it.

Orca's own process env and the claude --version probe still drop these variables: they are Orca's, not the user's launch.

* Leave out of an account's state everything Claude resets when it signs out

The .claude.json copy left out the login and keys matching cache patterns, but still carried account state such as additionalModelOptionsAnsweredAt, artifactRosterDenied, lastSeenOrgDefaultUpdatedAt and the subscription notices. The copy now leaves out the exact keys Claude resets on logout, beside the install ids, Console API key and first-token date; the cache patterns stay for account caches logout does not reset. Onboarding is still copied.

* Judge an old terminal's Claude banner by the pane's own runtime

The banner compared every old pane with the host selection and showed whenever only a WSL account was selected, so old host panes showed it with nothing to say and old WSL panes were judged by the host's account. The pane now names its runtime: a host pane is compared with the host selection, a WSL pane with its distro's selection through the WSL router, and a pane whose runtime is unknown, or with no account selected for it, stays hidden.

* Leave an account's settings file alone when only Orca's hooks differ from the default home's

* Reread a WSL account's Claude state only when the file changes

* Move tests merged from main onto the account-only Claude auth policy

(cherry picked from commit 8b2a5e4)
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