mirror of
https://github.com/stablyai/orca.git
synced 2026-10-19 00:03:20 +00:00
fix(accounts): align auto runtime consumers
This commit is contained in:
@@ -3537,6 +3537,72 @@ describe('ClaudeRuntimeAuthService', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('uses the global WSL runtime for untargeted Claude preparation under auto', async () => {
|
||||
setPlatform('win32')
|
||||
vi.doMock('../wsl', () => ({
|
||||
getDefaultWslDistro: () => 'Ubuntu',
|
||||
getWslHome: () => null,
|
||||
toWindowsWslPath: (value: string) => value
|
||||
}))
|
||||
const ubuntuAuthPath = createManagedClaudeAuth(
|
||||
testState.userDataDir,
|
||||
'ubuntu-account',
|
||||
createClaudeCredentialsJson('ubuntu@example.com', 'ubuntu-token')
|
||||
)
|
||||
const settings = createSettings({
|
||||
localAccountRuntime: 'auto',
|
||||
localWindowsRuntimeDefault: { kind: 'wsl', distro: 'Ubuntu' },
|
||||
claudeManagedAccounts: [
|
||||
createClaudeAccount('ubuntu-account', ubuntuAuthPath, {
|
||||
managedAuthRuntime: 'wsl',
|
||||
wslDistro: 'Ubuntu',
|
||||
wslLinuxAuthPath: '/home/alice/.local/share/orca/claude-accounts/ubuntu/auth'
|
||||
})
|
||||
],
|
||||
activeClaudeManagedAccountId: null,
|
||||
activeClaudeManagedAccountIdsByRuntime: {
|
||||
host: null,
|
||||
wsl: { Ubuntu: 'ubuntu-account' }
|
||||
}
|
||||
})
|
||||
const store = createStore(settings)
|
||||
|
||||
const { ClaudeRuntimeAuthService } = await import('./runtime-auth-service')
|
||||
const service = new ClaudeRuntimeAuthService(store as never)
|
||||
const preparation = await service.prepareForClaudeLaunch()
|
||||
|
||||
expect(preparation).toMatchObject({
|
||||
runtime: 'wsl',
|
||||
wslDistro: 'Ubuntu',
|
||||
provenance: 'managed:ubuntu-account:wsl:Ubuntu'
|
||||
})
|
||||
})
|
||||
|
||||
it('ignores a persisted WSL account-runtime pin on non-Windows hosts', async () => {
|
||||
setPlatform('darwin')
|
||||
vi.doMock('../wsl', () => ({
|
||||
getDefaultWslDistro: () => 'Ubuntu',
|
||||
getWslHome: () => null,
|
||||
toWindowsWslPath: (value: string) => value
|
||||
}))
|
||||
const settings = createSettings({
|
||||
localAccountRuntime: 'wsl',
|
||||
localAccountWslDistro: 'Ubuntu'
|
||||
})
|
||||
const store = createStore(settings)
|
||||
|
||||
const { ClaudeRuntimeAuthService } = await import('./runtime-auth-service')
|
||||
const service = new ClaudeRuntimeAuthService(store as never)
|
||||
const preparation = await service.prepareForClaudeLaunch()
|
||||
|
||||
expect(preparation).toMatchObject({
|
||||
runtime: 'host',
|
||||
wslDistro: null,
|
||||
provenance: 'system',
|
||||
stripAuthEnv: false
|
||||
})
|
||||
})
|
||||
|
||||
it('keeps untargeted Claude preparation on host when account runtime is host', async () => {
|
||||
setPlatform('win32')
|
||||
vi.doMock('../wsl', () => ({
|
||||
|
||||
@@ -684,11 +684,9 @@ export class ClaudeRuntimeAuthService {
|
||||
private getDefaultAccountSelectionTarget(
|
||||
settings = this.store.getSettings()
|
||||
): ClaudeAccountSelectionTarget {
|
||||
// Why: auth defaults follow the resolved account runtime ('auto' tracks the
|
||||
// global WSL project default), not legacy terminal WSL settings that can
|
||||
// outlive the Terminal UI.
|
||||
// Why: Windows auth follows the resolved account runtime; stale cross-platform WSL pins must stay local-host.
|
||||
const resolved = resolveLocalAccountRuntimeTarget(settings)
|
||||
if (resolved.runtime === 'wsl') {
|
||||
if (process.platform === 'win32' && resolved.runtime === 'wsl') {
|
||||
return { runtime: 'wsl', wslDistro: resolved.wslDistro }
|
||||
}
|
||||
return { runtime: 'host' }
|
||||
|
||||
@@ -618,6 +618,8 @@ describe('Store', () => {
|
||||
expect(settings.terminalScrollSensitivity).toBe(1.15)
|
||||
expect(settings.terminalFastScrollSensitivity).toBe(5)
|
||||
expect(settings.terminalTuiScrollSensitivity).toBe(1)
|
||||
expect(settings.localAccountRuntime).toBe('auto')
|
||||
expect(settings.localAccountRuntimeDefaultedToAutoForAllUsers).toBe(true)
|
||||
expect(settings.terminalTuiScrollSensitivityDefaultedToOne).toBe(true)
|
||||
expect(settings.terminalUseSeparateLightTheme).toBe(true)
|
||||
expect(settings.rightSidebarOpenByDefault).toBe(true)
|
||||
|
||||
@@ -2959,9 +2959,7 @@ export class Store {
|
||||
) {
|
||||
this.loadNeedsSave = true
|
||||
}
|
||||
// Why (#9537): the legacy hard 'host' default pinned account detection to
|
||||
// Windows even for WSL projects. Flip the untouched default to 'auto' once
|
||||
// so it follows localWindowsRuntimeDefault; an explicit 'wsl' pin survives.
|
||||
// Why (#9537): migrate the indistinguishable legacy host default once so WSL-default users follow their runtime.
|
||||
const localAccountRuntimeAlreadyMigrated =
|
||||
parsed.settings?.localAccountRuntimeDefaultedToAutoForAllUsers === true
|
||||
const migratedLocalAccountRuntime: GlobalSettings['localAccountRuntime'] =
|
||||
|
||||
@@ -103,7 +103,7 @@ describe('getInitialClaudeRateLimitTarget', () => {
|
||||
).toEqual({ runtime: 'wsl', wslDistro: 'Ubuntu' })
|
||||
})
|
||||
|
||||
it("auto follows the global WSL project runtime default", () => {
|
||||
it('auto follows the global WSL project runtime default', () => {
|
||||
expect(
|
||||
getInitialClaudeRateLimitTarget(
|
||||
{
|
||||
@@ -129,6 +129,23 @@ describe('getInitialClaudeRateLimitTarget', () => {
|
||||
).toEqual({ runtime: 'host' })
|
||||
})
|
||||
|
||||
it('does not let a stale WSL-only selection override an auto host target', () => {
|
||||
expect(
|
||||
getInitialClaudeRateLimitTarget(
|
||||
{
|
||||
...getDefaultSettings('/tmp'),
|
||||
localAccountRuntime: 'auto',
|
||||
localWindowsRuntimeDefault: { kind: 'windows-host' },
|
||||
activeClaudeManagedAccountIdsByRuntime: {
|
||||
host: null,
|
||||
wsl: { Ubuntu: 'wsl-account-1' }
|
||||
}
|
||||
},
|
||||
'win32'
|
||||
)
|
||||
).toEqual({ runtime: 'host' })
|
||||
})
|
||||
|
||||
it('keeps explicit host runtime on host', () => {
|
||||
expect(
|
||||
getInitialClaudeRateLimitTarget(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { GlobalSettings } from '../../shared/types'
|
||||
import { resolveLocalAccountRuntimeTarget } from '../../shared/local-account-runtime'
|
||||
import {
|
||||
getClaudeWslSelectionKey,
|
||||
normalizeClaudeRuntimeSelection,
|
||||
@@ -36,9 +37,14 @@ export function getInitialClaudeRateLimitTarget(
|
||||
getSingleSelectedWslDistro(settings)
|
||||
}
|
||||
}
|
||||
if (settings.localAccountRuntime === 'auto') {
|
||||
const target = resolveLocalAccountRuntimeTarget(settings, platform)
|
||||
return target.runtime === 'wsl'
|
||||
? { runtime: 'wsl', wslDistro: target.wslDistro }
|
||||
: { runtime: 'host' }
|
||||
}
|
||||
|
||||
// 'auto' (the default) and legacy-unset settings fall through here so account
|
||||
// detection follows the global WSL project runtime instead of pinning host.
|
||||
// Why: pre-setting profiles used account selection as their startup fallback.
|
||||
const projectRuntimeTarget = getProjectRuntimeRateLimitTarget(settings, platform)
|
||||
if (projectRuntimeTarget) {
|
||||
return projectRuntimeTarget
|
||||
|
||||
@@ -129,6 +129,23 @@ describe('getInitialCodexRateLimitTarget', () => {
|
||||
).toEqual({ runtime: 'host' })
|
||||
})
|
||||
|
||||
it('does not let a stale WSL-only selection override an auto host target', () => {
|
||||
expect(
|
||||
getInitialCodexRateLimitTarget(
|
||||
{
|
||||
...getDefaultSettings('/tmp'),
|
||||
localAccountRuntime: 'auto',
|
||||
localWindowsRuntimeDefault: { kind: 'windows-host' },
|
||||
activeCodexManagedAccountIdsByRuntime: {
|
||||
host: null,
|
||||
wsl: { Ubuntu: 'wsl-account-1' }
|
||||
}
|
||||
},
|
||||
'win32'
|
||||
)
|
||||
).toEqual({ runtime: 'host' })
|
||||
})
|
||||
|
||||
it('keeps explicit host runtime on host', () => {
|
||||
expect(
|
||||
getInitialCodexRateLimitTarget(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { GlobalSettings } from '../../shared/types'
|
||||
import { resolveLocalAccountRuntimeTarget } from '../../shared/local-account-runtime'
|
||||
import {
|
||||
getWslSelectionKey,
|
||||
normalizeCodexRuntimeSelection,
|
||||
@@ -36,9 +37,14 @@ export function getInitialCodexRateLimitTarget(
|
||||
getSingleSelectedWslDistro(settings)
|
||||
}
|
||||
}
|
||||
if (settings.localAccountRuntime === 'auto') {
|
||||
const target = resolveLocalAccountRuntimeTarget(settings, platform)
|
||||
return target.runtime === 'wsl'
|
||||
? { runtime: 'wsl', wslDistro: target.wslDistro }
|
||||
: { runtime: 'host' }
|
||||
}
|
||||
|
||||
// 'auto' (the default) and legacy-unset settings fall through here so account
|
||||
// detection follows the global WSL project runtime instead of pinning host.
|
||||
// Why: pre-setting profiles used account selection as their startup fallback.
|
||||
const projectRuntimeTarget = getProjectRuntimeRateLimitTarget(settings, platform)
|
||||
if (projectRuntimeTarget) {
|
||||
return projectRuntimeTarget
|
||||
|
||||
@@ -10,6 +10,7 @@ import type {
|
||||
GlobalSettings
|
||||
} from '../../../../shared/types'
|
||||
import { resolveLocalAccountRuntimeTarget } from '../../../../shared/local-account-runtime'
|
||||
import { getRendererAppPlatform } from '../../lib/renderer-app-platform'
|
||||
import { Badge } from '../ui/badge'
|
||||
import { Button } from '../ui/button'
|
||||
import { Input } from '../ui/input'
|
||||
@@ -267,11 +268,8 @@ function getSelectedAccountRuntime(
|
||||
wslDistros: string[],
|
||||
wslCapabilitiesLoading: boolean
|
||||
): LocalAccountRuntime {
|
||||
// Why: 'auto' (the default) follows the global WSL project runtime, so resolve
|
||||
// it to a concrete host/wsl position for the toggle instead of only honoring an
|
||||
// explicit 'wsl' pin. The renderer is sandboxed, so derive platform from the UA.
|
||||
const platform = navigator.userAgent.includes('Windows') ? 'win32' : 'linux'
|
||||
const resolvedRuntime = resolveLocalAccountRuntimeTarget(settings, platform)
|
||||
// Why: the two-option control displays the concrete target behind the persisted auto policy.
|
||||
const resolvedRuntime = resolveLocalAccountRuntimeTarget(settings, getRendererAppPlatform())
|
||||
if (wslSupportedPlatform && resolvedRuntime.runtime === 'wsl') {
|
||||
if (!wslAvailable && !wslCapabilitiesLoading) {
|
||||
return {
|
||||
|
||||
@@ -46,6 +46,7 @@ import type {
|
||||
RateLimitWindow
|
||||
} from '../../../../shared/rate-limit-types'
|
||||
import { resolveLocalAccountRuntimeTarget } from '../../../../shared/local-account-runtime'
|
||||
import { getRendererAppPlatform } from '../../lib/renderer-app-platform'
|
||||
import {
|
||||
ProviderIcon,
|
||||
ProviderPanel,
|
||||
@@ -196,24 +197,24 @@ function toCodexStatusRuntimeTarget(
|
||||
|
||||
export function getStatusBarPreferredWslDistro(
|
||||
settings: GlobalSettings | null | undefined,
|
||||
wslDistros: string[]
|
||||
wslDistros: string[],
|
||||
platform: NodeJS.Platform = getRendererAppPlatform()
|
||||
): string | null {
|
||||
const configuredDistro = settings?.localAccountWslDistro?.trim() || null
|
||||
if (configuredDistro) {
|
||||
return configuredDistro
|
||||
if (settings) {
|
||||
const target = resolveLocalAccountRuntimeTarget(settings, platform)
|
||||
if (target.runtime === 'wsl' && target.wslDistro) {
|
||||
return target.wslDistro
|
||||
}
|
||||
}
|
||||
return wslDistros.length === 1 ? wslDistros[0] : null
|
||||
}
|
||||
|
||||
function shouldIncludeSettingsWslRuntime(settings: GlobalSettings | null | undefined): boolean {
|
||||
// Why: 'auto' (the default) surfaces the WSL group when the global project
|
||||
// runtime is WSL, matching where account detection now reads from. The renderer
|
||||
// is sandboxed without process.platform, so derive it from the user agent.
|
||||
if (!settings) {
|
||||
return false
|
||||
}
|
||||
const platform = navigator.userAgent.includes('Windows') ? 'win32' : 'linux'
|
||||
return resolveLocalAccountRuntimeTarget(settings, platform).runtime === 'wsl'
|
||||
// Why: the fallback group must match the concrete runtime used for account polling.
|
||||
return resolveLocalAccountRuntimeTarget(settings, getRendererAppPlatform()).runtime === 'wsl'
|
||||
}
|
||||
|
||||
function getSingleConcreteCodexWslDistro(state: CodexRateLimitAccountsState): string | null {
|
||||
|
||||
@@ -116,10 +116,12 @@ describe('status bar runtime switch groups', () => {
|
||||
expect(
|
||||
getStatusBarPreferredWslDistro(
|
||||
{
|
||||
localAccountRuntime: 'wsl',
|
||||
localAccountWslDistro: null,
|
||||
terminalWindowsWslDistro: 'Debian'
|
||||
} as GlobalSettings,
|
||||
['Ubuntu']
|
||||
['Ubuntu'],
|
||||
'win32'
|
||||
)
|
||||
).toBe('Ubuntu')
|
||||
})
|
||||
@@ -128,14 +130,30 @@ describe('status bar runtime switch groups', () => {
|
||||
expect(
|
||||
getStatusBarPreferredWslDistro(
|
||||
{
|
||||
localAccountRuntime: 'wsl',
|
||||
localAccountWslDistro: 'Fedora',
|
||||
terminalWindowsWslDistro: 'Debian'
|
||||
} as GlobalSettings,
|
||||
['Ubuntu']
|
||||
['Ubuntu'],
|
||||
'win32'
|
||||
)
|
||||
).toBe('Fedora')
|
||||
})
|
||||
|
||||
it('uses the auto runtime distro instead of a stale account-runtime distro', () => {
|
||||
expect(
|
||||
getStatusBarPreferredWslDistro(
|
||||
{
|
||||
localAccountRuntime: 'auto',
|
||||
localAccountWslDistro: 'Fedora',
|
||||
localWindowsRuntimeDefault: { kind: 'wsl', distro: 'Ubuntu' }
|
||||
} as GlobalSettings,
|
||||
['Fedora', 'Ubuntu'],
|
||||
'win32'
|
||||
)
|
||||
).toBe('Ubuntu')
|
||||
})
|
||||
|
||||
it('labels the host account group with the active remote server name', () => {
|
||||
const state: CodexRateLimitAccountsState = {
|
||||
accounts: [],
|
||||
|
||||
@@ -11,13 +11,7 @@ type LocalAccountRuntimeSettings = Pick<
|
||||
'localAccountRuntime' | 'localAccountWslDistro' | 'localWindowsRuntimeDefault'
|
||||
>
|
||||
|
||||
/**
|
||||
* Resolves where provider accounts are inspected (Windows host vs a WSL distro).
|
||||
*
|
||||
* `'host'`/`'wsl'` are explicit pins; `'auto'` (the default) follows the global
|
||||
* Windows runtime default so a WSL project surfaces WSL accounts instead of the
|
||||
* Windows-host ones. Non-Windows platforms have no WSL, so always resolve host.
|
||||
*/
|
||||
/** Resolves the persisted account policy to a concrete host or WSL target. */
|
||||
export function resolveLocalAccountRuntimeTarget(
|
||||
settings: LocalAccountRuntimeSettings,
|
||||
platform: NodeJS.Platform = process.platform
|
||||
|
||||
+2
-2
@@ -2653,10 +2653,10 @@ export type GlobalSettings = {
|
||||
terminalWindowsShell: string
|
||||
/** Pins the WSL distro for terminals/agent scans instead of WSL's current global default. */
|
||||
terminalWindowsWslDistro?: string | null
|
||||
/** Account/auth location independent from the terminal shell (e.g. WSL terminals but Windows-scoped accounts). 'auto' follows the global Windows runtime default; 'host'/'wsl' pin it explicitly. */
|
||||
/** Account/auth location; auto follows the global Windows runtime while host/wsl pin it. */
|
||||
localAccountRuntime: 'auto' | 'host' | 'wsl'
|
||||
localAccountWslDistro?: string | null
|
||||
/** One-shot guard: flips the legacy hard 'host' default to 'auto' once so account detection follows the WSL project runtime; preserves explicit 'wsl'. */
|
||||
/** One-shot guard for migrating the legacy host default to auto. */
|
||||
localAccountRuntimeDefaultedToAutoForAllUsers?: boolean
|
||||
/** Independent from the terminal shell so users can inspect Windows vs WSL agent PATH state without changing it. */
|
||||
localAgentRuntime?: 'host' | 'wsl'
|
||||
|
||||
Reference in New Issue
Block a user