refactor(rate-limits): share initial account target policy (#13428)
This commit is contained in:
parent
8a33ce2536
commit
f3ea376b6b
|
|
@ -1,179 +0,0 @@
|
||||||
import { describe, expect, it } from 'vitest'
|
|
||||||
import { getDefaultSettings } from '../../shared/constants'
|
|
||||||
import type { GlobalSettings } from '../../shared/types'
|
|
||||||
import { getInitialClaudeRateLimitTarget } from './claude-rate-limit-target'
|
|
||||||
|
|
||||||
function legacySettingsWithoutAccountRuntime(settings: GlobalSettings): GlobalSettings {
|
|
||||||
const next = { ...settings } as Partial<GlobalSettings>
|
|
||||||
delete next.localAccountRuntime
|
|
||||||
return next as GlobalSettings
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('getInitialClaudeRateLimitTarget', () => {
|
|
||||||
it('uses the configured WSL account runtime before agent detection runtime', () => {
|
|
||||||
expect(
|
|
||||||
getInitialClaudeRateLimitTarget(
|
|
||||||
{
|
|
||||||
...getDefaultSettings('/tmp'),
|
|
||||||
localAccountRuntime: 'wsl',
|
|
||||||
localAccountWslDistro: 'Fedora',
|
|
||||||
localAgentRuntime: 'host',
|
|
||||||
terminalWindowsWslDistro: 'Debian'
|
|
||||||
},
|
|
||||||
'win32'
|
|
||||||
)
|
|
||||||
).toEqual({ runtime: 'wsl', wslDistro: 'Fedora' })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('uses the single selected WSL account distro when account runtime is WSL default', () => {
|
|
||||||
expect(
|
|
||||||
getInitialClaudeRateLimitTarget(
|
|
||||||
{
|
|
||||||
...getDefaultSettings('/tmp'),
|
|
||||||
localAccountRuntime: 'wsl',
|
|
||||||
activeClaudeManagedAccountIdsByRuntime: {
|
|
||||||
host: 'host-account-1',
|
|
||||||
wsl: { Ubuntu: 'wsl-account-1' }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'win32'
|
|
||||||
)
|
|
||||||
).toEqual({ runtime: 'wsl', wslDistro: 'Ubuntu' })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('ignores stale terminal WSL distro when account runtime is WSL default', () => {
|
|
||||||
expect(
|
|
||||||
getInitialClaudeRateLimitTarget(
|
|
||||||
{
|
|
||||||
...getDefaultSettings('/tmp'),
|
|
||||||
localAccountRuntime: 'wsl',
|
|
||||||
localAccountWslDistro: null,
|
|
||||||
terminalWindowsWslDistro: 'Debian',
|
|
||||||
activeClaudeManagedAccountIdsByRuntime: {
|
|
||||||
host: 'host-account-1',
|
|
||||||
wsl: {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'win32'
|
|
||||||
)
|
|
||||||
).toEqual({ runtime: 'wsl', wslDistro: null })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('uses the global WSL project runtime default when account runtime is unset', () => {
|
|
||||||
expect(
|
|
||||||
getInitialClaudeRateLimitTarget(
|
|
||||||
legacySettingsWithoutAccountRuntime({
|
|
||||||
...getDefaultSettings('/tmp'),
|
|
||||||
localWindowsRuntimeDefault: { kind: 'wsl', distro: 'Ubuntu' },
|
|
||||||
localAgentRuntime: 'host',
|
|
||||||
terminalWindowsWslDistro: 'Debian'
|
|
||||||
}),
|
|
||||||
'win32'
|
|
||||||
)
|
|
||||||
).toEqual({ runtime: 'wsl', wslDistro: 'Ubuntu' })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('ignores stale legacy WSL agent and terminal settings when the project default is host', () => {
|
|
||||||
expect(
|
|
||||||
getInitialClaudeRateLimitTarget(
|
|
||||||
legacySettingsWithoutAccountRuntime({
|
|
||||||
...getDefaultSettings('/tmp'),
|
|
||||||
localWindowsRuntimeDefault: { kind: 'windows-host' },
|
|
||||||
localAgentRuntime: 'wsl',
|
|
||||||
localAgentWslDistro: 'Ubuntu',
|
|
||||||
terminalWindowsShell: 'wsl.exe',
|
|
||||||
terminalWindowsWslDistro: 'Debian'
|
|
||||||
}),
|
|
||||||
'win32'
|
|
||||||
)
|
|
||||||
).toEqual({ runtime: 'host' })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('uses a single WSL-only active account after restart', () => {
|
|
||||||
expect(
|
|
||||||
getInitialClaudeRateLimitTarget(
|
|
||||||
legacySettingsWithoutAccountRuntime({
|
|
||||||
...getDefaultSettings('/tmp'),
|
|
||||||
activeClaudeManagedAccountIdsByRuntime: {
|
|
||||||
host: null,
|
|
||||||
wsl: { Ubuntu: 'wsl-account-1' }
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
).toEqual({ runtime: 'wsl', wslDistro: 'Ubuntu' })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('auto follows the global WSL project runtime default', () => {
|
|
||||||
expect(
|
|
||||||
getInitialClaudeRateLimitTarget(
|
|
||||||
{
|
|
||||||
...getDefaultSettings('/tmp'),
|
|
||||||
localAccountRuntime: 'auto',
|
|
||||||
localWindowsRuntimeDefault: { kind: 'wsl', distro: 'Ubuntu' }
|
|
||||||
},
|
|
||||||
'win32'
|
|
||||||
)
|
|
||||||
).toEqual({ runtime: 'wsl', wslDistro: 'Ubuntu' })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('auto resolves to host when the global project runtime is windows-host', () => {
|
|
||||||
expect(
|
|
||||||
getInitialClaudeRateLimitTarget(
|
|
||||||
{
|
|
||||||
...getDefaultSettings('/tmp'),
|
|
||||||
localAccountRuntime: 'auto',
|
|
||||||
localWindowsRuntimeDefault: { kind: 'windows-host' }
|
|
||||||
},
|
|
||||||
'win32'
|
|
||||||
)
|
|
||||||
).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(
|
|
||||||
{
|
|
||||||
...getDefaultSettings('/tmp'),
|
|
||||||
localAccountRuntime: 'host',
|
|
||||||
localAgentRuntime: 'host',
|
|
||||||
terminalWindowsShell: 'wsl.exe',
|
|
||||||
activeClaudeManagedAccountIdsByRuntime: {
|
|
||||||
host: null,
|
|
||||||
wsl: { Ubuntu: 'wsl-account-1' }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'win32'
|
|
||||||
)
|
|
||||||
).toEqual({ runtime: 'host' })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('ignores a stale explicit WSL runtime on non-Windows hosts', () => {
|
|
||||||
expect(
|
|
||||||
getInitialClaudeRateLimitTarget(
|
|
||||||
{
|
|
||||||
...getDefaultSettings('/tmp'),
|
|
||||||
localAccountRuntime: 'wsl',
|
|
||||||
localAccountWslDistro: 'Ubuntu'
|
|
||||||
},
|
|
||||||
'linux'
|
|
||||||
)
|
|
||||||
).toEqual({ runtime: 'host' })
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,71 +1,21 @@
|
||||||
import type { GlobalSettings } from '../../shared/types'
|
import type { GlobalSettings } from '../../shared/types'
|
||||||
import { resolveLocalAccountRuntimeTarget } from '../../shared/local-account-runtime'
|
|
||||||
import {
|
import {
|
||||||
getClaudeWslSelectionKey,
|
getClaudeWslSelectionKey,
|
||||||
normalizeClaudeRuntimeSelection,
|
normalizeClaudeRuntimeSelection,
|
||||||
type ClaudeAccountSelectionTarget
|
type ClaudeAccountSelectionTarget
|
||||||
} from '../claude-accounts/runtime-selection'
|
} from '../claude-accounts/runtime-selection'
|
||||||
import {
|
import { getInitialAccountRateLimitTarget } from './initial-account-rate-limit-target'
|
||||||
getProjectRuntimeRateLimitTarget,
|
|
||||||
normalizeOptionalDistro
|
|
||||||
} from './project-runtime-rate-limit-target'
|
|
||||||
|
|
||||||
function getSingleSelectedWslDistro(settings: GlobalSettings): string | null {
|
|
||||||
const selection = normalizeClaudeRuntimeSelection(settings)
|
|
||||||
const selectedWslEntries = Object.entries(selection.wsl).filter(([, accountId]) =>
|
|
||||||
Boolean(accountId)
|
|
||||||
)
|
|
||||||
if (selectedWslEntries.length !== 1) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
const [distroKey] = selectedWslEntries[0]
|
|
||||||
return distroKey === getClaudeWslSelectionKey(null) ? null : distroKey
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getInitialClaudeRateLimitTarget(
|
export function getInitialClaudeRateLimitTarget(
|
||||||
settings: GlobalSettings,
|
settings: GlobalSettings,
|
||||||
platform: NodeJS.Platform = process.platform
|
platform: NodeJS.Platform = process.platform
|
||||||
): ClaudeAccountSelectionTarget {
|
): ClaudeAccountSelectionTarget {
|
||||||
if (settings.localAccountRuntime === 'host') {
|
return getInitialAccountRateLimitTarget(
|
||||||
return { runtime: 'host' }
|
settings,
|
||||||
}
|
{
|
||||||
if (settings.localAccountRuntime === 'wsl') {
|
getWslSelectionKey: getClaudeWslSelectionKey,
|
||||||
if (platform !== 'win32') {
|
normalizeRuntimeSelection: normalizeClaudeRuntimeSelection
|
||||||
return { runtime: 'host' }
|
},
|
||||||
}
|
platform
|
||||||
return {
|
)
|
||||||
runtime: 'wsl',
|
|
||||||
wslDistro:
|
|
||||||
normalizeOptionalDistro(settings.localAccountWslDistro) ??
|
|
||||||
getSingleSelectedWslDistro(settings)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (settings.localAccountRuntime === 'auto') {
|
|
||||||
const target = resolveLocalAccountRuntimeTarget(settings, platform)
|
|
||||||
return target.runtime === 'wsl'
|
|
||||||
? { runtime: 'wsl', wslDistro: target.wslDistro }
|
|
||||||
: { runtime: 'host' }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Why: pre-setting profiles used account selection as their startup fallback.
|
|
||||||
const projectRuntimeTarget = getProjectRuntimeRateLimitTarget(settings, platform)
|
|
||||||
if (projectRuntimeTarget) {
|
|
||||||
return projectRuntimeTarget
|
|
||||||
}
|
|
||||||
|
|
||||||
const selection = normalizeClaudeRuntimeSelection(settings)
|
|
||||||
if (!selection.host) {
|
|
||||||
const selectedWslEntries = Object.entries(selection.wsl).filter(([, accountId]) =>
|
|
||||||
Boolean(accountId)
|
|
||||||
)
|
|
||||||
if (selectedWslEntries.length === 1) {
|
|
||||||
const [distroKey] = selectedWslEntries[0]
|
|
||||||
return {
|
|
||||||
runtime: 'wsl',
|
|
||||||
wslDistro: distroKey === getClaudeWslSelectionKey(null) ? null : distroKey
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { runtime: 'host' }
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,179 +0,0 @@
|
||||||
import { describe, expect, it } from 'vitest'
|
|
||||||
import { getDefaultSettings } from '../../shared/constants'
|
|
||||||
import type { GlobalSettings } from '../../shared/types'
|
|
||||||
import { getInitialCodexRateLimitTarget } from './codex-rate-limit-target'
|
|
||||||
|
|
||||||
function legacySettingsWithoutAccountRuntime(settings: GlobalSettings): GlobalSettings {
|
|
||||||
const next = { ...settings } as Partial<GlobalSettings>
|
|
||||||
delete next.localAccountRuntime
|
|
||||||
return next as GlobalSettings
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('getInitialCodexRateLimitTarget', () => {
|
|
||||||
it('uses the configured WSL account runtime before agent detection runtime', () => {
|
|
||||||
expect(
|
|
||||||
getInitialCodexRateLimitTarget(
|
|
||||||
{
|
|
||||||
...getDefaultSettings('/tmp'),
|
|
||||||
localAccountRuntime: 'wsl',
|
|
||||||
localAccountWslDistro: 'Fedora',
|
|
||||||
localAgentRuntime: 'host',
|
|
||||||
terminalWindowsWslDistro: 'Debian'
|
|
||||||
},
|
|
||||||
'win32'
|
|
||||||
)
|
|
||||||
).toEqual({ runtime: 'wsl', wslDistro: 'Fedora' })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('uses the single selected WSL account distro when account runtime is WSL default', () => {
|
|
||||||
expect(
|
|
||||||
getInitialCodexRateLimitTarget(
|
|
||||||
{
|
|
||||||
...getDefaultSettings('/tmp'),
|
|
||||||
localAccountRuntime: 'wsl',
|
|
||||||
activeCodexManagedAccountIdsByRuntime: {
|
|
||||||
host: 'host-account-1',
|
|
||||||
wsl: { Ubuntu: 'wsl-account-1' }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'win32'
|
|
||||||
)
|
|
||||||
).toEqual({ runtime: 'wsl', wslDistro: 'Ubuntu' })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('ignores stale terminal WSL distro when account runtime is WSL default', () => {
|
|
||||||
expect(
|
|
||||||
getInitialCodexRateLimitTarget(
|
|
||||||
{
|
|
||||||
...getDefaultSettings('/tmp'),
|
|
||||||
localAccountRuntime: 'wsl',
|
|
||||||
localAccountWslDistro: null,
|
|
||||||
terminalWindowsWslDistro: 'Debian',
|
|
||||||
activeCodexManagedAccountIdsByRuntime: {
|
|
||||||
host: 'host-account-1',
|
|
||||||
wsl: {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'win32'
|
|
||||||
)
|
|
||||||
).toEqual({ runtime: 'wsl', wslDistro: null })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('uses the global WSL project runtime default when account runtime is unset', () => {
|
|
||||||
expect(
|
|
||||||
getInitialCodexRateLimitTarget(
|
|
||||||
legacySettingsWithoutAccountRuntime({
|
|
||||||
...getDefaultSettings('/tmp'),
|
|
||||||
localWindowsRuntimeDefault: { kind: 'wsl', distro: 'Ubuntu' },
|
|
||||||
localAgentRuntime: 'host',
|
|
||||||
terminalWindowsWslDistro: 'Debian'
|
|
||||||
}),
|
|
||||||
'win32'
|
|
||||||
)
|
|
||||||
).toEqual({ runtime: 'wsl', wslDistro: 'Ubuntu' })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('ignores stale legacy WSL agent and terminal settings when the project default is host', () => {
|
|
||||||
expect(
|
|
||||||
getInitialCodexRateLimitTarget(
|
|
||||||
legacySettingsWithoutAccountRuntime({
|
|
||||||
...getDefaultSettings('/tmp'),
|
|
||||||
localWindowsRuntimeDefault: { kind: 'windows-host' },
|
|
||||||
localAgentRuntime: 'wsl',
|
|
||||||
localAgentWslDistro: 'Ubuntu',
|
|
||||||
terminalWindowsShell: 'wsl.exe',
|
|
||||||
terminalWindowsWslDistro: 'Debian'
|
|
||||||
}),
|
|
||||||
'win32'
|
|
||||||
)
|
|
||||||
).toEqual({ runtime: 'host' })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('uses a single WSL-only active account after restart', () => {
|
|
||||||
expect(
|
|
||||||
getInitialCodexRateLimitTarget(
|
|
||||||
legacySettingsWithoutAccountRuntime({
|
|
||||||
...getDefaultSettings('/tmp'),
|
|
||||||
activeCodexManagedAccountIdsByRuntime: {
|
|
||||||
host: null,
|
|
||||||
wsl: { Ubuntu: 'wsl-account-1' }
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
).toEqual({ runtime: 'wsl', wslDistro: 'Ubuntu' })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('auto follows the global WSL project runtime default', () => {
|
|
||||||
expect(
|
|
||||||
getInitialCodexRateLimitTarget(
|
|
||||||
{
|
|
||||||
...getDefaultSettings('/tmp'),
|
|
||||||
localAccountRuntime: 'auto',
|
|
||||||
localWindowsRuntimeDefault: { kind: 'wsl', distro: 'Ubuntu' }
|
|
||||||
},
|
|
||||||
'win32'
|
|
||||||
)
|
|
||||||
).toEqual({ runtime: 'wsl', wslDistro: 'Ubuntu' })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('auto resolves to host when the global project runtime is windows-host', () => {
|
|
||||||
expect(
|
|
||||||
getInitialCodexRateLimitTarget(
|
|
||||||
{
|
|
||||||
...getDefaultSettings('/tmp'),
|
|
||||||
localAccountRuntime: 'auto',
|
|
||||||
localWindowsRuntimeDefault: { kind: 'windows-host' }
|
|
||||||
},
|
|
||||||
'win32'
|
|
||||||
)
|
|
||||||
).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(
|
|
||||||
{
|
|
||||||
...getDefaultSettings('/tmp'),
|
|
||||||
localAccountRuntime: 'host',
|
|
||||||
localAgentRuntime: 'host',
|
|
||||||
terminalWindowsShell: 'wsl.exe',
|
|
||||||
activeCodexManagedAccountIdsByRuntime: {
|
|
||||||
host: null,
|
|
||||||
wsl: { Ubuntu: 'wsl-account-1' }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'win32'
|
|
||||||
)
|
|
||||||
).toEqual({ runtime: 'host' })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('ignores a stale explicit WSL runtime on non-Windows hosts', () => {
|
|
||||||
expect(
|
|
||||||
getInitialCodexRateLimitTarget(
|
|
||||||
{
|
|
||||||
...getDefaultSettings('/tmp'),
|
|
||||||
localAccountRuntime: 'wsl',
|
|
||||||
localAccountWslDistro: 'Ubuntu'
|
|
||||||
},
|
|
||||||
'darwin'
|
|
||||||
)
|
|
||||||
).toEqual({ runtime: 'host' })
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,73 +1,18 @@
|
||||||
import type { GlobalSettings } from '../../shared/types'
|
import type { GlobalSettings } from '../../shared/types'
|
||||||
import { resolveLocalAccountRuntimeTarget } from '../../shared/local-account-runtime'
|
|
||||||
import {
|
import {
|
||||||
getWslSelectionKey,
|
getWslSelectionKey,
|
||||||
normalizeCodexRuntimeSelection,
|
normalizeCodexRuntimeSelection,
|
||||||
type CodexAccountSelectionTarget
|
type CodexAccountSelectionTarget
|
||||||
} from '../codex-accounts/runtime-selection'
|
} from '../codex-accounts/runtime-selection'
|
||||||
import {
|
import { getInitialAccountRateLimitTarget } from './initial-account-rate-limit-target'
|
||||||
getProjectRuntimeRateLimitTarget,
|
|
||||||
normalizeOptionalDistro
|
|
||||||
} from './project-runtime-rate-limit-target'
|
|
||||||
|
|
||||||
function getSingleSelectedWslDistro(settings: GlobalSettings): string | null {
|
|
||||||
const selection = normalizeCodexRuntimeSelection(settings)
|
|
||||||
const selectedWslEntries = Object.entries(selection.wsl).filter(([, accountId]) =>
|
|
||||||
Boolean(accountId)
|
|
||||||
)
|
|
||||||
if (selectedWslEntries.length !== 1) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
const [distroKey] = selectedWslEntries[0]
|
|
||||||
return distroKey === getWslSelectionKey(null) ? null : distroKey
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getInitialCodexRateLimitTarget(
|
export function getInitialCodexRateLimitTarget(
|
||||||
settings: GlobalSettings,
|
settings: GlobalSettings,
|
||||||
platform: NodeJS.Platform = process.platform
|
platform: NodeJS.Platform = process.platform
|
||||||
): CodexAccountSelectionTarget {
|
): CodexAccountSelectionTarget {
|
||||||
if (settings.localAccountRuntime === 'host') {
|
return getInitialAccountRateLimitTarget(
|
||||||
return { runtime: 'host' }
|
settings,
|
||||||
}
|
{ getWslSelectionKey, normalizeRuntimeSelection: normalizeCodexRuntimeSelection },
|
||||||
if (settings.localAccountRuntime === 'wsl') {
|
platform
|
||||||
if (platform !== 'win32') {
|
)
|
||||||
return { runtime: 'host' }
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
runtime: 'wsl',
|
|
||||||
wslDistro:
|
|
||||||
normalizeOptionalDistro(settings.localAccountWslDistro) ??
|
|
||||||
getSingleSelectedWslDistro(settings)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (settings.localAccountRuntime === 'auto') {
|
|
||||||
const target = resolveLocalAccountRuntimeTarget(settings, platform)
|
|
||||||
return target.runtime === 'wsl'
|
|
||||||
? { runtime: 'wsl', wslDistro: target.wslDistro }
|
|
||||||
: { runtime: 'host' }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Why: pre-setting profiles used account selection as their startup fallback.
|
|
||||||
const projectRuntimeTarget = getProjectRuntimeRateLimitTarget(settings, platform)
|
|
||||||
if (projectRuntimeTarget) {
|
|
||||||
return projectRuntimeTarget
|
|
||||||
}
|
|
||||||
|
|
||||||
const selection = normalizeCodexRuntimeSelection(settings)
|
|
||||||
if (!selection.host) {
|
|
||||||
const selectedWslEntries = Object.entries(selection.wsl).filter(([, accountId]) =>
|
|
||||||
Boolean(accountId)
|
|
||||||
)
|
|
||||||
if (selectedWslEntries.length === 1) {
|
|
||||||
const [distroKey] = selectedWslEntries[0]
|
|
||||||
// Why: after restart there is no last-clicked switcher target, but a
|
|
||||||
// single WSL-only active account is the least surprising quota context.
|
|
||||||
return {
|
|
||||||
runtime: 'wsl',
|
|
||||||
wslDistro: distroKey === getWslSelectionKey(null) ? null : distroKey
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { runtime: 'host' }
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,163 @@
|
||||||
|
import { describe, expect, it } from 'vitest'
|
||||||
|
import { getDefaultSettings } from '../../shared/constants'
|
||||||
|
import type { GlobalSettings } from '../../shared/types'
|
||||||
|
import { getInitialClaudeRateLimitTarget } from './claude-rate-limit-target'
|
||||||
|
import { getInitialCodexRateLimitTarget } from './codex-rate-limit-target'
|
||||||
|
|
||||||
|
type RuntimeSelection = {
|
||||||
|
host: string | null
|
||||||
|
wsl: Record<string, string | null>
|
||||||
|
}
|
||||||
|
|
||||||
|
type Scenario = {
|
||||||
|
name: string
|
||||||
|
settings: Partial<GlobalSettings>
|
||||||
|
expected: { runtime: 'host' } | { runtime: 'wsl'; wslDistro: string | null }
|
||||||
|
legacy?: boolean
|
||||||
|
platform?: NodeJS.Platform
|
||||||
|
selection?: RuntimeSelection
|
||||||
|
}
|
||||||
|
|
||||||
|
const providers = [
|
||||||
|
{
|
||||||
|
name: 'Codex',
|
||||||
|
getTarget: getInitialCodexRateLimitTarget,
|
||||||
|
selectionSettings: (selection: RuntimeSelection) => ({
|
||||||
|
activeCodexManagedAccountIdsByRuntime: selection
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Claude',
|
||||||
|
getTarget: getInitialClaudeRateLimitTarget,
|
||||||
|
selectionSettings: (selection: RuntimeSelection) => ({
|
||||||
|
activeClaudeManagedAccountIdsByRuntime: selection
|
||||||
|
})
|
||||||
|
}
|
||||||
|
] as const
|
||||||
|
|
||||||
|
const scenarios: Scenario[] = [
|
||||||
|
{
|
||||||
|
name: 'uses the trimmed configured WSL distro before the selected account',
|
||||||
|
settings: {
|
||||||
|
localAccountRuntime: 'wsl',
|
||||||
|
localAccountWslDistro: ' Fedora ',
|
||||||
|
localAgentRuntime: 'host',
|
||||||
|
terminalWindowsWslDistro: 'Debian'
|
||||||
|
},
|
||||||
|
selection: { host: null, wsl: { Ubuntu: 'wsl-account-1' } },
|
||||||
|
expected: { runtime: 'wsl', wslDistro: 'Fedora' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'uses the single selected distro for an unpinned WSL runtime',
|
||||||
|
settings: { localAccountRuntime: 'wsl' },
|
||||||
|
selection: { host: 'host-account-1', wsl: { Ubuntu: 'wsl-account-1' } },
|
||||||
|
expected: { runtime: 'wsl', wslDistro: 'Ubuntu' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ignores a stale terminal distro for an unpinned WSL runtime',
|
||||||
|
settings: {
|
||||||
|
localAccountRuntime: 'wsl',
|
||||||
|
localAccountWslDistro: null,
|
||||||
|
terminalWindowsWslDistro: 'Debian'
|
||||||
|
},
|
||||||
|
selection: { host: 'host-account-1', wsl: {} },
|
||||||
|
expected: { runtime: 'wsl', wslDistro: null }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'keeps an explicit host runtime on host',
|
||||||
|
settings: { localAccountRuntime: 'host', terminalWindowsShell: 'wsl.exe' },
|
||||||
|
selection: { host: null, wsl: { Ubuntu: 'wsl-account-1' } },
|
||||||
|
expected: { runtime: 'host' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ignores an explicit WSL runtime on non-Windows hosts',
|
||||||
|
settings: { localAccountRuntime: 'wsl', localAccountWslDistro: 'Ubuntu' },
|
||||||
|
platform: 'linux',
|
||||||
|
expected: { runtime: 'host' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'auto follows the global WSL runtime before stale selections',
|
||||||
|
settings: {
|
||||||
|
localAccountRuntime: 'auto',
|
||||||
|
localWindowsRuntimeDefault: { kind: 'wsl', distro: 'Ubuntu' }
|
||||||
|
},
|
||||||
|
selection: { host: null, wsl: { Debian: 'wsl-account-1' } },
|
||||||
|
expected: { runtime: 'wsl', wslDistro: 'Ubuntu' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'auto keeps the global host runtime before stale selections',
|
||||||
|
settings: {
|
||||||
|
localAccountRuntime: 'auto',
|
||||||
|
localWindowsRuntimeDefault: { kind: 'windows-host' }
|
||||||
|
},
|
||||||
|
selection: { host: null, wsl: { Ubuntu: 'wsl-account-1' } },
|
||||||
|
expected: { runtime: 'host' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'legacy settings use the global WSL runtime before selections',
|
||||||
|
settings: { localWindowsRuntimeDefault: { kind: 'wsl', distro: 'Ubuntu' } },
|
||||||
|
selection: { host: null, wsl: { Debian: 'wsl-account-1' } },
|
||||||
|
legacy: true,
|
||||||
|
expected: { runtime: 'wsl', wslDistro: 'Ubuntu' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'legacy settings ignore stale agent and terminal WSL values',
|
||||||
|
settings: {
|
||||||
|
localWindowsRuntimeDefault: { kind: 'windows-host' },
|
||||||
|
localAgentRuntime: 'wsl',
|
||||||
|
localAgentWslDistro: 'Ubuntu',
|
||||||
|
terminalWindowsShell: 'wsl.exe',
|
||||||
|
terminalWindowsWslDistro: 'Debian'
|
||||||
|
},
|
||||||
|
legacy: true,
|
||||||
|
expected: { runtime: 'host' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'legacy settings preserve a single WSL selection on macOS',
|
||||||
|
settings: {},
|
||||||
|
selection: { host: null, wsl: { Ubuntu: 'wsl-account-1' } },
|
||||||
|
legacy: true,
|
||||||
|
platform: 'darwin',
|
||||||
|
expected: { runtime: 'wsl', wslDistro: 'Ubuntu' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'legacy settings map the provider default WSL key to no distro',
|
||||||
|
settings: {},
|
||||||
|
selection: { host: null, wsl: { __default__: 'wsl-account-1' } },
|
||||||
|
legacy: true,
|
||||||
|
platform: 'linux',
|
||||||
|
expected: { runtime: 'wsl', wslDistro: null }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'legacy selection fallback requires no selected host account',
|
||||||
|
settings: {},
|
||||||
|
selection: { host: 'host-account-1', wsl: { Ubuntu: 'wsl-account-1' } },
|
||||||
|
legacy: true,
|
||||||
|
expected: { runtime: 'host' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'legacy selection fallback requires exactly one selected WSL account',
|
||||||
|
settings: {},
|
||||||
|
selection: {
|
||||||
|
host: null,
|
||||||
|
wsl: { Debian: 'wsl-account-1', Fedora: null, Ubuntu: 'wsl-account-2' }
|
||||||
|
},
|
||||||
|
legacy: true,
|
||||||
|
expected: { runtime: 'host' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
describe.each(providers)('$name initial rate-limit target', ({ getTarget, selectionSettings }) => {
|
||||||
|
it.each(scenarios)('$name', (scenario) => {
|
||||||
|
const settings = {
|
||||||
|
...getDefaultSettings('/tmp'),
|
||||||
|
...scenario.settings,
|
||||||
|
...(scenario.selection ? selectionSettings(scenario.selection) : {})
|
||||||
|
}
|
||||||
|
if (scenario.legacy) {
|
||||||
|
delete (settings as Partial<GlobalSettings>).localAccountRuntime
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(getTarget(settings, scenario.platform ?? 'win32')).toEqual(scenario.expected)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
import { resolveLocalAccountRuntimeTarget } from '../../shared/local-account-runtime'
|
||||||
|
import type { GlobalSettings } from '../../shared/types'
|
||||||
|
|
||||||
|
type AccountRuntimeSelection = {
|
||||||
|
host: string | null
|
||||||
|
wsl: Record<string, string | null>
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccountRuntimeSelectionProvider = {
|
||||||
|
getWslSelectionKey: (wslDistro: string | null | undefined) => string
|
||||||
|
normalizeRuntimeSelection: (settings: GlobalSettings) => AccountRuntimeSelection
|
||||||
|
}
|
||||||
|
|
||||||
|
type WslRateLimitRuntimeTarget = { runtime: 'wsl'; wslDistro: string | null }
|
||||||
|
|
||||||
|
export type AccountRateLimitRuntimeTarget = { runtime: 'host' } | WslRateLimitRuntimeTarget
|
||||||
|
|
||||||
|
export function getInitialAccountRateLimitTarget(
|
||||||
|
settings: GlobalSettings,
|
||||||
|
provider: AccountRuntimeSelectionProvider,
|
||||||
|
platform: NodeJS.Platform = process.platform
|
||||||
|
): AccountRateLimitRuntimeTarget {
|
||||||
|
if (settings.localAccountRuntime === 'host') {
|
||||||
|
return { runtime: 'host' }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings.localAccountRuntime === 'wsl') {
|
||||||
|
if (platform !== 'win32') {
|
||||||
|
return { runtime: 'host' }
|
||||||
|
}
|
||||||
|
const configuredTarget = resolveLocalAccountRuntimeTarget(settings, platform)
|
||||||
|
return {
|
||||||
|
runtime: 'wsl',
|
||||||
|
wslDistro:
|
||||||
|
configuredTarget.wslDistro ??
|
||||||
|
getSingleSelectedWslTarget(
|
||||||
|
provider.normalizeRuntimeSelection(settings),
|
||||||
|
provider.getWslSelectionKey
|
||||||
|
)?.wslDistro ??
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pre-setting profiles omit the policy and fall back to project/account selection.
|
||||||
|
const resolvedTarget = toRateLimitTarget(resolveLocalAccountRuntimeTarget(settings, platform))
|
||||||
|
if (settings.localAccountRuntime === 'auto' || resolvedTarget.runtime === 'wsl') {
|
||||||
|
return resolvedTarget
|
||||||
|
}
|
||||||
|
|
||||||
|
const selection = provider.normalizeRuntimeSelection(settings)
|
||||||
|
return selection.host
|
||||||
|
? { runtime: 'host' }
|
||||||
|
: (getSingleSelectedWslTarget(selection, provider.getWslSelectionKey) ?? { runtime: 'host' })
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSingleSelectedWslTarget(
|
||||||
|
selection: AccountRuntimeSelection,
|
||||||
|
getWslSelectionKey: AccountRuntimeSelectionProvider['getWslSelectionKey']
|
||||||
|
): WslRateLimitRuntimeTarget | null {
|
||||||
|
const selectedWslEntries = Object.entries(selection.wsl).filter(([, accountId]) =>
|
||||||
|
Boolean(accountId)
|
||||||
|
)
|
||||||
|
if (selectedWslEntries.length !== 1) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const [distroKey] = selectedWslEntries[0]
|
||||||
|
return {
|
||||||
|
runtime: 'wsl',
|
||||||
|
wslDistro: distroKey === getWslSelectionKey(null) ? null : distroKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toRateLimitTarget(
|
||||||
|
target: ReturnType<typeof resolveLocalAccountRuntimeTarget>
|
||||||
|
): AccountRateLimitRuntimeTarget {
|
||||||
|
return target.runtime === 'wsl'
|
||||||
|
? { runtime: 'wsl', wslDistro: target.wslDistro }
|
||||||
|
: { runtime: 'host' }
|
||||||
|
}
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
import type { GlobalSettings } from '../../shared/types'
|
|
||||||
import { normalizeGlobalWindowsRuntimeDefault } from '../../shared/project-execution-runtime'
|
|
||||||
|
|
||||||
export type AccountRateLimitRuntimeTarget =
|
|
||||||
| { runtime: 'host' }
|
|
||||||
| { runtime: 'wsl'; wslDistro: string | null }
|
|
||||||
|
|
||||||
export function getProjectRuntimeRateLimitTarget(
|
|
||||||
settings: GlobalSettings,
|
|
||||||
platform: NodeJS.Platform
|
|
||||||
): AccountRateLimitRuntimeTarget | null {
|
|
||||||
if (platform !== 'win32') {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const runtimeDefault = normalizeGlobalWindowsRuntimeDefault(settings.localWindowsRuntimeDefault)
|
|
||||||
if (runtimeDefault.kind !== 'wsl') {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
// Why: account quota polling has no project id, so its best default is the
|
|
||||||
// global project runtime instead of stale terminal/agent WSL settings.
|
|
||||||
return { runtime: 'wsl', wslDistro: runtimeDefault.distro }
|
|
||||||
}
|
|
||||||
|
|
||||||
export function normalizeOptionalDistro(value: string | null | undefined): string | null {
|
|
||||||
const trimmed = value?.trim()
|
|
||||||
return trimmed ? trimmed : null
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue