source dump of claude code
at main 96 lines 4.0 kB view raw
1/** 2 * Leaf state module for the remote-managed-settings sync cache. 3 * 4 * Split from syncCache.ts to break the settings.ts → syncCache.ts → auth.ts → 5 * settings.ts cycle. auth.ts sits inside the large settings SCC; importing it 6 * from settings.ts's own dependency chain pulls hundreds of modules into the 7 * eagerly-evaluated SCC at startup. 8 * 9 * This module imports only leaves (path, envUtils, file, json, types, 10 * settings/settingsCache — also a leaf, only type-imports validation). settings.ts 11 * reads the cache from here. syncCache.ts keeps isRemoteManagedSettingsEligible 12 * (the auth-touching part) and re-exports everything from here for callers that 13 * don't care about the cycle. 14 * 15 * Eligibility is a tri-state here: undefined (not yet determined — return 16 * null), false (ineligible — return null), true (proceed). managedEnv.ts 17 * calls isRemoteManagedSettingsEligible() just before the policySettings 18 * read — after userSettings/flagSettings env vars are applied, so the check 19 * sees config-provided CLAUDE_CODE_USE_BEDROCK/ANTHROPIC_BASE_URL. That call 20 * computes once and mirrors the result here via setEligibility(). Every 21 * subsequent read hits the cached bool instead of re-running the auth chain. 22 */ 23 24import { join } from 'path' 25import { getClaudeConfigHomeDir } from '../../utils/envUtils.js' 26import { readFileSync } from '../../utils/fileRead.js' 27import { stripBOM } from '../../utils/jsonRead.js' 28import { resetSettingsCache } from '../../utils/settings/settingsCache.js' 29import type { SettingsJson } from '../../utils/settings/types.js' 30import { jsonParse } from '../../utils/slowOperations.js' 31 32const SETTINGS_FILENAME = 'remote-settings.json' 33 34let sessionCache: SettingsJson | null = null 35let eligible: boolean | undefined 36 37export function setSessionCache(value: SettingsJson | null): void { 38 sessionCache = value 39} 40 41export function resetSyncCache(): void { 42 sessionCache = null 43 eligible = undefined 44} 45 46export function setEligibility(v: boolean): boolean { 47 eligible = v 48 return v 49} 50 51export function getSettingsPath(): string { 52 return join(getClaudeConfigHomeDir(), SETTINGS_FILENAME) 53} 54 55// sync IO — settings pipeline is sync. fileRead and jsonRead are leaves; 56// file.ts and json.ts both sit in the settings SCC. 57function loadSettings(): SettingsJson | null { 58 try { 59 const content = readFileSync(getSettingsPath()) 60 const data: unknown = jsonParse(stripBOM(content)) 61 if (!data || typeof data !== 'object' || Array.isArray(data)) { 62 return null 63 } 64 return data as SettingsJson 65 } catch { 66 return null 67 } 68} 69 70export function getRemoteManagedSettingsSyncFromCache(): SettingsJson | null { 71 if (eligible !== true) return null 72 if (sessionCache) return sessionCache 73 const cachedSettings = loadSettings() 74 if (cachedSettings) { 75 sessionCache = cachedSettings 76 // Remote settings just became available for the first time. Any merged 77 // getSettings_DEPRECATED() result cached before this moment is missing 78 // the policySettings layer (the `eligible !== true` guard above returned 79 // null). Flush so the next merged read re-merges with this layer visible. 80 // 81 // Fires at most once: subsequent calls hit `if (sessionCache)` above. 82 // When called from loadSettingsFromDisk() (settings.ts:546), the merged 83 // cache is still null (setSessionSettingsCache runs at :732 after 84 // loadSettingsFromDisk returns) — no-op. The async-fetch arm (index.ts 85 // setSessionCache + notifyChange) already handles its own reset. 86 // 87 // gh-23085: isBridgeEnabled() at main.tsx Commander-definition time 88 // (before preAction → init() → isRemoteManagedSettingsEligible()) reached 89 // getSettings_DEPRECATED() at auth.ts:115. The try/catch in bridgeEnabled 90 // swallowed the later getGlobalConfig() throw, but the merged settings 91 // cache was already poisoned. See managedSettingsHeadless.int.test.ts. 92 resetSettingsCache() 93 return cachedSettings 94 } 95 return null 96}