From 4f6e61739c13323484bcb036980e2553e6bb31bd Mon Sep 17 00:00:00 2001 From: Tam Nhu Tran Date: Sun, 3 May 2026 01:42:53 -0400 Subject: [PATCH] refactor(config): adopt config-loader-facade across the codebase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue #1161. Sweeps 127 files to import from src/config/config-loader-facade.ts instead of unified-config-loader or utils/config-manager directly. WRITE callers (32 files): replaced raw saveUnifiedConfig / mutateUnifiedConfig / updateUnifiedConfig calls with the facade's cache-coherent wrappers saveConfig / mutateConfig / updateConfig. This fixes a latent stale-cache window where direct writes through the underlying loader bypassed the facade's memoization. READ callers (95 files): mechanical import-path migration only — function names unchanged because the facade re-exports them. No behavior change. Also updated: - tests/unit/utils/browser/browser-setup.test.ts (DI interface rename) - src/management/checks/image-analysis-check.ts (dynamic import rename) - src/web-server/health-service.ts (dynamic require rename) - src/ccs.ts (path prefix fix from sweep script) After sweep: zero raw write callers remain outside src/config/. Direct imports of config-manager remain only for symbols not in the facade (getConfigPath, getCcsDirSource, etc). Behavior unchanged; full suite passes 1824/1824. Out of scope: switching loadOrCreateUnifiedConfig() callers to getCachedConfig() — needs per-callsite cache-safety analysis. Tracked as follow-up. Refs #1161 --- src/api/services/cliproxy-profile-bridge.ts | 10 +++++-- src/api/services/openrouter-catalog.ts | 2 +- src/api/services/profile-lifecycle-service.ts | 12 ++++++--- src/api/services/profile-reader.ts | 8 ++++-- src/api/services/profile-writer.ts | 16 ++++++++---- src/auth/commands/create-command.ts | 3 ++- src/auth/commands/default-command.ts | 3 ++- src/auth/commands/remove-command.ts | 3 ++- src/auth/profile-continuity-inheritance.ts | 11 ++++---- src/auth/profile-detector.ts | 9 +++++-- src/auth/profile-registry.ts | 26 ++++++++++--------- src/auth/resume-lane-diagnostics.ts | 3 ++- src/ccs.ts | 19 ++++++-------- src/channels/official-channels-store.ts | 3 ++- src/cliproxy/accounts/account-safety.ts | 4 +-- .../auth/antigravity-responsibility.ts | 2 +- src/cliproxy/auth/auth-token-manager.ts | 11 ++++---- src/cliproxy/auth/token-refresh-config.ts | 2 +- src/cliproxy/binary-manager.ts | 3 ++- src/cliproxy/config/env-builder.ts | 3 ++- src/cliproxy/config/generator.ts | 3 ++- src/cliproxy/config/model-config.ts | 3 ++- src/cliproxy/config/path-resolver.ts | 3 ++- src/cliproxy/config/thinking-config.ts | 3 ++- src/cliproxy/executor/index.ts | 14 +++++----- src/cliproxy/proxy/proxy-target-resolver.ts | 2 +- src/cliproxy/proxy/tool-sanitization-proxy.ts | 3 ++- src/cliproxy/quota/quota-manager.ts | 3 ++- src/cliproxy/routing/routing-strategy.ts | 6 ++--- src/cliproxy/services/binary-service.ts | 2 +- src/cliproxy/services/catalog-cache.ts | 3 ++- .../services/variant-config-adapter.ts | 20 +++++++------- src/cliproxy/services/variant-service.ts | 5 ++-- src/cliproxy/services/variant-settings.ts | 3 ++- src/cliproxy/sync/auto-sync-watcher.ts | 4 +-- src/cliproxy/sync/profile-mapper.ts | 3 ++- src/commands/browser-command.ts | 7 ++--- .../cliproxy/resolve-lifecycle-port.ts | 3 ++- src/commands/cliproxy/variant-subcommand.ts | 3 ++- src/commands/config-auth/disable-command.ts | 5 ++-- src/commands/config-auth/setup-command.ts | 5 ++-- src/commands/config-auth/show-command.ts | 2 +- src/commands/config-channels-command.ts | 13 +++++----- src/commands/config-command.ts | 3 ++- src/commands/config-image-analysis-command.ts | 13 +++++----- src/commands/config-thinking-command.ts | 13 +++++----- src/commands/copilot-command.ts | 7 ++--- src/commands/cursor-command.ts | 7 ++--- src/commands/env-command.ts | 3 ++- src/commands/migrate-command.ts | 3 ++- src/commands/proxy-command.ts | 3 ++- src/commands/setup-command.ts | 16 +++++++----- src/commands/version-command.ts | 3 ++- src/copilot/copilot-daemon.ts | 3 ++- src/copilot/copilot-executor.ts | 3 ++- src/copilot/copilot-package-manager.ts | 2 +- src/cursor/cursor-auth.ts | 2 +- src/cursor/cursor-daemon-pid.ts | 2 +- src/cursor/cursor-profile-executor.ts | 3 ++- src/delegation/delegation-handler.ts | 2 +- src/delegation/headless-executor.ts | 5 ++-- src/delegation/session-manager.ts | 2 +- src/docker/docker-assets.ts | 3 ++- src/glmt/glmt-transformer.ts | 3 ++- src/management/checks/config-check.ts | 3 ++- src/management/checks/env-check.ts | 3 ++- src/management/checks/image-analysis-check.ts | 8 +++--- src/management/checks/profile-check.ts | 2 +- src/management/checks/symlink-check.ts | 2 +- src/management/checks/system-check.ts | 2 +- src/management/instance-manager.ts | 3 ++- src/management/recovery-manager.ts | 9 ++++--- src/management/repair/auto-repair.ts | 3 ++- src/management/shared-manager.ts | 3 ++- src/proxy/proxy-daemon-entry.ts | 2 +- src/proxy/proxy-daemon-paths.ts | 2 +- src/proxy/proxy-port-resolver.ts | 2 +- src/proxy/request-router.ts | 2 +- src/services/logging/log-config.ts | 5 ++-- src/services/logging/log-paths.ts | 2 +- src/utils/browser/browser-setup.ts | 8 +++--- src/utils/browser/browser-status.ts | 3 ++- src/utils/config-manager.ts | 2 +- .../hooks/get-image-analysis-hook-env.ts | 2 +- .../image-analyzer-hook-configuration.ts | 3 ++- .../hooks/image-analyzer-hook-installer.ts | 3 ++- .../image-analyzer-profile-hook-injector.ts | 3 ++- src/utils/image-analysis/mcp-installer.ts | 3 ++- src/utils/shell-executor.ts | 3 ++- src/utils/websearch/hook-config.ts | 3 ++- src/utils/websearch/hook-env.ts | 2 +- src/utils/websearch/hook-installer.ts | 3 ++- src/utils/websearch/mcp-installer.ts | 3 ++- src/utils/websearch/profile-hook-injector.ts | 3 ++- src/utils/websearch/provider-secrets.ts | 2 +- src/utils/websearch/status.ts | 3 ++- src/web-server/file-watcher.ts | 2 +- src/web-server/health-service.ts | 11 ++++---- src/web-server/health/config-checks.ts | 5 ++-- src/web-server/health/profile-checks.ts | 3 ++- src/web-server/middleware/auth-middleware.ts | 8 ++++-- src/web-server/models-dev/registry-cache.ts | 3 ++- src/web-server/overview-routes.ts | 3 ++- src/web-server/routes/account-routes.ts | 3 ++- src/web-server/routes/auth-routes.ts | 3 ++- src/web-server/routes/browser-routes.ts | 5 ++-- src/web-server/routes/channels-routes.ts | 5 ++-- src/web-server/routes/cliproxy-auth-routes.ts | 3 ++- src/web-server/routes/cliproxy-local-proxy.ts | 3 ++- src/web-server/routes/cliproxy-sync-routes.ts | 5 ++-- src/web-server/routes/config-routes.ts | 17 ++++++------ src/web-server/routes/copilot-routes.ts | 5 ++-- .../routes/copilot-settings-routes.ts | 9 ++++--- src/web-server/routes/cursor-routes.ts | 3 ++- .../routes/cursor-settings-routes.ts | 9 ++++--- .../routes/image-analysis-routes.ts | 11 +++++--- src/web-server/routes/misc-routes.ts | 20 +++++++------- src/web-server/routes/proxy-routes.ts | 7 ++--- src/web-server/routes/route-helpers.ts | 3 ++- src/web-server/routes/settings-routes.ts | 18 ++++++++----- src/web-server/routes/websearch-routes.ts | 5 ++-- .../claude-extension-binding-service.ts | 2 +- .../services/logs-dashboard-service.ts | 4 +-- src/web-server/shared-routes.ts | 3 ++- src/web-server/usage/aggregator.ts | 3 ++- src/web-server/usage/cliproxy-usage-syncer.ts | 3 ++- src/web-server/usage/disk-cache.ts | 2 +- .../unit/utils/browser/browser-setup.test.ts | 4 +-- 128 files changed, 397 insertions(+), 267 deletions(-) diff --git a/src/api/services/cliproxy-profile-bridge.ts b/src/api/services/cliproxy-profile-bridge.ts index dc936c23..25ab7d21 100644 --- a/src/api/services/cliproxy-profile-bridge.ts +++ b/src/api/services/cliproxy-profile-bridge.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; import * as path from 'path'; -import { getCcsDir, loadConfigSafe } from '../../utils/config-manager'; + import { buildProxyUrl, getProxyTarget } from '../../cliproxy/proxy/proxy-target-resolver'; import { getEffectiveApiKey } from '../../cliproxy/auth/auth-token-manager'; import { getModelMappingFromConfig } from '../../cliproxy/config/base-config-loader'; @@ -11,7 +11,7 @@ import { mapExternalProviderName, } from '../../cliproxy/provider-capabilities'; import { extractProviderFromPathname } from '../../cliproxy/ai-providers/model-id-normalizer'; -import { isUnifiedMode, loadOrCreateUnifiedConfig } from '../../config/unified-config-loader'; + import type { TargetType } from '../../targets/target-adapter'; import type { Settings } from '../../types/config'; import type { CLIProxyProvider } from '../../cliproxy/types'; @@ -21,6 +21,12 @@ import type { ModelMapping, ResolvedCliproxyBridgeProfile, } from './profile-types'; +import { + getCcsDir, + isUnifiedMode, + loadConfigSafe, + loadOrCreateUnifiedConfig, +} from '../../config/config-loader-facade'; const DEFAULT_PROFILE_SUFFIX = '-api'; diff --git a/src/api/services/openrouter-catalog.ts b/src/api/services/openrouter-catalog.ts index bfcb784e..f13147bd 100644 --- a/src/api/services/openrouter-catalog.ts +++ b/src/api/services/openrouter-catalog.ts @@ -5,7 +5,7 @@ import * as fs from 'fs'; import * as path from 'path'; -import { getCcsDir } from '../../utils/config-manager'; +import { getCcsDir } from '../../config/config-loader-facade'; const OPENROUTER_API_URL = 'https://openrouter.ai/api/v1/models'; function getCacheFile() { diff --git a/src/api/services/profile-lifecycle-service.ts b/src/api/services/profile-lifecycle-service.ts index 28d43d11..39c6cf82 100644 --- a/src/api/services/profile-lifecycle-service.ts +++ b/src/api/services/profile-lifecycle-service.ts @@ -9,12 +9,12 @@ import * as path from 'path'; import type { Config, Settings } from '../../types'; import type { TargetType } from '../../targets/target-adapter'; import { getPersistedTargetChoices, isPersistedTargetType } from '../../targets/target-metadata'; -import { getCcsDir, getConfigPath, loadConfigSafe } from '../../utils/config-manager'; +import { getConfigPath } from '../../utils/config-manager'; import { ensureWebSearchMcpOrThrow } from '../../utils/websearch-manager'; import { ensureImageAnalysisMcpOrThrow } from '../../utils/image-analysis'; import { isSensitiveKey } from '../../utils/sensitive-keys'; import { isReservedName } from '../../config/reserved-names'; -import { isUnifiedMode, mutateUnifiedConfig } from '../../config/unified-config-loader'; + import { validateApiName } from './validation-service'; import { listApiProfiles } from './profile-reader'; import { validateApiProfileSettingsPayload } from './profile-lifecycle-validation'; @@ -26,6 +26,12 @@ import type { ImportApiProfileResult, RegisterApiProfileOrphansResult, } from './profile-types'; +import { + getCcsDir, + isUnifiedMode, + loadConfigSafe, + mutateConfig, +} from '../../config/config-loader-facade'; const SETTINGS_FILE_SUFFIX = '.settings.json'; const REDACTED_TOKEN_SENTINEL = '__CCS_REDACTED__'; @@ -62,7 +68,7 @@ function writeJsonObjectAtomically(filePath: string, value: unknown): void { function registerApiProfileInConfig(name: string, target: TargetType, force = false): void { if (isUnifiedMode()) { - mutateUnifiedConfig((config) => { + mutateConfig((config) => { if (config.profiles[name] && !force) { throw new Error(`API profile already exists: ${name}`); } diff --git a/src/api/services/profile-reader.ts b/src/api/services/profile-reader.ts index a18f04c2..cb3b5a75 100644 --- a/src/api/services/profile-reader.ts +++ b/src/api/services/profile-reader.ts @@ -6,14 +6,18 @@ */ import * as fs from 'fs'; -import { loadConfigSafe } from '../../utils/config-manager'; -import { loadOrCreateUnifiedConfig, isUnifiedMode } from '../../config/unified-config-loader'; + import { expandPath } from '../../utils/helpers'; import type { TargetType } from '../../targets/target-adapter'; import { isPersistedTargetType } from '../../targets/target-metadata'; import type { Settings } from '../../types/config'; import type { ApiProfileInfo, CliproxyVariantInfo, ApiListResult } from './profile-types'; import { resolveCliproxyBridgeMetadata } from './cliproxy-profile-bridge'; +import { + isUnifiedMode, + loadConfigSafe, + loadOrCreateUnifiedConfig, +} from '../../config/config-loader-facade'; function sanitizeTarget(target: unknown): TargetType { if (isPersistedTargetType(target)) { diff --git a/src/api/services/profile-writer.ts b/src/api/services/profile-writer.ts index 0e267160..2ef17caa 100644 --- a/src/api/services/profile-writer.ts +++ b/src/api/services/profile-writer.ts @@ -4,10 +4,10 @@ */ import * as fs from 'fs'; import * as path from 'path'; -import { getCcsDir, getConfigPath, loadConfigSafe } from '../../utils/config-manager'; +import { getConfigPath } from '../../utils/config-manager'; import { expandPath } from '../../utils/helpers'; import { validateApiName } from './validation-service'; -import { mutateUnifiedConfig, isUnifiedMode } from '../../config/unified-config-loader'; + import { ensureWebSearchMcpOrThrow } from '../../utils/websearch-manager'; import { ensureImageAnalysisMcpOrThrow } from '../../utils/image-analysis'; import type { TargetType } from '../../targets/target-adapter'; @@ -31,6 +31,12 @@ import { resolveCliproxyBridgeMetadata, resolveCliproxyBridgeProfile, } from './cliproxy-profile-bridge'; +import { + getCcsDir, + isUnifiedMode, + loadConfigSafe, + mutateConfig, +} from '../../config/config-loader-facade'; /** Check if URL is an OpenRouter endpoint */ function isOpenRouterUrl(baseUrl: string): boolean { @@ -232,7 +238,7 @@ function createApiProfileUnified( throw error; } - mutateUnifiedConfig((config) => { + mutateConfig((config) => { config.profiles[name] = { type: 'api', settings: `~/.ccs/${settingsFile}`, @@ -343,7 +349,7 @@ export function updateApiProfileTarget( ): UpdateApiProfileTargetResult { try { if (isUnifiedMode()) { - mutateUnifiedConfig((config) => { + mutateConfig((config) => { if (!config.profiles[name]) { throw new Error(`API profile not found: ${name}`); } @@ -392,7 +398,7 @@ export function updateApiProfileTarget( /** Remove API profile from unified config */ function removeApiProfileUnified(name: string): void { - mutateUnifiedConfig((config) => { + mutateConfig((config) => { const profile = config.profiles[name]; if (!profile) { diff --git a/src/auth/commands/create-command.ts b/src/auth/commands/create-command.ts index c70b2c6c..f071e001 100644 --- a/src/auth/commands/create-command.ts +++ b/src/auth/commands/create-command.ts @@ -12,7 +12,7 @@ import { getWindowsEscapedCommandShell, stripClaudeCodeEnv, } from '../../utils/shell-executor'; -import { isUnifiedMode } from '../../config/unified-config-loader'; + import { ProfileMetadata } from '../../types'; import { resolveCreateAccountContext, @@ -25,6 +25,7 @@ import { exitWithError } from '../../errors'; import { ExitCode } from '../../errors/exit-codes'; import { CommandContext, parseArgs } from './types'; import { stripAmbientProviderCredentials } from './create-command-env'; +import { isUnifiedMode } from '../../config/config-loader-facade'; function sanitizeProfileNameForInstance(name: string): string { return name.replace(/[^a-zA-Z0-9_-]/g, '-').toLowerCase(); diff --git a/src/auth/commands/default-command.ts b/src/auth/commands/default-command.ts index 7964a60f..2800f931 100644 --- a/src/auth/commands/default-command.ts +++ b/src/auth/commands/default-command.ts @@ -5,10 +5,11 @@ */ import { initUI, color, dim, ok, fail } from '../../utils/ui'; -import { isUnifiedMode } from '../../config/unified-config-loader'; + import { exitWithError } from '../../errors'; import { ExitCode } from '../../errors/exit-codes'; import { CommandContext, parseArgs } from './types'; +import { isUnifiedMode } from '../../config/config-loader-facade'; /** * Handle the default command (set default profile) diff --git a/src/auth/commands/remove-command.ts b/src/auth/commands/remove-command.ts index b7df32fa..9302d1b0 100644 --- a/src/auth/commands/remove-command.ts +++ b/src/auth/commands/remove-command.ts @@ -8,10 +8,11 @@ import * as fs from 'fs'; import * as path from 'path'; import { initUI, color, ok, fail, info } from '../../utils/ui'; import { InteractivePrompt } from '../../utils/prompt'; -import { isUnifiedMode } from '../../config/unified-config-loader'; + import { exitWithError } from '../../errors'; import { ExitCode } from '../../errors/exit-codes'; import { CommandContext, parseArgs } from './types'; +import { isUnifiedMode } from '../../config/config-loader-facade'; /** * Handle the remove command diff --git a/src/auth/profile-continuity-inheritance.ts b/src/auth/profile-continuity-inheritance.ts index b2a775b3..1af11922 100644 --- a/src/auth/profile-continuity-inheritance.ts +++ b/src/auth/profile-continuity-inheritance.ts @@ -1,15 +1,16 @@ import * as fs from 'fs'; -import { - getConfigJsonPath, - getContinuityInheritanceMap, - isUnifiedMode, -} from '../config/unified-config-loader'; + import { warn } from '../utils/ui'; import InstanceManager from '../management/instance-manager'; import ProfileRegistry from './profile-registry'; import { isAccountContextMetadata, resolveAccountContextPolicy } from './account-context'; import type { ProfileType } from '../types/profile'; import { getProfileLookupCandidates, resolveAliasToCanonical } from '../utils/profile-compat'; +import { + getConfigJsonPath, + getContinuityInheritanceMap, + isUnifiedMode, +} from '../config/config-loader-facade'; export interface ProfileContinuityInheritanceInput { profileName: string; diff --git a/src/auth/profile-detector.ts b/src/auth/profile-detector.ts index b0c8d1ca..f577c367 100644 --- a/src/auth/profile-detector.ts +++ b/src/auth/profile-detector.ts @@ -21,8 +21,7 @@ import { CompositeVariantConfig, CompositeTierConfig, } from '../config/unified-config-types'; -import { loadUnifiedConfig, isUnifiedMode, getCursorConfig } from '../config/unified-config-loader'; -import { getCcsDir } from '../utils/config-manager'; + import { getProfileLookupCandidates, isLegacyProfileAlias } from '../utils/profile-compat'; import type { CLIProxyProvider } from '../cliproxy/types'; import { CLIPROXY_PROVIDER_IDS, isCLIProxyProvider } from '../cliproxy/provider-capabilities'; @@ -30,6 +29,12 @@ import { LEGACY_CURSOR_PROFILE_NAME } from '../cursor/constants'; import { normalizeCopilotModelId } from '../copilot/copilot-model-normalizer'; import type { TargetType } from '../targets/target-adapter'; import type { ProfileType } from '../types/profile'; +import { + getCcsDir, + getCursorConfig, + isUnifiedMode, + loadUnifiedConfig, +} from '../config/config-loader-facade'; export type { ProfileType } from '../types/profile'; /** CLIProxy profile names (OAuth-based, zero config) */ diff --git a/src/auth/profile-registry.ts b/src/auth/profile-registry.ts index 35d17193..31c5482d 100644 --- a/src/auth/profile-registry.ts +++ b/src/auth/profile-registry.ts @@ -1,15 +1,17 @@ import * as fs from 'fs'; import * as path from 'path'; import { ProfileMetadata } from '../types'; -import { - loadOrCreateUnifiedConfig, - mutateUnifiedConfig, - isUnifiedMode, -} from '../config/unified-config-loader'; + import type { AccountConfig } from '../config/unified-config-types'; -import { getCcsDir } from '../utils/config-manager'; + import { isValidContextGroupName, normalizeContextGroupName } from './account-context'; import { createLogger } from '../services/logging'; +import { + getCcsDir, + isUnifiedMode, + loadOrCreateUnifiedConfig, + mutateConfig, +} from '../config/config-loader-facade'; const logger = createLogger('auth:profile-registry'); @@ -323,7 +325,7 @@ export class ProfileRegistry { * Create account in unified config (config.yaml) */ createAccountUnified(name: string, metadata: CreateMetadata = {}): void { - mutateUnifiedConfig((config) => { + mutateConfig((config) => { if (config.accounts[name]) { throw new Error(`Account already exists: ${name}`); } @@ -342,7 +344,7 @@ export class ProfileRegistry { * Update account metadata in unified config */ updateAccountUnified(name: string, updates: Partial): void { - mutateUnifiedConfig((config) => { + mutateConfig((config) => { if (!config.accounts[name]) { throw new Error(`Account not found: ${name}`); } @@ -357,7 +359,7 @@ export class ProfileRegistry { * Remove account from unified config */ removeAccountUnified(name: string): void { - mutateUnifiedConfig((config) => { + mutateConfig((config) => { if (!config.accounts[name]) { throw new Error(`Account not found: ${name}`); } @@ -372,7 +374,7 @@ export class ProfileRegistry { * Set default profile in unified config */ setDefaultUnified(name: string): void { - mutateUnifiedConfig((config) => { + mutateConfig((config) => { const exists = config.accounts[name] || config.profiles[name] || config.cliproxy?.variants?.[name]; if (!exists) { @@ -386,7 +388,7 @@ export class ProfileRegistry { * Clear default profile in unified config (restore original CCS behavior) */ clearDefaultUnified(): void { - mutateUnifiedConfig((config) => { + mutateConfig((config) => { config.default = undefined; }); } @@ -426,7 +428,7 @@ export class ProfileRegistry { * Update account last_used in unified config */ touchAccountUnified(name: string): void { - mutateUnifiedConfig((config) => { + mutateConfig((config) => { if (!config.accounts[name]) { throw new Error(`Account not found: ${name}`); } diff --git a/src/auth/resume-lane-diagnostics.ts b/src/auth/resume-lane-diagnostics.ts index 4919f157..ba3e3b95 100644 --- a/src/auth/resume-lane-diagnostics.ts +++ b/src/auth/resume-lane-diagnostics.ts @@ -1,11 +1,12 @@ import * as fs from 'fs'; import * as path from 'path'; import { getDefaultClaudeConfigDir } from '../utils/claude-config-path'; -import { getCcsDir } from '../utils/config-manager'; + import InstanceManager from '../management/instance-manager'; import ProfileDetector from './profile-detector'; import { resolveConfiguredContinuitySourceAccount } from './profile-continuity-inheritance'; import type { ProfileType } from '../types/profile'; +import { getCcsDir } from '../config/config-loader-facade'; export type ResumeLaneKind = | 'native' diff --git a/src/ccs.ts b/src/ccs.ts index 0fde15ea..d88d2f35 100644 --- a/src/ccs.ts +++ b/src/ccs.ts @@ -2,12 +2,7 @@ import './utils/fetch-proxy-setup'; import * as fs from 'fs'; import { detectClaudeCli } from './utils/claude-detector'; -import { - getSettingsPath, - loadSettings, - setGlobalConfigDir, - detectCloudSyncPath, -} from './utils/config-manager'; +import { getSettingsPath, setGlobalConfigDir, detectCloudSyncPath } from './utils/config-manager'; import { expandPath } from './utils/helpers'; import { validateGlmKey, @@ -46,11 +41,7 @@ import { resolveOptionalBrowserAttachRuntime, syncBrowserMcpToConfigDir, } from './utils/browser'; -import { - getBrowserConfig, - getGlobalEnvConfig, - getOfficialChannelsConfig, -} from './config/unified-config-loader'; + import { ensureProfileHooks as ensureImageAnalyzerHooks, removeImageAnalysisProfileHook, @@ -122,6 +113,12 @@ import { checkCachedUpdate, isCacheStale, } from './utils/update-checker'; +import { + getBrowserConfig, + getGlobalEnvConfig, + getOfficialChannelsConfig, + loadSettings, +} from './config/config-loader-facade'; // Note: npm is now the only supported installation method // ========== Profile Detection ========== diff --git a/src/channels/official-channels-store.ts b/src/channels/official-channels-store.ts index 7e99e573..5eb73dac 100644 --- a/src/channels/official-channels-store.ts +++ b/src/channels/official-channels-store.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; import * as path from 'path'; -import { getCcsDir } from '../utils/config-manager'; + import { getDefaultClaudeConfigDir } from '../utils/claude-config-path'; import type { OfficialChannelId } from '../config/unified-config-types'; import { @@ -10,6 +10,7 @@ import { getOfficialChannelTokenIds, isOfficialChannelTokenRequired, } from './official-channels-runtime'; +import { getCcsDir } from '../config/config-loader-facade'; export type OfficialChannelTokenSource = 'saved_env' | 'process_env' | 'missing'; diff --git a/src/cliproxy/accounts/account-safety.ts b/src/cliproxy/accounts/account-safety.ts index f4b826f3..b3f48784 100644 --- a/src/cliproxy/accounts/account-safety.ts +++ b/src/cliproxy/accounts/account-safety.ts @@ -14,7 +14,7 @@ import * as path from 'path'; import { warn, info } from '../../utils/ui'; import { CLIProxyProvider } from '../types'; import { loadAccountsRegistry, pauseAccount, resumeAccount } from './registry'; -import { getCcsDir } from '../../utils/config-manager'; +import { getCcsDir } from '../../config/config-loader-facade'; const ISSUE_509_URL = 'https://github.com/kaitranntt/ccs/issues/509'; @@ -690,7 +690,7 @@ export async function handleQuotaExhaustion( // Dynamic imports to avoid circular dependencies const { applyCooldown, findHealthyAccount } = await import('../quota/quota-manager'); const { setDefaultAccount, touchAccount } = await import('./account-manager'); - const { loadOrCreateUnifiedConfig } = await import('../../config/unified-config-loader'); + const { loadOrCreateUnifiedConfig } = await import('../../config/config-loader-facade'); const config = loadOrCreateUnifiedConfig(); const threshold = config.quota_management?.auto?.exhaustion_threshold ?? 5; diff --git a/src/cliproxy/auth/antigravity-responsibility.ts b/src/cliproxy/auth/antigravity-responsibility.ts index 62f8e9a2..99e3411a 100644 --- a/src/cliproxy/auth/antigravity-responsibility.ts +++ b/src/cliproxy/auth/antigravity-responsibility.ts @@ -10,7 +10,7 @@ import { createInterface, Interface } from 'readline'; import { fail, info, ok, warn } from '../../utils/ui'; -import { getCliproxySafetyConfig } from '../../config/unified-config-loader'; +import { getCliproxySafetyConfig } from '../../config/config-loader-facade'; export const ANTIGRAVITY_RISK_ISSUE_URL = 'https://github.com/kaitranntt/ccs/issues/509'; export const ANTIGRAVITY_ACK_VERSION = '2026-02-24-antigravity-oauth-v2'; diff --git a/src/cliproxy/auth/auth-token-manager.ts b/src/cliproxy/auth/auth-token-manager.ts index 7ace9252..06cac201 100644 --- a/src/cliproxy/auth/auth-token-manager.ts +++ b/src/cliproxy/auth/auth-token-manager.ts @@ -8,8 +8,9 @@ */ import { randomBytes } from 'crypto'; -import { loadOrCreateUnifiedConfig, mutateUnifiedConfig } from '../../config/unified-config-loader'; + import { CCS_INTERNAL_API_KEY, CCS_CONTROL_PANEL_SECRET } from '../config/generator'; +import { loadOrCreateUnifiedConfig, mutateConfig } from '../../config/config-loader-facade'; /** * Generate a cryptographically secure token. @@ -87,7 +88,7 @@ export function getEffectiveManagementSecret(): string { * @param apiKey - New API key (or undefined to reset to default) */ export function setGlobalApiKey(apiKey: string | undefined): void { - mutateUnifiedConfig((config) => { + mutateConfig((config) => { if (!config.cliproxy.auth) { config.cliproxy.auth = {}; } @@ -107,7 +108,7 @@ export function setGlobalApiKey(apiKey: string | undefined): void { * @param secret - New management secret (or undefined to reset to default) */ export function setGlobalManagementSecret(secret: string | undefined): void { - mutateUnifiedConfig((config) => { + mutateConfig((config) => { if (!config.cliproxy.auth) { config.cliproxy.auth = {}; } @@ -128,7 +129,7 @@ export function setGlobalManagementSecret(secret: string | undefined): void { * @param apiKey - New API key (or undefined to remove override) */ export function setVariantApiKey(variantName: string, apiKey: string | undefined): void { - mutateUnifiedConfig((config) => { + mutateConfig((config) => { const variant = config.cliproxy.variants[variantName]; if (!variant) { @@ -155,7 +156,7 @@ export function setVariantApiKey(variantName: string, apiKey: string | undefined * Removes cliproxy.auth and all variant auth overrides. */ export function resetAuthToDefaults(): void { - mutateUnifiedConfig((config) => { + mutateConfig((config) => { delete config.cliproxy.auth; for (const variantName of Object.keys(config.cliproxy.variants)) { diff --git a/src/cliproxy/auth/token-refresh-config.ts b/src/cliproxy/auth/token-refresh-config.ts index 39b25f42..3af38149 100644 --- a/src/cliproxy/auth/token-refresh-config.ts +++ b/src/cliproxy/auth/token-refresh-config.ts @@ -5,8 +5,8 @@ * Returns null if disabled or not configured. */ -import { loadOrCreateUnifiedConfig } from '../../config/unified-config-loader'; import type { TokenRefreshSettings } from '../../config/unified-config-types'; +import { loadOrCreateUnifiedConfig } from '../../config/config-loader-facade'; /** * Get token refresh configuration from unified config diff --git a/src/cliproxy/binary-manager.ts b/src/cliproxy/binary-manager.ts index baa11726..74c24b71 100644 --- a/src/cliproxy/binary-manager.ts +++ b/src/cliproxy/binary-manager.ts @@ -18,7 +18,7 @@ import { } from './binary/platform-detector'; import { stopProxy } from './services/proxy-lifecycle-service'; import { waitForPortFree } from '../utils/port-utils'; -import { loadOrCreateUnifiedConfig } from '../config/unified-config-loader'; + import { UpdateCheckResult, checkForUpdates, @@ -39,6 +39,7 @@ import { import type { CLIProxyBackend } from './types'; import { getVersionListCachePath } from './binary/version-cache'; +import { loadOrCreateUnifiedConfig } from '../config/config-loader-facade'; export const CLIPROXY_DELETED_PLUS_REPO = 'router-for-me/CLIProxyAPIPlus'; export const CLIPROXY_PLUS_FALLBACK_TRACKING_URL = 'https://github.com/kaitranntt/ccs/issues/1062'; diff --git a/src/cliproxy/config/env-builder.ts b/src/cliproxy/config/env-builder.ts index ec0d5c00..4b66f87f 100644 --- a/src/cliproxy/config/env-builder.ts +++ b/src/cliproxy/config/env-builder.ts @@ -7,7 +7,7 @@ import * as fs from 'fs'; import * as path from 'path'; import type { CLIProxyProvider, ProviderModelMapping } from '../types'; import { getModelMappingFromConfig, getEnvVarsFromConfig } from '../config/base-config-loader'; -import { getGlobalEnvConfig } from '../../config/unified-config-loader'; + import { getEffectiveApiKey } from '../auth/auth-token-manager'; import { expandPath } from '../../utils/helpers'; import { warn } from '../../utils/ui'; @@ -31,6 +31,7 @@ import { normalizeIFlowLegacyModelAliases, normalizeModelIdForProvider, } from '../ai-providers/model-id-normalizer'; +import { getGlobalEnvConfig } from '../../config/config-loader-facade'; /** Settings file structure for user overrides */ interface ProviderSettings { diff --git a/src/cliproxy/config/generator.ts b/src/cliproxy/config/generator.ts index 3578c316..a34d8a45 100644 --- a/src/cliproxy/config/generator.ts +++ b/src/cliproxy/config/generator.ts @@ -9,11 +9,12 @@ import type { CLIProxyProvider, ProviderConfig } from '../types'; import { getProviderDisplayName } from '../provider-capabilities'; import { getModelMappingFromConfig } from '../config/base-config-loader'; import { AI_PROVIDER_FAMILY_IDS } from '../ai-providers/types'; -import { loadOrCreateUnifiedConfig } from '../../config/unified-config-loader'; + import { getEffectiveApiKey, getEffectiveManagementSecret } from '../auth/auth-token-manager'; import { getDeniedModelIdReasonForProvider } from '../ai-providers/model-id-normalizer'; import { getAuthDir, getProviderAuthDir, getConfigPathForPort } from './path-resolver'; import { CLIPROXY_DEFAULT_PORT } from './port-manager'; +import { loadOrCreateUnifiedConfig } from '../../config/config-loader-facade'; /** Internal API key for CCS-managed requests */ export const CCS_INTERNAL_API_KEY = 'ccs-internal-managed'; diff --git a/src/cliproxy/config/model-config.ts b/src/cliproxy/config/model-config.ts index 9c782d84..5237ce48 100644 --- a/src/cliproxy/config/model-config.ts +++ b/src/cliproxy/config/model-config.ts @@ -12,8 +12,9 @@ import { getProviderCatalog, supportsModelConfig, ModelEntry } from '../model-ca import { getClaudeEnvVars, resolveProviderSettingsPath } from './config-generator'; import { CLIProxyProvider } from '../types'; import { initUI, color, bold, dim, ok, info, header } from '../../utils/ui'; -import { getCcsDir } from '../../utils/config-manager'; + import { normalizeModelIdForProvider } from '../ai-providers/model-id-normalizer'; +import { getCcsDir } from '../../config/config-loader-facade'; function canonicalizeModelForProvider(provider: CLIProxyProvider, model: string): string { return normalizeModelIdForProvider(model, provider); diff --git a/src/cliproxy/config/path-resolver.ts b/src/cliproxy/config/path-resolver.ts index 413d6aee..547b9034 100644 --- a/src/cliproxy/config/path-resolver.ts +++ b/src/cliproxy/config/path-resolver.ts @@ -4,9 +4,10 @@ */ import * as path from 'path'; -import { getCcsDir } from '../../utils/config-manager'; + import type { CLIProxyProvider } from '../types'; import { CLIPROXY_DEFAULT_PORT } from './port-manager'; +import { getCcsDir } from '../../config/config-loader-facade'; /** * Get CLIProxy base directory diff --git a/src/cliproxy/config/thinking-config.ts b/src/cliproxy/config/thinking-config.ts index 7e1eba81..b4d545f9 100644 --- a/src/cliproxy/config/thinking-config.ts +++ b/src/cliproxy/config/thinking-config.ts @@ -6,11 +6,12 @@ import type { CLIProxyProvider } from '../types'; import { DEFAULT_THINKING_TIER_DEFAULTS } from '../../config/unified-config-types'; import type { ThinkingConfig } from '../../config/unified-config-types'; -import { getThinkingConfig } from '../../config/unified-config-loader'; + import { getModelThinkingSupport, supportsThinking } from '../model-catalog'; import { isThinkingOffValue, validateThinking } from '../thinking-validator'; import { normalizeModelIdForProvider } from '../ai-providers/model-id-normalizer'; import { warn } from '../../utils/ui'; +import { getThinkingConfig } from '../../config/config-loader-facade'; /** Model tier types for thinking budget defaults */ export type ModelTier = 'opus' | 'sonnet' | 'haiku'; diff --git a/src/cliproxy/executor/index.ts b/src/cliproxy/executor/index.ts index 80ca3088..6f6a6a93 100644 --- a/src/cliproxy/executor/index.ts +++ b/src/cliproxy/executor/index.ts @@ -16,7 +16,7 @@ import * as os from 'os'; import * as path from 'path'; import { ProgressIndicator } from '../../utils/progress-indicator'; import { ok, fail, info, warn } from '../../utils/ui'; -import { getCcsDir } from '../../utils/config-manager'; + import { escapeShellArg, getWindowsEscapedCommandShell } from '../../utils/shell-executor'; import { ensureCLIProxyBinary, @@ -77,11 +77,7 @@ import { resolveOptionalBrowserAttachRuntime, syncBrowserMcpToConfigDir, } from '../../utils/browser'; -import { - getBrowserConfig, - loadOrCreateUnifiedConfig, - getThinkingConfig, -} from '../../config/unified-config-loader'; + import { HttpsTunnelProxy } from '../proxy/https-tunnel-proxy'; import { isKiroAuthMethod, @@ -128,6 +124,12 @@ import { shouldDisableCodexReasoning, } from './thinking-override-resolver'; import { shouldStartHttpsTunnel } from './https-tunnel-policy'; +import { + getBrowserConfig, + getCcsDir, + getThinkingConfig, + loadOrCreateUnifiedConfig, +} from '../../config/config-loader-facade'; function resolveRuntimeQuotaMonitorProviders( provider: CLIProxyProvider, diff --git a/src/cliproxy/proxy/proxy-target-resolver.ts b/src/cliproxy/proxy/proxy-target-resolver.ts index 0f6e0e01..1f7875d8 100644 --- a/src/cliproxy/proxy/proxy-target-resolver.ts +++ b/src/cliproxy/proxy/proxy-target-resolver.ts @@ -5,7 +5,6 @@ * based on unified config. Used by stats-fetcher, auth-routes, and UI. */ -import { loadOrCreateUnifiedConfig } from '../../config/unified-config-loader'; import type { CliproxyServerConfig } from '../../config/unified-config-types'; import { CLIPROXY_DEFAULT_PORT, @@ -15,6 +14,7 @@ import { } from '../config/port-manager'; import { getProxyEnvVars } from './proxy-config-resolver'; import { getEffectiveManagementSecret } from '../auth/auth-token-manager'; +import { loadOrCreateUnifiedConfig } from '../../config/config-loader-facade'; /** Resolved proxy target for making requests */ export interface ProxyTarget { diff --git a/src/cliproxy/proxy/tool-sanitization-proxy.ts b/src/cliproxy/proxy/tool-sanitization-proxy.ts index bb3d99dd..3fed56e4 100644 --- a/src/cliproxy/proxy/tool-sanitization-proxy.ts +++ b/src/cliproxy/proxy/tool-sanitization-proxy.ts @@ -25,8 +25,9 @@ import { stripCodexEffortSuffix, } from '../ai-providers/model-id-normalizer'; import { getModelMaxLevel } from '../model-catalog'; -import { getCcsDir } from '../../utils/config-manager'; + import { createLogger } from '../../services/logging'; +import { getCcsDir } from '../../config/config-loader-facade'; export interface ToolSanitizationProxyConfig { /** Upstream CLIProxy URL */ diff --git a/src/cliproxy/quota/quota-manager.ts b/src/cliproxy/quota/quota-manager.ts index f715ee47..4493aeb6 100644 --- a/src/cliproxy/quota/quota-manager.ts +++ b/src/cliproxy/quota/quota-manager.ts @@ -32,8 +32,9 @@ import { touchAccount, type AccountInfo, } from '../accounts/account-manager'; -import { loadOrCreateUnifiedConfig } from '../../config/unified-config-loader'; + import type { RuntimeMonitorConfig } from '../../config/unified-config-types'; +import { loadOrCreateUnifiedConfig } from '../../config/config-loader-facade'; export type ManagedQuotaProvider = 'agy' | 'claude' | 'codex' | 'gemini' | 'ghcp'; type ManagedQuotaResult = diff --git a/src/cliproxy/routing/routing-strategy.ts b/src/cliproxy/routing/routing-strategy.ts index 65c44d86..d6ed1ec2 100644 --- a/src/cliproxy/routing/routing-strategy.ts +++ b/src/cliproxy/routing/routing-strategy.ts @@ -1,4 +1,3 @@ -import { mutateUnifiedConfig, loadOrCreateUnifiedConfig } from '../../config/unified-config-loader'; import { regenerateConfig } from '../config/generator'; import { getAuthDir, getConfigPathForPort } from '../config/path-resolver'; import { @@ -7,6 +6,7 @@ import { getRoutingErrorMessage, } from './routing-strategy-http'; import type { CliproxyRoutingStrategy } from '../types'; +import { loadOrCreateUnifiedConfig, mutateConfig } from '../../config/config-loader-facade'; export const DEFAULT_CLIPROXY_ROUTING_STRATEGY: CliproxyRoutingStrategy = 'round-robin'; export const DEFAULT_CLIPROXY_SESSION_AFFINITY_ENABLED = false; @@ -223,7 +223,7 @@ export async function applyCliproxyRoutingStrategy( }; } - mutateUnifiedConfig((config) => { + mutateConfig((config) => { if (config.cliproxy) { config.cliproxy.routing = { ...config.cliproxy.routing, strategy }; } @@ -278,7 +278,7 @@ export async function applyCliproxySessionAffinitySettings( current.ttl ?? DEFAULT_CLIPROXY_SESSION_AFFINITY_TTL; - mutateUnifiedConfig((config) => { + mutateConfig((config) => { if (config.cliproxy) { config.cliproxy.routing = { ...config.cliproxy.routing, diff --git a/src/cliproxy/services/binary-service.ts b/src/cliproxy/services/binary-service.ts index 530571ce..7c91fd09 100644 --- a/src/cliproxy/services/binary-service.ts +++ b/src/cliproxy/services/binary-service.ts @@ -22,7 +22,7 @@ import { } from '../binary-manager'; import { BACKEND_CONFIG, DEFAULT_BACKEND } from '../binary/platform-detector'; import { CLIProxyBackend } from '../types'; -import { loadOrCreateUnifiedConfig } from '../../config/unified-config-loader'; +import { loadOrCreateUnifiedConfig } from '../../config/config-loader-facade'; /** Binary status result */ export interface BinaryStatusResult { diff --git a/src/cliproxy/services/catalog-cache.ts b/src/cliproxy/services/catalog-cache.ts index 2a456459..925d7370 100644 --- a/src/cliproxy/services/catalog-cache.ts +++ b/src/cliproxy/services/catalog-cache.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; import * as path from 'path'; -import { getCcsDir } from '../../utils/config-manager'; + import type { CLIProxyProvider } from '../types'; import type { ModelEntry, ProviderCatalog, ThinkingSupport } from '../model-catalog'; import { MODEL_CATALOG } from '../model-catalog'; @@ -15,6 +15,7 @@ import { buildProxyUrl, getProxyTarget, } from '../proxy/proxy-target-resolver'; +import { getCcsDir } from '../../config/config-loader-facade'; const CACHE_FILE_NAME = 'model-catalog-cache.json'; const CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours diff --git a/src/cliproxy/services/variant-config-adapter.ts b/src/cliproxy/services/variant-config-adapter.ts index 2425cec1..a24d0df9 100644 --- a/src/cliproxy/services/variant-config-adapter.ts +++ b/src/cliproxy/services/variant-config-adapter.ts @@ -1,5 +1,5 @@ import * as fs from 'fs'; -import { getConfigPath, loadConfigSafe } from '../../utils/config-manager'; +import { getConfigPath } from '../../utils/config-manager'; import { CLIProxyProvider } from '../types'; import type { TargetType } from '../../targets/target-adapter'; import { @@ -8,12 +8,14 @@ import { CompositeTierConfig, CLIPROXY_SUPPORTED_PROVIDERS, } from '../../config/unified-config-types'; -import { - loadOrCreateUnifiedConfig, - mutateUnifiedConfig, - isUnifiedMode, -} from '../../config/unified-config-loader'; + import { CLIPROXY_DEFAULT_PORT } from '../config/config-generator'; +import { + isUnifiedMode, + loadConfigSafe, + loadOrCreateUnifiedConfig, + mutateConfig, +} from '../../config/config-loader-facade'; export const VARIANT_PORT_BASE = CLIPROXY_DEFAULT_PORT + 1; export const VARIANT_PORT_MAX_OFFSET = 100; @@ -171,7 +173,7 @@ export function listVariantsFromConfig(): Record { } export function saveCompositeVariantUnified(name: string, config: CompositeVariantConfig): void { - mutateUnifiedConfig((unifiedConfig) => { + mutateConfig((unifiedConfig) => { if (!unifiedConfig.cliproxy) { unifiedConfig.cliproxy = { oauth_accounts: {}, @@ -195,7 +197,7 @@ export function saveVariantUnified( port?: number, target: TargetType = 'claude' ): void { - mutateUnifiedConfig((config) => { + mutateConfig((config) => { if (!config.cliproxy) { config.cliproxy = { oauth_accounts: {}, @@ -266,7 +268,7 @@ export function saveVariantLegacy( export function removeVariantFromUnifiedConfig(name: string): VariantConfig | null { let removedVariant: CLIProxyVariantConfig | CompositeVariantConfig | null = null; - mutateUnifiedConfig((config) => { + mutateConfig((config) => { if (!config.cliproxy?.variants || !(name in config.cliproxy.variants)) { return; } diff --git a/src/cliproxy/services/variant-service.ts b/src/cliproxy/services/variant-service.ts index 629d9a09..39f5ed67 100644 --- a/src/cliproxy/services/variant-service.ts +++ b/src/cliproxy/services/variant-service.ts @@ -12,11 +12,11 @@ import { CLIProxyProvider, PLUS_ONLY_PROVIDERS } from '../types'; import { CompositeTierConfig, CompositeVariantConfig } from '../../config/unified-config-types'; import type { TargetType } from '../../targets/target-adapter'; import { isReservedName, isWindowsReservedName } from '../../config/reserved-names'; -import { isUnifiedMode } from '../../config/unified-config-loader'; + import { deleteConfigForPort } from '../config/config-generator'; import { hasActiveSessions, deleteSessionLockForPort } from '../session-tracker'; import { warn } from '../../utils/ui'; -import { getCcsDir } from '../../utils/config-manager'; + import { validateCompositeTiers } from '../config/composite-validator'; import { canonicalizeModelIdForProvider, @@ -43,6 +43,7 @@ import { getNextAvailablePort, } from './variant-config-adapter'; import { getConfiguredBackend, getPlusBackendUnavailableMessage } from '../binary-manager'; +import { getCcsDir, isUnifiedMode } from '../../config/config-loader-facade'; // Re-export VariantConfig from adapter export type { VariantConfig } from './variant-config-adapter'; diff --git a/src/cliproxy/services/variant-settings.ts b/src/cliproxy/services/variant-settings.ts index 88b9c6a0..2d27c4b4 100644 --- a/src/cliproxy/services/variant-settings.ts +++ b/src/cliproxy/services/variant-settings.ts @@ -9,7 +9,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; import { CLIProxyProfileName } from '../../auth/profile-detector'; -import { getCcsDir } from '../../utils/config-manager'; + import { expandPath } from '../../utils/helpers'; import { getClaudeEnvVars, CLIPROXY_DEFAULT_PORT } from '../config/config-generator'; import { CLIProxyProvider } from '../types'; @@ -24,6 +24,7 @@ import { prepareImageAnalysisFallbackHook } from '../../utils/hooks'; import { getEffectiveApiKey } from '../auth/auth-token-manager'; import { warn } from '../../utils/ui'; import { normalizeModelIdForProvider } from '../ai-providers/model-id-normalizer'; +import { getCcsDir } from '../../config/config-loader-facade'; /** Environment settings structure */ interface SettingsEnv { diff --git a/src/cliproxy/sync/auto-sync-watcher.ts b/src/cliproxy/sync/auto-sync-watcher.ts index bd264861..d5427342 100644 --- a/src/cliproxy/sync/auto-sync-watcher.ts +++ b/src/cliproxy/sync/auto-sync-watcher.ts @@ -7,9 +7,9 @@ import * as chokidar from 'chokidar'; import * as path from 'path'; -import { getCcsDir } from '../../utils/config-manager'; -import { loadOrCreateUnifiedConfig } from '../../config/unified-config-loader'; + import { syncToLocalConfig } from './local-config-sync'; +import { getCcsDir, loadOrCreateUnifiedConfig } from '../../config/config-loader-facade'; /** Debounce delay in milliseconds */ const DEBOUNCE_MS = 3000; diff --git a/src/cliproxy/sync/profile-mapper.ts b/src/cliproxy/sync/profile-mapper.ts index a092c982..d8b538aa 100644 --- a/src/cliproxy/sync/profile-mapper.ts +++ b/src/cliproxy/sync/profile-mapper.ts @@ -6,10 +6,11 @@ import * as fs from 'fs'; import * as path from 'path'; -import { getCcsDir } from '../../utils/config-manager'; + import { expandPath } from '../../utils/helpers'; import { listApiProfiles, isApiProfileConfigured } from '../../api/services/profile-reader'; import type { ClaudeKey } from '../management/management-api-types'; +import { getCcsDir } from '../../config/config-loader-facade'; /** * Profile info with settings for sync. diff --git a/src/commands/browser-command.ts b/src/commands/browser-command.ts index 3633f67e..8cf94e89 100644 --- a/src/commands/browser-command.ts +++ b/src/commands/browser-command.ts @@ -1,9 +1,10 @@ import * as browserUtils from '../utils/browser'; -import { getBrowserConfig, mutateUnifiedConfig } from '../config/unified-config-loader'; + import type { BrowserToolPolicy } from '../config/unified-config-types'; import { getCcsPathDisplay } from '../utils/config-manager'; import { getNodePlatformKey } from '../utils/browser/platform'; import { color, dim, header, initUI, subheader } from '../utils/ui'; +import { getBrowserConfig, mutateConfig } from '../config/config-loader-facade'; type HelpWriter = (line: string) => void; type BrowserLane = 'claude' | 'codex' | 'all'; @@ -216,7 +217,7 @@ function updateBrowserPolicies(updates: { claude?: BrowserToolPolicy; codex?: BrowserToolPolicy; }): void { - mutateUnifiedConfig((config) => { + mutateConfig((config) => { const current = getBrowserConfig(); config.browser = { claude: { @@ -235,7 +236,7 @@ function updateBrowserPolicies(updates: { function updateBrowserEnabled(subcommand: 'enable' | 'disable', lane: BrowserLane): void { const nextEnabled = subcommand === 'enable'; - mutateUnifiedConfig((config) => { + mutateConfig((config) => { const current = getBrowserConfig(); config.browser = { claude: { diff --git a/src/commands/cliproxy/resolve-lifecycle-port.ts b/src/commands/cliproxy/resolve-lifecycle-port.ts index e250d5e6..04294739 100644 --- a/src/commands/cliproxy/resolve-lifecycle-port.ts +++ b/src/commands/cliproxy/resolve-lifecycle-port.ts @@ -1,6 +1,7 @@ import { CLIPROXY_DEFAULT_PORT, validatePort } from '../../cliproxy/config/port-manager'; -import { loadOrCreateUnifiedConfig } from '../../config/unified-config-loader'; + import type { UnifiedConfig } from '../../config/unified-config-types'; +import { loadOrCreateUnifiedConfig } from '../../config/config-loader-facade'; type LifecyclePortConfig = Pick; diff --git a/src/commands/cliproxy/variant-subcommand.ts b/src/commands/cliproxy/variant-subcommand.ts index 1c8b7833..aedf6001 100644 --- a/src/commands/cliproxy/variant-subcommand.ts +++ b/src/commands/cliproxy/variant-subcommand.ts @@ -17,7 +17,7 @@ import type { CliproxyProviderRoutingHints } from '../../shared/cliproxy-model-r import { CLIProxyProvider, CLIProxyBackend } from '../../cliproxy/types'; import type { TargetType } from '../../targets/target-adapter'; import { getPersistedTargetChoices, isPersistedTargetType } from '../../targets/target-metadata'; -import { isUnifiedMode } from '../../config/unified-config-loader'; + import { initUI, header, color, ok, fail, warn, info, infoBox, dim } from '../../utils/ui'; import { InteractivePrompt } from '../../utils/prompt'; import { @@ -32,6 +32,7 @@ import { import { DEFAULT_BACKEND } from '../../cliproxy/binary/platform-detector'; import { CompositeTierConfig } from '../../config/unified-config-types'; import { formatAccountDisplayName } from '../../cliproxy/accounts/email-account-identity'; +import { isUnifiedMode } from '../../config/config-loader-facade'; interface CliproxyProfileArgs { name?: string; diff --git a/src/commands/config-auth/disable-command.ts b/src/commands/config-auth/disable-command.ts index d6efb0c2..e6d5b2fa 100644 --- a/src/commands/config-auth/disable-command.ts +++ b/src/commands/config-auth/disable-command.ts @@ -5,8 +5,9 @@ */ import { InteractivePrompt } from '../../utils/prompt'; -import { getDashboardAuthConfig, mutateUnifiedConfig } from '../../config/unified-config-loader'; + import { initUI, header, ok, info, warn, dim } from '../../utils/ui'; +import { getDashboardAuthConfig, mutateConfig } from '../../config/config-loader-facade'; /** * Handle disable command - disable auth with confirmation @@ -53,7 +54,7 @@ export async function handleDisable(): Promise { } // Disable auth - mutateUnifiedConfig((fullConfig) => { + mutateConfig((fullConfig) => { fullConfig.dashboard_auth = { enabled: false, username: fullConfig.dashboard_auth?.username ?? '', diff --git a/src/commands/config-auth/setup-command.ts b/src/commands/config-auth/setup-command.ts index 75df5d39..c7e6f448 100644 --- a/src/commands/config-auth/setup-command.ts +++ b/src/commands/config-auth/setup-command.ts @@ -8,9 +8,10 @@ import bcrypt from 'bcrypt'; import { InteractivePrompt } from '../../utils/prompt'; -import { mutateUnifiedConfig } from '../../config/unified-config-loader'; + import { initUI, header, subheader, ok, fail, info, warn, dim } from '../../utils/ui'; import type { AuthSetupResult } from './types'; +import { mutateConfig } from '../../config/config-loader-facade'; const BCRYPT_ROUNDS = 10; const MIN_PASSWORD_LENGTH = 8; @@ -99,7 +100,7 @@ export async function handleSetup(): Promise { // Hash password const passwordHash = await bcrypt.hash(password, BCRYPT_ROUNDS); - const config = mutateUnifiedConfig((currentConfig) => { + const config = mutateConfig((currentConfig) => { currentConfig.dashboard_auth = { enabled: true, username, diff --git a/src/commands/config-auth/show-command.ts b/src/commands/config-auth/show-command.ts index 8bbdc1bd..54cf117a 100644 --- a/src/commands/config-auth/show-command.ts +++ b/src/commands/config-auth/show-command.ts @@ -4,9 +4,9 @@ * Display current dashboard authentication status. */ -import { getDashboardAuthConfig } from '../../config/unified-config-loader'; import { initUI, header, subheader, ok, info, warn, dim, color } from '../../utils/ui'; import type { AuthStatusInfo } from './types'; +import { getDashboardAuthConfig } from '../../config/config-loader-facade'; /** * Get auth status info with ENV override detection diff --git a/src/commands/config-channels-command.ts b/src/commands/config-channels-command.ts index b06c654d..c31cc9ab 100644 --- a/src/commands/config-channels-command.ts +++ b/src/commands/config-channels-command.ts @@ -1,9 +1,5 @@ import { initUI, header, ok, info, warn, fail, subheader, color, dim } from '../utils/ui'; -import { - getOfficialChannelsConfig, - loadOrCreateUnifiedConfig, - updateUnifiedConfig, -} from '../config/unified-config-loader'; + import type { OfficialChannelId } from '../config/unified-config-types'; import { DEFAULT_OFFICIAL_CHANNELS_CONFIG } from '../config/unified-config-types'; import { @@ -42,6 +38,11 @@ import { isOfficialChannelSelectionValid, } from '../channels/official-channels-runtime'; import { extractOption, hasAnyFlag } from './arg-extractor'; +import { + getOfficialChannelsConfig, + loadOrCreateUnifiedConfig, + updateConfig, +} from '../config/config-loader-facade'; interface ChannelsCommandOptions { enable: boolean; @@ -440,7 +441,7 @@ export async function handleConfigChannelsCommand(args: string[]): Promise try { if (hasConfigMutation) { - updateUnifiedConfig({ channels: nextConfig }); + updateConfig({ channels: nextConfig }); } if (options.setToken) { diff --git a/src/commands/config-command.ts b/src/commands/config-command.ts index bf47b324..12360b4a 100644 --- a/src/commands/config-command.ts +++ b/src/commands/config-command.ts @@ -12,7 +12,7 @@ import { startServer } from '../web-server'; import { setupGracefulShutdown } from '../web-server/shutdown'; import { ensureCliproxyService } from '../cliproxy/service-manager'; import { CLIPROXY_DEFAULT_PORT } from '../cliproxy/config/config-generator'; -import { getDashboardAuthConfig } from '../config/unified-config-loader'; + import { initUI, header, ok, info, warn, fail } from '../utils/ui'; import { resolveNamedCommand, type NamedCommandRoute } from './named-command-router'; import { @@ -23,6 +23,7 @@ import { } from './config-dashboard-host'; import { parseConfigCommandArgs, showConfigCommandHelp } from './config-command-options'; import { createLogger } from '../services/logging'; +import { getDashboardAuthConfig } from '../config/config-loader-facade'; const logger = createLogger('command:config'); diff --git a/src/commands/config-image-analysis-command.ts b/src/commands/config-image-analysis-command.ts index b9ed3f6a..ce796ae6 100644 --- a/src/commands/config-image-analysis-command.ts +++ b/src/commands/config-image-analysis-command.ts @@ -6,11 +6,7 @@ */ import { initUI, header, ok, info, warn, fail, subheader, color, dim } from '../utils/ui'; -import { - getImageAnalysisConfig, - updateUnifiedConfig, - loadOrCreateUnifiedConfig, -} from '../config/unified-config-loader'; + import { DEFAULT_IMAGE_ANALYSIS_CONFIG } from '../config/unified-config-types'; import { CLIPROXY_PROVIDER_IDS, @@ -19,6 +15,11 @@ import { } from '../cliproxy/provider-capabilities'; import { extractOption, hasAnyFlag } from './arg-extractor'; import { normalizeImageAnalysisBackendId } from '../utils/hooks'; +import { + getImageAnalysisConfig, + loadOrCreateUnifiedConfig, + updateConfig, +} from '../config/config-loader-facade'; interface ImageAnalysisCommandOptions { enable?: boolean; @@ -346,7 +347,7 @@ export async function handleConfigImageAnalysisCommand(args: string[]): Promise< } if (hasChanges) { - updateUnifiedConfig({ image_analysis: imageConfig }); + updateConfig({ image_analysis: imageConfig }); console.log(ok('Configuration updated')); console.log(''); } diff --git a/src/commands/config-thinking-command.ts b/src/commands/config-thinking-command.ts index 646d4571..a33dd42e 100644 --- a/src/commands/config-thinking-command.ts +++ b/src/commands/config-thinking-command.ts @@ -6,11 +6,7 @@ */ import { initUI, header, ok, info, warn, fail, subheader, color, dim } from '../utils/ui'; -import { - getThinkingConfig, - updateUnifiedConfig, - loadOrCreateUnifiedConfig, -} from '../config/unified-config-loader'; + import { DEFAULT_THINKING_TIER_DEFAULTS } from '../config/unified-config-types'; import { VALID_THINKING_LEVELS } from '../cliproxy/thinking-validator'; import { @@ -18,6 +14,11 @@ import { parseThinkingCommandArgs, parseThinkingOverrideInput, } from './config-thinking-parser'; +import { + getThinkingConfig, + loadOrCreateUnifiedConfig, + updateConfig, +} from '../config/config-loader-facade'; const VALID_THINKING_MODES = ['auto', 'off', 'manual'] as const; @@ -293,7 +294,7 @@ export async function handleConfigThinkingCommand(args: string[]): Promise } if (hasChanges) { - updateUnifiedConfig({ thinking: thinkingConfig }); + updateConfig({ thinking: thinkingConfig }); console.log(ok('Configuration updated')); console.log(''); } diff --git a/src/commands/copilot-command.ts b/src/commands/copilot-command.ts index f25ebd52..4483f045 100644 --- a/src/commands/copilot-command.ts +++ b/src/commands/copilot-command.ts @@ -15,10 +15,11 @@ import { normalizeCopilotConfigWithWarnings, } from '../copilot'; import type { CopilotModel } from '../copilot'; -import { loadOrCreateUnifiedConfig, mutateUnifiedConfig } from '../config/unified-config-loader'; + import { DEFAULT_COPILOT_CONFIG } from '../config/unified-config-types'; import { ok, fail, info, color, warn } from '../utils/ui'; import { normalizeCopilotSubcommand } from '../copilot/constants'; +import { loadOrCreateUnifiedConfig, mutateConfig } from '../config/config-loader-facade'; /** * Handle copilot subcommand. @@ -361,7 +362,7 @@ async function handleStop(): Promise { * Handle enable subcommand. */ async function handleEnable(): Promise { - mutateUnifiedConfig((config) => { + mutateConfig((config) => { if (!config.copilot) { config.copilot = { ...DEFAULT_COPILOT_CONFIG }; } @@ -383,7 +384,7 @@ async function handleEnable(): Promise { * Handle disable subcommand. */ async function handleDisable(): Promise { - mutateUnifiedConfig((config) => { + mutateConfig((config) => { if (config.copilot) { config.copilot.enabled = false; } diff --git a/src/commands/cursor-command.ts b/src/commands/cursor-command.ts index 80c2f260..7510f4a7 100644 --- a/src/commands/cursor-command.ts +++ b/src/commands/cursor-command.ts @@ -16,7 +16,7 @@ import { getDefaultModel, probeCursorRuntime, } from '../cursor'; -import { getCursorConfig, mutateUnifiedConfig } from '../config/unified-config-loader'; + import { DEFAULT_CURSOR_CONFIG } from '../config/unified-config-types'; import { renderCursorHelp, @@ -25,6 +25,7 @@ import { renderCursorStatus, } from './cursor-command-display'; import { ok, fail, info } from '../utils/ui'; +import { getCursorConfig, mutateConfig } from '../config/config-loader-facade'; const LEGACY_CURSOR_COMMAND = 'ccs legacy cursor'; const CLIPROXY_CURSOR_COMMAND = 'ccs cursor'; @@ -286,7 +287,7 @@ async function handleStop(): Promise { */ async function handleEnable(): Promise { printLegacyCursorDeprecationNotice(); - mutateUnifiedConfig((config) => { + mutateConfig((config) => { if (!config.cursor) { config.cursor = { ...DEFAULT_CURSOR_CONFIG }; } @@ -310,7 +311,7 @@ async function handleEnable(): Promise { */ async function handleDisable(): Promise { printLegacyCursorDeprecationNotice(); - mutateUnifiedConfig((config) => { + mutateConfig((config) => { if (config.cursor) { config.cursor.enabled = false; } diff --git a/src/commands/env-command.ts b/src/commands/env-command.ts index bfb35103..ca3129b0 100644 --- a/src/commands/env-command.ts +++ b/src/commands/env-command.ts @@ -6,12 +6,13 @@ */ import { initUI, header, dim, color, subheader, fail, warn } from '../utils/ui'; -import { getCcsDir } from '../utils/config-manager'; + import { CLAUDE_EXTENSION_HOSTS, type ClaudeExtensionHost } from '../shared/claude-extension-hosts'; import { renderClaudeExtensionSettingsJson, resolveClaudeExtensionSetup, } from '../shared/claude-extension-setup'; +import { getCcsDir } from '../config/config-loader-facade'; type ShellType = 'bash' | 'fish' | 'powershell'; type OutputFormat = 'openai' | 'anthropic' | 'raw' | 'claude-extension'; diff --git a/src/commands/migrate-command.ts b/src/commands/migrate-command.ts index 3d643689..c7865222 100644 --- a/src/commands/migrate-command.ts +++ b/src/commands/migrate-command.ts @@ -16,8 +16,9 @@ import { needsMigration, getBackupDirectories, } from '../config/migration-manager'; -import { hasUnifiedConfig } from '../config/unified-config-loader'; + import { initUI, ok, fail, info, warn, infoBox, dim } from '../utils/ui'; +import { hasUnifiedConfig } from '../config/config-loader-facade'; export async function handleMigrateCommand(args: string[]): Promise { await initUI(); diff --git a/src/commands/proxy-command.ts b/src/commands/proxy-command.ts index 258e5526..53a11b11 100644 --- a/src/commands/proxy-command.ts +++ b/src/commands/proxy-command.ts @@ -1,5 +1,5 @@ import { detectShell, formatExportLine } from './env-command'; -import { getSettingsPath, loadSettings } from '../utils/config-manager'; +import { getSettingsPath } from '../utils/config-manager'; import { expandPath } from '../utils/helpers'; import { fail, info, ok } from '../utils/ui'; import { @@ -10,6 +10,7 @@ import { startOpenAICompatProxy, stopOpenAICompatProxy, } from '../proxy'; +import { loadSettings } from '../config/config-loader-facade'; function parseOptionValue(args: string[], key: string): string | undefined { const exactIndex = args.findIndex((arg) => arg === key); diff --git a/src/commands/setup-command.ts b/src/commands/setup-command.ts index ed1f884d..d5cccc2f 100644 --- a/src/commands/setup-command.ts +++ b/src/commands/setup-command.ts @@ -16,15 +16,17 @@ import * as readline from 'readline'; import * as fs from 'fs'; import * as path from 'path'; import { initUI, header, ok, info, warn } from '../utils/ui'; + +import { DEFAULT_CLIPROXY_SERVER_CONFIG } from '../config/unified-config-types'; + +import { CLIPROXY_DEFAULT_PORT } from '../cliproxy/config/port-manager'; import { + getCcsDir, + hasUnifiedConfig, loadOrCreateUnifiedConfig, loadUnifiedConfig, - mutateUnifiedConfig, - hasUnifiedConfig, -} from '../config/unified-config-loader'; -import { DEFAULT_CLIPROXY_SERVER_CONFIG } from '../config/unified-config-types'; -import { getCcsDir } from '../utils/config-manager'; -import { CLIPROXY_DEFAULT_PORT } from '../cliproxy/config/port-manager'; + mutateConfig, +} from '../config/config-loader-facade'; /** Custom error for user cancellation (Ctrl+C) */ class UserCancelledError extends Error { @@ -377,7 +379,7 @@ async function runSetupWizard(force: boolean = false): Promise { console.log(' After creating, edit the settings file to add your API key.'); } - mutateUnifiedConfig((currentConfig) => { + mutateConfig((currentConfig) => { currentConfig.setup_completed = true; currentConfig.cliproxy_server = config.cliproxy_server; }); diff --git a/src/commands/version-command.ts b/src/commands/version-command.ts index 3e8e350c..e355fbc8 100644 --- a/src/commands/version-command.ts +++ b/src/commands/version-command.ts @@ -7,9 +7,10 @@ import * as path from 'path'; import * as fs from 'fs'; import { initUI, header, subheader, color, warn } from '../utils/ui'; -import { getActiveConfigPath, getCcsDir } from '../utils/config-manager'; +import { getActiveConfigPath } from '../utils/config-manager'; import { getVersion } from '../utils/version'; import { getProfileLookupCandidates } from '../utils/profile-compat'; +import { getCcsDir } from '../config/config-loader-facade'; /** * Handle version command diff --git a/src/copilot/copilot-daemon.ts b/src/copilot/copilot-daemon.ts index 9214f02f..0575d233 100644 --- a/src/copilot/copilot-daemon.ts +++ b/src/copilot/copilot-daemon.ts @@ -11,10 +11,11 @@ import * as path from 'path'; import * as http from 'http'; import { CopilotDaemonStatus } from './types'; import { CopilotConfig, DEFAULT_COPILOT_CONFIG } from '../config/unified-config-types'; -import { loadOrCreateUnifiedConfig } from '../config/unified-config-loader'; + import { getCopilotDir, getCopilotApiBinPath } from './copilot-package-manager'; import { verifyProcessOwnership } from '../cursor/daemon-process-ownership'; import { createLogger } from '../services/logging'; +import { loadOrCreateUnifiedConfig } from '../config/config-loader-facade'; const logger = createLogger('copilot:daemon'); diff --git a/src/copilot/copilot-executor.ts b/src/copilot/copilot-executor.ts index b7d96962..ea36d9b0 100644 --- a/src/copilot/copilot-executor.ts +++ b/src/copilot/copilot-executor.ts @@ -7,7 +7,7 @@ import { spawn } from 'child_process'; import { CopilotConfig } from '../config/unified-config-types'; -import { getGlobalEnvConfig } from '../config/unified-config-loader'; + import { ensureCliproxyService } from '../cliproxy'; import { getEffectiveApiKey } from '../cliproxy/auth/auth-token-manager'; import { CLIPROXY_DEFAULT_PORT } from '../cliproxy/config/port-manager'; @@ -36,6 +36,7 @@ import { } from '../utils/hooks'; import { stripClaudeCodeEnv } from '../utils/shell-executor'; import { createLogger } from '../services/logging'; +import { getGlobalEnvConfig } from '../config/config-loader-facade'; const logger = createLogger('copilot:executor'); diff --git a/src/copilot/copilot-package-manager.ts b/src/copilot/copilot-package-manager.ts index e5c72fba..ebebb6d2 100644 --- a/src/copilot/copilot-package-manager.ts +++ b/src/copilot/copilot-package-manager.ts @@ -15,7 +15,7 @@ import * as path from 'path'; import { spawn, spawnSync } from 'child_process'; import { ProgressIndicator } from '../utils/progress-indicator'; import { ok, info } from '../utils/ui'; -import { getCcsDir } from '../utils/config-manager'; +import { getCcsDir } from '../config/config-loader-facade'; /** Cache duration for version check (1 hour in milliseconds) */ const VERSION_CACHE_DURATION_MS = 60 * 60 * 1000; diff --git a/src/cursor/cursor-auth.ts b/src/cursor/cursor-auth.ts index 313ec2a8..25284876 100644 --- a/src/cursor/cursor-auth.ts +++ b/src/cursor/cursor-auth.ts @@ -19,7 +19,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; import type { CursorCredentials, CursorAuthStatus, AutoDetectResult } from './types'; -import { getCcsDir } from '../utils/config-manager'; +import { getCcsDir } from '../config/config-loader-facade'; const ACCESS_TOKEN_KEYS = ['cursorAuth/accessToken', 'cursorAuth/token'] as const; const MACHINE_ID_KEYS = [ diff --git a/src/cursor/cursor-daemon-pid.ts b/src/cursor/cursor-daemon-pid.ts index fceef47a..ceb855d5 100644 --- a/src/cursor/cursor-daemon-pid.ts +++ b/src/cursor/cursor-daemon-pid.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; import * as path from 'path'; -import { getCcsDir } from '../utils/config-manager'; +import { getCcsDir } from '../config/config-loader-facade'; function getCursorDir(): string { return path.join(getCcsDir(), 'cursor'); diff --git a/src/cursor/cursor-profile-executor.ts b/src/cursor/cursor-profile-executor.ts index 1a1b239f..293bce24 100644 --- a/src/cursor/cursor-profile-executor.ts +++ b/src/cursor/cursor-profile-executor.ts @@ -1,7 +1,7 @@ import { spawn } from 'child_process'; import type { CursorConfig } from '../config/unified-config-types'; -import { getGlobalEnvConfig } from '../config/unified-config-loader'; + import { ensureCliproxyService } from '../cliproxy'; import { CLIPROXY_DEFAULT_PORT } from '../cliproxy/config/port-manager'; import { fail, info, ok } from '../utils/ui'; @@ -15,6 +15,7 @@ import { getImageAnalysisHookEnv, resolveImageAnalysisRuntimeStatus } from '../u import { stripClaudeCodeEnv } from '../utils/shell-executor'; import { checkAuthStatus } from './cursor-auth'; import { isDaemonRunning, startDaemon } from './cursor-daemon'; +import { getGlobalEnvConfig } from '../config/config-loader-facade'; interface CursorImageAnalysisResolution { env: Record; diff --git a/src/delegation/delegation-handler.ts b/src/delegation/delegation-handler.ts index 79870271..2716bfcb 100644 --- a/src/delegation/delegation-handler.ts +++ b/src/delegation/delegation-handler.ts @@ -6,7 +6,7 @@ import { ResultFormatter } from './result-formatter'; import { DelegationValidator } from '../utils/delegation-validator'; import { SettingsParser } from './settings-parser'; import { fail, warn } from '../utils/ui'; -import { getCcsDir } from '../utils/config-manager'; +import { getCcsDir } from '../config/config-loader-facade'; const PROFILE_FLAGS_WITH_VALUE = new Set(['-p', '--prompt', '--effort']); diff --git a/src/delegation/headless-executor.ts b/src/delegation/headless-executor.ts index 26e2760c..cb97bb32 100644 --- a/src/delegation/headless-executor.ts +++ b/src/delegation/headless-executor.ts @@ -15,8 +15,8 @@ import { ui, warn, info } from '../utils/ui'; import { type ExecutionOptions, type ExecutionResult, type StreamMessage } from './executor/types'; import { StreamBuffer, formatToolVerbose } from './executor/stream-parser'; import { buildExecutionResult } from './executor/result-aggregator'; -import { getCcsDir, getModelDisplayName, loadSettings } from '../utils/config-manager'; -import { getGlobalEnvConfig } from '../config/unified-config-loader'; +import { getModelDisplayName } from '../utils/config-manager'; + import { getProfileLookupCandidates } from '../utils/profile-compat'; import { getClaudeLaunchEnvOverrides, @@ -58,6 +58,7 @@ import { readWebSearchTraceRecords, syncWebSearchMcpToConfigDir, } from '../utils/websearch-manager'; +import { getCcsDir, getGlobalEnvConfig, loadSettings } from '../config/config-loader-facade'; // Re-export types for consumers export type { ExecutionOptions, ExecutionResult, StreamMessage } from './executor/types'; diff --git a/src/delegation/session-manager.ts b/src/delegation/session-manager.ts index c407daad..79d94438 100644 --- a/src/delegation/session-manager.ts +++ b/src/delegation/session-manager.ts @@ -6,7 +6,7 @@ import * as fs from 'fs'; import * as path from 'path'; -import { getCcsDir } from '../utils/config-manager'; +import { getCcsDir } from '../config/config-loader-facade'; interface SessionData { sessionId: string; diff --git a/src/docker/docker-assets.ts b/src/docker/docker-assets.ts index 1ebf58aa..b40c6808 100644 --- a/src/docker/docker-assets.ts +++ b/src/docker/docker-assets.ts @@ -1,6 +1,7 @@ import * as path from 'path'; -import { getCcsDir } from '../utils/config-manager'; + import type { DockerConfigSummary } from './docker-types'; +import { getCcsDir } from '../config/config-loader-facade'; export const DOCKER_REMOTE_DIR = '~/.ccs/docker'; export const DOCKER_COMPOSE_SERVICE = 'ccs-cliproxy'; diff --git a/src/glmt/glmt-transformer.ts b/src/glmt/glmt-transformer.ts index 72c4c63e..68a18b6f 100644 --- a/src/glmt/glmt-transformer.ts +++ b/src/glmt/glmt-transformer.ts @@ -11,7 +11,7 @@ import * as fs from 'fs'; import * as path from 'path'; import { DeltaAccumulator } from './delta-accumulator'; -import { getCcsDir } from '../utils/config-manager'; + import { createLogger } from '../services/logging'; import { RequestTransformer, @@ -32,6 +32,7 @@ import { type ThinkingSignature, type ValidationResult, } from './pipeline'; +import { getCcsDir } from '../config/config-loader-facade'; export class GlmtTransformer { private verbose: boolean; diff --git a/src/management/checks/config-check.ts b/src/management/checks/config-check.ts index 8c1af017..b706852b 100644 --- a/src/management/checks/config-check.ts +++ b/src/management/checks/config-check.ts @@ -6,8 +6,9 @@ import * as fs from 'fs'; import * as path from 'path'; import { ok, fail, warn, info } from '../../utils/ui'; import { HealthCheck, IHealthChecker, createSpinner } from './types'; -import { getCcsDir } from '../../utils/config-manager'; + import { getClaudeConfigDir } from '../../utils/claude-config-path'; +import { getCcsDir } from '../../config/config-loader-facade'; const ora = createSpinner(); diff --git a/src/management/checks/env-check.ts b/src/management/checks/env-check.ts index 95a34a61..0dab2952 100644 --- a/src/management/checks/env-check.ts +++ b/src/management/checks/env-check.ts @@ -4,8 +4,9 @@ import { getEnvironmentDiagnostics } from '../environment-diagnostics'; import { ok, warn } from '../../utils/ui'; -import { getCcsDir, getCcsDirSource } from '../../utils/config-manager'; +import { getCcsDirSource } from '../../utils/config-manager'; import { HealthCheck, IHealthChecker, createSpinner } from './types'; +import { getCcsDir } from '../../config/config-loader-facade'; const ora = createSpinner(); diff --git a/src/management/checks/image-analysis-check.ts b/src/management/checks/image-analysis-check.ts index 85fe7e3a..50e9ba99 100644 --- a/src/management/checks/image-analysis-check.ts +++ b/src/management/checks/image-analysis-check.ts @@ -5,7 +5,6 @@ * Checks: enabled status, provider_models, timeout, CLIProxy availability. */ -import { getImageAnalysisConfig } from '../../config/unified-config-loader'; import { DEFAULT_IMAGE_ANALYSIS_CONFIG } from '../../config/unified-config-types'; import { countManagedImageAnalysisHookFiles, @@ -17,6 +16,7 @@ import { isCliproxyRunning } from '../../cliproxy/services/stats-fetcher'; import { CLIPROXY_DEFAULT_PORT } from '../../cliproxy/config/config-generator'; import type { HealthCheck } from './types'; import { hasImageAnalyzerHook } from '../../utils/hooks/image-analyzer-hook-installer'; +import { getImageAnalysisConfig } from '../../config/config-loader-facade'; /** * Run image analysis configuration check @@ -112,8 +112,8 @@ export async function runImageAnalysisCheck(results: HealthCheck): Promise * Fix image analysis configuration issues */ export async function fixImageAnalysisConfig(): Promise { - const { updateUnifiedConfig, loadOrCreateUnifiedConfig } = await import( - '../../config/unified-config-loader' + const { updateConfig, loadOrCreateUnifiedConfig } = await import( + '../../config/config-loader-facade' ); const config = loadOrCreateUnifiedConfig(); @@ -145,7 +145,7 @@ export async function fixImageAnalysisConfig(): Promise { } if (fixed) { - updateUnifiedConfig({ image_analysis: config.image_analysis }); + updateConfig({ image_analysis: config.image_analysis }); } const repairStats = repairImageAnalysisRuntimeState(); diff --git a/src/management/checks/profile-check.ts b/src/management/checks/profile-check.ts index d1cd555b..5c969a83 100644 --- a/src/management/checks/profile-check.ts +++ b/src/management/checks/profile-check.ts @@ -6,7 +6,7 @@ import * as fs from 'fs'; import * as path from 'path'; import { ok, fail, warn, info } from '../../utils/ui'; import { HealthCheck, IHealthChecker, createSpinner } from './types'; -import { getCcsDir } from '../../utils/config-manager'; +import { getCcsDir } from '../../config/config-loader-facade'; const ora = createSpinner(); diff --git a/src/management/checks/symlink-check.ts b/src/management/checks/symlink-check.ts index 0d4a6fa7..56f7d0e4 100644 --- a/src/management/checks/symlink-check.ts +++ b/src/management/checks/symlink-check.ts @@ -7,7 +7,7 @@ import * as path from 'path'; import * as os from 'os'; import { ok, fail, warn } from '../../utils/ui'; import { HealthCheck, IHealthChecker, createSpinner } from './types'; -import { getCcsDir } from '../../utils/config-manager'; +import { getCcsDir } from '../../config/config-loader-facade'; const ora = createSpinner(); diff --git a/src/management/checks/system-check.ts b/src/management/checks/system-check.ts index aaa8d458..875c0976 100644 --- a/src/management/checks/system-check.ts +++ b/src/management/checks/system-check.ts @@ -8,7 +8,7 @@ import { getClaudeCliInfo } from '../../utils/claude-detector'; import { escapeShellArg, stripClaudeCodeEnv } from '../../utils/shell-executor'; import { ok, fail } from '../../utils/ui'; import { HealthCheck, IHealthChecker, createSpinner } from './types'; -import { getCcsDir } from '../../utils/config-manager'; +import { getCcsDir } from '../../config/config-loader-facade'; const ora = createSpinner(); diff --git a/src/management/instance-manager.ts b/src/management/instance-manager.ts index ba39c65c..e6d73717 100644 --- a/src/management/instance-manager.ts +++ b/src/management/instance-manager.ts @@ -12,8 +12,9 @@ import SharedManager from './shared-manager'; import ProfileContextSyncLock from './profile-context-sync-lock'; import { DEFAULT_ACCOUNT_CONTEXT_MODE } from '../auth/account-context'; import type { AccountContextPolicy } from '../auth/account-context'; -import { getCcsDir, getCcsHome } from '../utils/config-manager'; +import { getCcsHome } from '../utils/config-manager'; import { createLogger } from '../services/logging'; +import { getCcsDir } from '../config/config-loader-facade'; const logger = createLogger('management:instance-manager'); diff --git a/src/management/recovery-manager.ts b/src/management/recovery-manager.ts index e7f6decf..425f76d7 100644 --- a/src/management/recovery-manager.ts +++ b/src/management/recovery-manager.ts @@ -7,13 +7,14 @@ import * as fs from 'fs'; import * as path from 'path'; import { info } from '../utils/ui'; -import { getCcsHome, getCcsDir } from '../utils/config-manager'; +import { getCcsHome } from '../utils/config-manager'; import { createEmptyUnifiedConfig, UNIFIED_CONFIG_VERSION } from '../config/unified-config-types'; import { - saveUnifiedConfig, + getCcsDir, hasUnifiedConfig, loadUnifiedConfig, -} from '../config/unified-config-loader'; + saveConfig, +} from '../config/config-loader-facade'; /** * Recovery Manager Class @@ -137,7 +138,7 @@ class RecoveryManager { config.version = UNIFIED_CONFIG_VERSION; try { - saveUnifiedConfig(config); + saveConfig(config); this.recovered.push(`Created ${this.ccsDir}/config.yaml`); return true; } catch (_saveErr) { diff --git a/src/management/repair/auto-repair.ts b/src/management/repair/auto-repair.ts index 861a30b6..d0db80b3 100644 --- a/src/management/repair/auto-repair.ts +++ b/src/management/repair/auto-repair.ts @@ -5,7 +5,7 @@ import * as fs from 'fs'; import * as path from 'path'; import { ok, warn, fail, info, header, color } from '../../utils/ui'; -import { getCcsDir } from '../../utils/config-manager'; + import { CLIPROXY_DEFAULT_PORT, configNeedsRegeneration, @@ -16,6 +16,7 @@ import { getPortProcess, isCLIProxyProcess } from '../../utils/port-utils'; import { killProcessOnPort, getPlatformName } from '../../utils/platform-commands'; import { createSpinner } from '../checks/types'; import { fixImageAnalysisConfig } from '../checks/image-analysis-check'; +import { getCcsDir } from '../../config/config-loader-facade'; const ora = createSpinner(); diff --git a/src/management/shared-manager.ts b/src/management/shared-manager.ts index c2f79d2c..d9963679 100644 --- a/src/management/shared-manager.ts +++ b/src/management/shared-manager.ts @@ -13,11 +13,12 @@ import ProfileContextSyncLock from './profile-context-sync-lock'; import { ok, info, warn } from '../utils/ui'; import { DEFAULT_ACCOUNT_CONTEXT_GROUP } from '../auth/account-context'; import type { AccountContextPolicy } from '../auth/account-context'; -import { getCcsDir } from '../utils/config-manager'; + import { normalizePluginMetadataContent, normalizePluginMetadataValue, } from './plugin-path-normalizer'; +import { getCcsDir } from '../config/config-loader-facade'; export { normalizePluginMetadataContent, normalizePluginMetadataPathString, diff --git a/src/proxy/proxy-daemon-entry.ts b/src/proxy/proxy-daemon-entry.ts index d66b1f34..8f3b7e24 100644 --- a/src/proxy/proxy-daemon-entry.ts +++ b/src/proxy/proxy-daemon-entry.ts @@ -1,7 +1,7 @@ -import { loadSettings } from '../utils/config-manager'; import { resolveOpenAICompatProfileConfig } from './profile-router'; import { OPENAI_COMPAT_PROXY_DEFAULT_PORT } from './proxy-daemon-paths'; import { startOpenAICompatProxyServer } from './server/proxy-server'; +import { loadSettings } from '../config/config-loader-facade'; interface RuntimeOptions { port: number; diff --git a/src/proxy/proxy-daemon-paths.ts b/src/proxy/proxy-daemon-paths.ts index 843e1286..c321d121 100644 --- a/src/proxy/proxy-daemon-paths.ts +++ b/src/proxy/proxy-daemon-paths.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import { getCcsDir } from '../utils/config-manager'; +import { getCcsDir } from '../config/config-loader-facade'; export const OPENAI_COMPAT_PROXY_LEGACY_DEFAULT_PORT = 3456; export const OPENAI_COMPAT_PROXY_ADAPTIVE_PORT_START = 43_456; diff --git a/src/proxy/proxy-port-resolver.ts b/src/proxy/proxy-port-resolver.ts index cd7cd9a3..95f15268 100644 --- a/src/proxy/proxy-port-resolver.ts +++ b/src/proxy/proxy-port-resolver.ts @@ -1,9 +1,9 @@ -import { loadOrCreateUnifiedConfig } from '../config/unified-config-loader'; import { OPENAI_COMPAT_PROXY_ADAPTIVE_PORT_END, OPENAI_COMPAT_PROXY_ADAPTIVE_PORT_START, OPENAI_COMPAT_PROXY_LEGACY_DEFAULT_PORT, } from './proxy-daemon-paths'; +import { loadOrCreateUnifiedConfig } from '../config/config-loader-facade'; export interface OpenAICompatProxyPortPreference { port: number; diff --git a/src/proxy/request-router.ts b/src/proxy/request-router.ts index aa758280..2025cbea 100644 --- a/src/proxy/request-router.ts +++ b/src/proxy/request-router.ts @@ -1,4 +1,3 @@ -import { loadConfigSafe, loadSettings } from '../utils/config-manager'; import { expandPath } from '../utils/helpers'; import type { ProxyOpenAIRequest } from './transformers/request-transformer'; import { @@ -6,6 +5,7 @@ import { type OpenAICompatProxyRoutingConfig, } from './routing-config'; import { resolveOpenAICompatProfileConfig, type OpenAICompatProfileConfig } from './profile-router'; +import { loadConfigSafe, loadSettings } from '../config/config-loader-facade'; export type ProxyRoutingScenario = 'default' | 'background' | 'think' | 'longContext' | 'webSearch'; diff --git a/src/services/logging/log-config.ts b/src/services/logging/log-config.ts index 3985d25e..0c8b9def 100644 --- a/src/services/logging/log-config.ts +++ b/src/services/logging/log-config.ts @@ -1,10 +1,11 @@ import * as fs from 'fs'; import { DEFAULT_LOGGING_CONFIG } from '../../config/unified-config-types'; + +import type { LoggingConfig } from './log-types'; import { getConfigYamlPath, getLoggingConfig as getUnifiedLoggingConfig, -} from '../../config/unified-config-loader'; -import type { LoggingConfig } from './log-types'; +} from '../../config/config-loader-facade'; const CACHE_RECHECK_MS = 1000; let cachedConfig: LoggingConfig = { ...DEFAULT_LOGGING_CONFIG }; diff --git a/src/services/logging/log-paths.ts b/src/services/logging/log-paths.ts index 258e256d..1fe2fb21 100644 --- a/src/services/logging/log-paths.ts +++ b/src/services/logging/log-paths.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; import * as path from 'path'; -import { getCcsDir } from '../../utils/config-manager'; +import { getCcsDir } from '../../config/config-loader-facade'; const LOGS_DIR = 'logs'; const ARCHIVE_DIR = 'archive'; diff --git a/src/utils/browser/browser-setup.ts b/src/utils/browser/browser-setup.ts index 1d23e738..b95345fc 100644 --- a/src/utils/browser/browser-setup.ts +++ b/src/utils/browser/browser-setup.ts @@ -1,4 +1,3 @@ -import { getBrowserConfig, mutateUnifiedConfig } from '../../config/unified-config-loader'; import type { BrowserConfig } from '../../config/unified-config-types'; import { getNodePlatformKey } from './platform'; import { type BrowserStatusPayload, getBrowserStatus } from './browser-status'; @@ -9,6 +8,7 @@ import { getRecommendedBrowserUserDataDir, isManagedClaudeBrowserAttachConfig, } from './browser-settings'; +import { getBrowserConfig, mutateConfig } from '../../config/config-loader-facade'; export interface BrowserSetupResult { configUpdated: boolean; @@ -23,14 +23,14 @@ export interface BrowserSetupResult { export interface BrowserSetupDeps { getBrowserConfig: typeof getBrowserConfig; - mutateUnifiedConfig: typeof mutateUnifiedConfig; + mutateConfig: typeof mutateConfig; ensureBrowserMcp: typeof ensureBrowserMcp; getBrowserStatus: typeof getBrowserStatus; } const defaultBrowserSetupDeps: BrowserSetupDeps = { getBrowserConfig, - mutateUnifiedConfig, + mutateConfig, ensureBrowserMcp, getBrowserStatus, }; @@ -81,7 +81,7 @@ export async function runBrowserSetup( function persistBrowserSetupConfig(deps: BrowserSetupDeps, currentConfig: BrowserConfig): boolean { const before = JSON.stringify(currentConfig); - deps.mutateUnifiedConfig((config) => { + deps.mutateConfig((config) => { const existingBrowser = config.browser ?? currentConfig; const currentUserDataDir = existingBrowser.claude.user_data_dir?.trim(); diff --git a/src/utils/browser/browser-status.ts b/src/utils/browser/browser-status.ts index 2fbe14ef..48732454 100644 --- a/src/utils/browser/browser-status.ts +++ b/src/utils/browser/browser-status.ts @@ -4,7 +4,7 @@ import type { BrowserEvalMode, BrowserToolPolicy, } from '../../config/unified-config-types'; -import { getBrowserConfig, loadUnifiedConfig } from '../../config/unified-config-loader'; + import { getCcsPathDisplay } from '../config-manager'; import { getCodexBinaryInfo } from '../../targets/codex-detector'; import { type BrowserRuntimeEnv, resolveBrowserRuntimeEnv } from './chrome-reuse'; @@ -19,6 +19,7 @@ import { getEffectiveClaudeBrowserAttachConfig, getRecommendedBrowserUserDataDir, } from './browser-settings'; +import { getBrowserConfig, loadUnifiedConfig } from '../../config/config-loader-facade'; export interface ClaudeBrowserStatus { enabled: boolean; diff --git a/src/utils/config-manager.ts b/src/utils/config-manager.ts index 5bb7d79c..e6d183a0 100644 --- a/src/utils/config-manager.ts +++ b/src/utils/config-manager.ts @@ -6,7 +6,7 @@ import { isConfig, isSettings } from '../types'; import type { Config, Settings, CLIProxyVariantsConfig, CLIProxyVariantConfig } from '../types'; import { expandPath, error } from './helpers'; import { info } from './ui'; -import { isUnifiedMode, loadOrCreateUnifiedConfig } from '../config/unified-config-loader'; +import { isUnifiedMode, loadOrCreateUnifiedConfig } from '../config/config-loader-facade'; // TODO: Replace with proper imports after converting these files // const { ErrorManager } = require('./error-manager'); diff --git a/src/utils/hooks/get-image-analysis-hook-env.ts b/src/utils/hooks/get-image-analysis-hook-env.ts index 8c1777a6..86e947fe 100644 --- a/src/utils/hooks/get-image-analysis-hook-env.ts +++ b/src/utils/hooks/get-image-analysis-hook-env.ts @@ -7,7 +7,6 @@ * @module utils/hooks/image-analysis-hook-env */ -import { getImageAnalysisConfig } from '../../config/unified-config-loader'; import { resolveCliproxyBridgeProfile } from '../../api/services/cliproxy-profile-bridge'; import { getEffectiveApiKey } from '../../cliproxy/auth/auth-token-manager'; import { mapExternalProviderName } from '../../cliproxy/provider-capabilities'; @@ -21,6 +20,7 @@ import { resolveImageAnalysisStatus, type ImageAnalysisResolutionContext, } from './image-analysis-backend-resolver'; +import { getImageAnalysisConfig } from '../../config/config-loader-facade'; /** * Serialize provider_models map to env var format: provider:model,provider:model diff --git a/src/utils/hooks/image-analyzer-hook-configuration.ts b/src/utils/hooks/image-analyzer-hook-configuration.ts index 45de9481..057dd375 100644 --- a/src/utils/hooks/image-analyzer-hook-configuration.ts +++ b/src/utils/hooks/image-analyzer-hook-configuration.ts @@ -7,8 +7,9 @@ */ import * as path from 'path'; -import { getImageAnalysisConfig } from '../../config/unified-config-loader'; + import { getCcsHooksDir } from '../config-manager'; +import { getImageAnalysisConfig } from '../../config/config-loader-facade'; // Hook file name const IMAGE_ANALYZER_HOOK = 'image-analyzer-transformer.cjs'; diff --git a/src/utils/hooks/image-analyzer-hook-installer.ts b/src/utils/hooks/image-analyzer-hook-installer.ts index e124c74a..9bb5bf7e 100644 --- a/src/utils/hooks/image-analyzer-hook-installer.ts +++ b/src/utils/hooks/image-analyzer-hook-installer.ts @@ -12,9 +12,10 @@ import * as path from 'path'; import { info, warn } from '../ui'; import { getImageAnalyzerHookPath } from './image-analyzer-hook-configuration'; import { getCcsHooksDir } from '../config-manager'; -import { getImageAnalysisConfig } from '../../config/unified-config-loader'; + import { removeMigrationMarker } from './image-analyzer-profile-hook-injector'; import { installImageAnalysisPrompts } from '../image-analysis/hook-installer'; +import { getImageAnalysisConfig } from '../../config/config-loader-facade'; // Re-export from hook-configuration for backward compatibility export { diff --git a/src/utils/hooks/image-analyzer-profile-hook-injector.ts b/src/utils/hooks/image-analyzer-profile-hook-injector.ts index 73a0517e..76b907cf 100644 --- a/src/utils/hooks/image-analyzer-profile-hook-injector.ts +++ b/src/utils/hooks/image-analyzer-profile-hook-injector.ts @@ -21,12 +21,13 @@ import { isCcsImageAnalyzerHook, removeCcsImageAnalyzerHooks, } from './image-analyzer-hook-utils'; -import { getImageAnalysisConfig } from '../../config/unified-config-loader'; + import { getCcsDir } from '../config-manager'; import { resolveImageAnalysisStatus, type ImageAnalysisResolutionContext, } from './image-analysis-backend-resolver'; +import { getImageAnalysisConfig } from '../../config/config-loader-facade'; // Valid profile name pattern (alphanumeric, dot, dash, underscore only) const VALID_PROFILE_NAME = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/; diff --git a/src/utils/image-analysis/mcp-installer.ts b/src/utils/image-analysis/mcp-installer.ts index 76b8c3d2..64bd9e35 100644 --- a/src/utils/image-analysis/mcp-installer.ts +++ b/src/utils/image-analysis/mcp-installer.ts @@ -5,12 +5,13 @@ import * as fs from 'fs'; import * as path from 'path'; import * as lockfile from 'proper-lockfile'; -import { getImageAnalysisConfig } from '../../config/unified-config-loader'; + import { getCcsDir } from '../config-manager'; import { getClaudeUserConfigPath } from '../claude-config-path'; import { info, warn } from '../ui'; import { InstanceManager } from '../../management/instance-manager'; import { installImageAnalysisPrompts } from './hook-installer'; +import { getImageAnalysisConfig } from '../../config/config-loader-facade'; const IMAGE_ANALYSIS_MCP_SERVER = 'ccs-image-analysis-server.cjs'; const IMAGE_ANALYSIS_MCP_RUNTIME = 'image-analysis-runtime.cjs'; diff --git a/src/utils/shell-executor.ts b/src/utils/shell-executor.ts index 35a7505d..4b236a90 100644 --- a/src/utils/shell-executor.ts +++ b/src/utils/shell-executor.ts @@ -8,8 +8,9 @@ import { spawn, spawnSync, ChildProcess, type SpawnOptions } from 'child_process import { ErrorManager } from './error-manager'; import { getWebSearchHookEnv } from './websearch-manager'; import { wireChildProcessSignals } from './signal-forwarder'; -import { loadOrCreateUnifiedConfig } from '../config/unified-config-loader'; + import SharedManager from '../management/shared-manager'; +import { loadOrCreateUnifiedConfig } from '../config/config-loader-facade'; /** * Strip ANTHROPIC_* env vars from an environment object. diff --git a/src/utils/websearch/hook-config.ts b/src/utils/websearch/hook-config.ts index b7d6c092..83b605ab 100644 --- a/src/utils/websearch/hook-config.ts +++ b/src/utils/websearch/hook-config.ts @@ -9,10 +9,11 @@ import * as fs from 'fs'; import * as path from 'path'; import { info, warn } from '../ui'; -import { getWebSearchConfig } from '../../config/unified-config-loader'; + import { getCcsHooksDir } from '../config-manager'; import { getClaudeSettingsPath } from '../claude-config-path'; import { isCcsWebSearchHook, deduplicateCcsHooks } from './hook-utils'; +import { getWebSearchConfig } from '../../config/config-loader-facade'; // Hook file name const WEBSEARCH_HOOK = 'websearch-transformer.cjs'; diff --git a/src/utils/websearch/hook-env.ts b/src/utils/websearch/hook-env.ts index 2e79e649..f3b8887f 100644 --- a/src/utils/websearch/hook-env.ts +++ b/src/utils/websearch/hook-env.ts @@ -6,9 +6,9 @@ * @module utils/websearch/hook-env */ -import { getWebSearchConfig } from '../../config/unified-config-loader'; import { normalizeSearxngBaseUrl } from './types'; import { resolveAllowedWebSearchTraceFile } from './trace'; +import { getWebSearchConfig } from '../../config/config-loader-facade'; /** * Get environment variables for WebSearch hook configuration. diff --git a/src/utils/websearch/hook-installer.ts b/src/utils/websearch/hook-installer.ts index dc5c1f70..64a18797 100644 --- a/src/utils/websearch/hook-installer.ts +++ b/src/utils/websearch/hook-installer.ts @@ -9,9 +9,10 @@ import * as fs from 'fs'; import * as path from 'path'; import { info, warn } from '../ui'; -import { getWebSearchConfig } from '../../config/unified-config-loader'; + import { getCcsDir, getCcsHooksDir } from '../config-manager'; import { getHookPath } from './hook-config'; +import { getWebSearchConfig } from '../../config/config-loader-facade'; // Re-export from hook-config for backward compatibility export { getHookPath, getWebSearchHookConfig } from './hook-config'; diff --git a/src/utils/websearch/mcp-installer.ts b/src/utils/websearch/mcp-installer.ts index 5f7260e9..967860ba 100644 --- a/src/utils/websearch/mcp-installer.ts +++ b/src/utils/websearch/mcp-installer.ts @@ -4,13 +4,14 @@ import * as fs from 'fs'; import * as path from 'path'; -import { getWebSearchConfig } from '../../config/unified-config-loader'; + import { getCcsDir } from '../config-manager'; import { getClaudeUserConfigPath } from '../claude-config-path'; import { info, warn } from '../ui'; import { InstanceManager } from '../../management/instance-manager'; import { installWebSearchHook } from './hook-installer'; import { appendWebSearchTrace } from './trace'; +import { getWebSearchConfig } from '../../config/config-loader-facade'; const WEBSEARCH_MCP_SERVER = 'ccs-websearch-server.cjs'; const WEBSEARCH_MCP_SERVER_NAME = 'ccs-websearch'; diff --git a/src/utils/websearch/profile-hook-injector.ts b/src/utils/websearch/profile-hook-injector.ts index 62bbed64..f1e909d6 100644 --- a/src/utils/websearch/profile-hook-injector.ts +++ b/src/utils/websearch/profile-hook-injector.ts @@ -12,11 +12,12 @@ import * as fs from 'fs'; import * as path from 'path'; import { info, warn } from '../ui'; import { getWebSearchHookConfig, getHookPath } from './hook-config'; -import { getWebSearchConfig } from '../../config/unified-config-loader'; + import { removeHookConfig } from './hook-config'; import { getCcsDir } from '../config-manager'; import { isCcsWebSearchHook, deduplicateCcsHooks } from './hook-utils'; import { getMigrationMarkerPath, installWebSearchHook } from './hook-installer'; +import { getWebSearchConfig } from '../../config/config-loader-facade'; // Valid profile name pattern (alphanumeric, dash, underscore only) const VALID_PROFILE_NAME = /^[a-zA-Z0-9_-]+$/; diff --git a/src/utils/websearch/provider-secrets.ts b/src/utils/websearch/provider-secrets.ts index 26ab1a77..8cb55b94 100644 --- a/src/utils/websearch/provider-secrets.ts +++ b/src/utils/websearch/provider-secrets.ts @@ -1,5 +1,5 @@ -import { getGlobalEnvConfig } from '../../config/unified-config-loader'; import { maskSensitiveValue } from '../sensitive-keys'; +import { getGlobalEnvConfig } from '../../config/config-loader-facade'; export type WebSearchApiKeyProviderId = 'exa' | 'tavily' | 'brave'; export type WebSearchApiKeySource = 'global_env' | 'process_env' | 'both' | 'none'; diff --git a/src/utils/websearch/status.ts b/src/utils/websearch/status.ts index 5f496624..1cf9e57b 100644 --- a/src/utils/websearch/status.ts +++ b/src/utils/websearch/status.ts @@ -9,13 +9,14 @@ import { existsSync, readFileSync } from 'fs'; import { join } from 'path'; import { ok, warn, fail, info } from '../ui'; -import { getWebSearchConfig } from '../../config/unified-config-loader'; + import { getCcsDir } from '../config-manager'; import { getGeminiCliStatus, isGeminiAuthenticated } from './gemini-cli'; import { getGrokCliStatus } from './grok-cli'; import { getOpenCodeCliStatus } from './opencode-cli'; import { getWebSearchApiKeyStates } from './provider-secrets'; import { normalizeSearxngBaseUrl, type WebSearchCliInfo, type WebSearchStatus } from './types'; +import { getWebSearchConfig } from '../../config/config-loader-facade'; const PROVIDER_STATE_FILE = 'websearch-provider-state.json'; diff --git a/src/web-server/file-watcher.ts b/src/web-server/file-watcher.ts index 90de9027..5a9b4303 100644 --- a/src/web-server/file-watcher.ts +++ b/src/web-server/file-watcher.ts @@ -7,7 +7,7 @@ import chokidar, { FSWatcher } from 'chokidar'; import * as path from 'path'; -import { getCcsDir } from '../utils/config-manager'; +import { getCcsDir } from '../config/config-loader-facade'; export interface FileChangeEvent { type: 'config-changed' | 'settings-changed' | 'profiles-changed' | 'proxy-status-changed'; diff --git a/src/web-server/health-service.ts b/src/web-server/health-service.ts index c76ae57f..27559cd9 100644 --- a/src/web-server/health-service.ts +++ b/src/web-server/health-service.ts @@ -8,7 +8,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; -import { getCcsDir, getConfigPath } from '../utils/config-manager'; +import { getConfigPath } from '../utils/config-manager'; import packageJson from '../../package.json'; // Import all check functions from modular components @@ -35,6 +35,7 @@ import { checkOAuthPortsForDashboard, checkWebSearchClis, } from './health'; +import { getCcsDir } from '../config/config-loader-facade'; // Re-export types for external consumers export type { HealthCheck, HealthGroup, HealthReport }; @@ -143,10 +144,10 @@ export function fixHealthIssue(checkId: string): { success: boolean; message: st case 'config-file': { // Use appropriate config based on unified mode - const { isUnifiedMode } = require('../config/unified-config-loader'); + const { isUnifiedMode } = require('../config/config-loader-facade'); if (isUnifiedMode()) { - const { mutateUnifiedConfig } = require('../config/unified-config-loader'); - mutateUnifiedConfig(() => {}); + const { mutateConfig } = require('../config/config-loader-facade'); + mutateConfig(() => {}); return { success: true, message: 'Created/updated config.yaml' }; } const configPath = getConfigPath(); @@ -157,7 +158,7 @@ export function fixHealthIssue(checkId: string): { success: boolean; message: st case 'profiles-file': { // Use appropriate storage based on unified mode - const { isUnifiedMode: isUnified } = require('../config/unified-config-loader'); + const { isUnifiedMode: isUnified } = require('../config/config-loader-facade'); if (isUnified()) { // In unified mode, accounts are stored in config.yaml return { success: true, message: 'Accounts stored in config.yaml (unified mode)' }; diff --git a/src/web-server/health/config-checks.ts b/src/web-server/health/config-checks.ts index f8ff910b..eb467034 100644 --- a/src/web-server/health/config-checks.ts +++ b/src/web-server/health/config-checks.ts @@ -7,9 +7,10 @@ import * as fs from 'fs'; import * as path from 'path'; -import { getConfigPath, getCcsDir } from '../../utils/config-manager'; -import { isUnifiedMode, hasUnifiedConfig } from '../../config/unified-config-loader'; +import { getConfigPath } from '../../utils/config-manager'; + import type { HealthCheck } from './types'; +import { getCcsDir, hasUnifiedConfig, isUnifiedMode } from '../../config/config-loader-facade'; /** * Check config file (config.json or config.yaml based on mode) diff --git a/src/web-server/health/profile-checks.ts b/src/web-server/health/profile-checks.ts index 83955611..5e5e6561 100644 --- a/src/web-server/health/profile-checks.ts +++ b/src/web-server/health/profile-checks.ts @@ -7,8 +7,9 @@ import * as fs from 'fs'; import * as path from 'path'; -import { isUnifiedMode, loadUnifiedConfig } from '../../config/unified-config-loader'; + import type { HealthCheck } from './types'; +import { isUnifiedMode, loadUnifiedConfig } from '../../config/config-loader-facade'; /** * Check profiles configuration (API profiles from config.json or config.yaml) diff --git a/src/web-server/middleware/auth-middleware.ts b/src/web-server/middleware/auth-middleware.ts index c3f04f04..4afc4703 100644 --- a/src/web-server/middleware/auth-middleware.ts +++ b/src/web-server/middleware/auth-middleware.ts @@ -6,11 +6,15 @@ import type { NextFunction, Request, Response } from 'express'; import session from 'express-session'; import rateLimit from 'express-rate-limit'; -import { getDashboardAuthConfig, isDashboardAuthEnabled } from '../../config/unified-config-loader'; + import crypto from 'crypto'; import fs from 'fs'; import path from 'path'; -import { getCcsDir } from '../../utils/config-manager'; +import { + getCcsDir, + getDashboardAuthConfig, + isDashboardAuthEnabled, +} from '../../config/config-loader-facade'; // Extend Express Request with session declare module 'express-session' { diff --git a/src/web-server/models-dev/registry-cache.ts b/src/web-server/models-dev/registry-cache.ts index 9b2a0802..650f41b4 100644 --- a/src/web-server/models-dev/registry-cache.ts +++ b/src/web-server/models-dev/registry-cache.ts @@ -1,7 +1,8 @@ import * as fs from 'fs'; import * as path from 'path'; -import { getCcsDir } from '../../utils/config-manager'; + import type { ModelsDevCacheData, ModelsDevProvider, ModelsDevRegistry } from './types'; +import { getCcsDir } from '../../config/config-loader-facade'; export const MODELS_DEV_API_URL = 'https://models.dev/api.json'; diff --git a/src/web-server/overview-routes.ts b/src/web-server/overview-routes.ts index d0c0586f..384f5de7 100644 --- a/src/web-server/overview-routes.ts +++ b/src/web-server/overview-routes.ts @@ -5,11 +5,12 @@ */ import { Router, Request, Response } from 'express'; -import { loadConfigSafe } from '../utils/config-manager'; + import { runHealthChecks } from './health-service'; import { getAllAuthStatus, initializeAccounts } from '../cliproxy/auth/auth-handler'; import { getVersion } from '../utils/version'; import ProfileRegistry from '../auth/profile-registry'; +import { loadConfigSafe } from '../config/config-loader-facade'; export const overviewRoutes = Router(); diff --git a/src/web-server/routes/account-routes.ts b/src/web-server/routes/account-routes.ts index 0ae56c1d..df520087 100644 --- a/src/web-server/routes/account-routes.ts +++ b/src/web-server/routes/account-routes.ts @@ -8,7 +8,7 @@ import { Router, Request, Response } from 'express'; import ProfileRegistry from '../../auth/profile-registry'; import InstanceManager from '../../management/instance-manager'; -import { isUnifiedMode, loadOrCreateUnifiedConfig } from '../../config/unified-config-loader'; + import { getAllAccountsSummary, setDefaultAccount as setCliproxyDefault, @@ -33,6 +33,7 @@ import { } from './account-route-helpers'; import type { AccountConfig } from '../../config/unified-config-types'; import { resolveConfiguredPlainCcsResumeLane } from '../../auth/resume-lane-diagnostics'; +import { isUnifiedMode, loadOrCreateUnifiedConfig } from '../../config/config-loader-facade'; const router = Router(); diff --git a/src/web-server/routes/auth-routes.ts b/src/web-server/routes/auth-routes.ts index 6fcd3e22..2ec20d1e 100644 --- a/src/web-server/routes/auth-routes.ts +++ b/src/web-server/routes/auth-routes.ts @@ -6,9 +6,10 @@ import { Router, type Request, type Response } from 'express'; import bcrypt from 'bcrypt'; import crypto from 'crypto'; -import { getDashboardAuthConfig } from '../../config/unified-config-loader'; + import type { DashboardAuthConfig } from '../../config/unified-config-types'; import { isLoopbackRemoteAddress, loginRateLimiter } from '../middleware/auth-middleware'; +import { getDashboardAuthConfig } from '../../config/config-loader-facade'; /** * Timing-safe string comparison to prevent timing attacks. diff --git a/src/web-server/routes/browser-routes.ts b/src/web-server/routes/browser-routes.ts index f25dcc2f..2e789df8 100644 --- a/src/web-server/routes/browser-routes.ts +++ b/src/web-server/routes/browser-routes.ts @@ -1,9 +1,10 @@ import { Router, type Request, type Response } from 'express'; -import { mutateUnifiedConfig } from '../../config/unified-config-loader'; + import type { BrowserConfig, BrowserEvalMode } from '../../config/unified-config-types'; import { getBrowserStatus } from '../../utils/browser'; import { getUserFacingBrowserConfig } from '../../utils/browser/browser-status'; import { requireLocalAccessWhenAuthDisabled } from '../middleware/auth-middleware'; +import { mutateConfig } from '../../config/config-loader-facade'; const router = Router(); const BROWSER_LOCAL_ACCESS_ERROR = @@ -173,7 +174,7 @@ router.put('/', async (req: Request, res: Response): Promise => { const current = getUserFacingBrowserConfig(); const nextClaudeUserDataDir = claude?.userDataDir === undefined ? current.claude.user_data_dir : claude.userDataDir.trim(); - mutateUnifiedConfig((config) => { + mutateConfig((config) => { config.browser = { claude: { enabled: claude?.enabled ?? current.claude.enabled, diff --git a/src/web-server/routes/channels-routes.ts b/src/web-server/routes/channels-routes.ts index 89a67cef..dc0913ab 100644 --- a/src/web-server/routes/channels-routes.ts +++ b/src/web-server/routes/channels-routes.ts @@ -1,5 +1,5 @@ import { Router, type Request, type Response } from 'express'; -import { getOfficialChannelsConfig, mutateUnifiedConfig } from '../../config/unified-config-loader'; + import { clearConfiguredOfficialChannelTokensEverywhere, getOfficialChannelTokenStatus, @@ -24,6 +24,7 @@ import { isOfficialChannelId, } from '../../channels/official-channels-runtime'; import { requireLocalAccessWhenAuthDisabled } from '../middleware/auth-middleware'; +import { getOfficialChannelsConfig, mutateConfig } from '../../config/config-loader-facade'; const router = Router(); @@ -146,7 +147,7 @@ router.put('/', (req: Request, res: Response): void => { } try { - const updated = mutateUnifiedConfig((config) => { + const updated = mutateConfig((config) => { config.channels = { selected: selected !== undefined ? [...new Set(selected)] : (config.channels?.selected ?? []), diff --git a/src/web-server/routes/cliproxy-auth-routes.ts b/src/web-server/routes/cliproxy-auth-routes.ts index 009ac005..5faae932 100644 --- a/src/web-server/routes/cliproxy-auth-routes.ts +++ b/src/web-server/routes/cliproxy-auth-routes.ts @@ -34,7 +34,7 @@ import { import { fetchRemoteAuthStatus } from '../../cliproxy/services/remote-auth-fetcher'; import { ensureManagedModelPrefixes } from '../../cliproxy/ai-providers/managed-model-prefixes'; import { invalidateQuotaCache } from '../../cliproxy/quota/quota-response-cache'; -import { loadOrCreateUnifiedConfig } from '../../config/unified-config-loader'; + import { tryKiroImport } from '../../cliproxy/auth/kiro-import'; import { type ProviderTokenSnapshot, @@ -65,6 +65,7 @@ import { } from '../../cliproxy/auth/antigravity-responsibility'; import { createRouteErrorHelpers } from './route-helpers'; import { requireLocalAccessWhenAuthDisabled } from '../middleware/auth-middleware'; +import { loadOrCreateUnifiedConfig } from '../../config/config-loader-facade'; const router = Router(); const MANUAL_AUTH_STATE_TTL_MS = 10 * 60 * 1000; diff --git a/src/web-server/routes/cliproxy-local-proxy.ts b/src/web-server/routes/cliproxy-local-proxy.ts index dc55e0fb..80d065d6 100644 --- a/src/web-server/routes/cliproxy-local-proxy.ts +++ b/src/web-server/routes/cliproxy-local-proxy.ts @@ -10,8 +10,9 @@ import http from 'http'; import { Request, Response, Router } from 'express'; import { CLIPROXY_DEFAULT_PORT, validatePort } from '../../cliproxy/config/port-manager'; -import { loadOrCreateUnifiedConfig } from '../../config/unified-config-loader'; + import { requireLocalAccessWhenAuthDisabled } from '../middleware/auth-middleware'; +import { loadOrCreateUnifiedConfig } from '../../config/config-loader-facade'; export interface CliproxyLocalProxyDeps { enforceAccess?: (req: Request, res: Response) => boolean; diff --git a/src/web-server/routes/cliproxy-sync-routes.ts b/src/web-server/routes/cliproxy-sync-routes.ts index d414bbda..37eab52c 100644 --- a/src/web-server/routes/cliproxy-sync-routes.ts +++ b/src/web-server/routes/cliproxy-sync-routes.ts @@ -3,7 +3,7 @@ */ import { Router, Request, Response } from 'express'; -import { mutateUnifiedConfig } from '../../config/unified-config-loader'; + import { generateSyncPayload, generateSyncPreview, @@ -12,6 +12,7 @@ import { syncToLocalConfig, getLocalSyncStatus, } from '../../cliproxy/sync'; +import { mutateConfig } from '../../config/config-loader-facade'; const router = Router(); @@ -130,7 +131,7 @@ router.put('/auto-sync', async (req: Request, res: Response): Promise => { } try { - mutateUnifiedConfig((config) => { + mutateConfig((config) => { if (!config.cliproxy) { throw new Error('CLIProxy config not initialized'); } diff --git a/src/web-server/routes/config-routes.ts b/src/web-server/routes/config-routes.ts index 3cfa87e6..6a48d96f 100644 --- a/src/web-server/routes/config-routes.ts +++ b/src/web-server/routes/config-routes.ts @@ -4,13 +4,7 @@ import { Router, Request, Response } from 'express'; import * as fs from 'fs'; -import { - hasUnifiedConfig, - loadUnifiedConfig, - mutateUnifiedConfig, - getConfigFormat, - getConfigYamlPath, -} from '../../config/unified-config-loader'; + import { needsMigration, migrate, @@ -28,6 +22,13 @@ import { import { DEFAULT_CLIPROXY_SERVER_CONFIG } from '../../config/unified-config-types'; import { requireLocalAccessWhenAuthDisabled } from '../middleware/auth-middleware'; import { isSensitiveKey } from '../../utils/sensitive-keys'; +import { + getConfigFormat, + getConfigYamlPath, + hasUnifiedConfig, + loadUnifiedConfig, + mutateConfig, +} from '../../config/config-loader-facade'; const router = Router(); const LOCAL_CONFIG_ERROR = @@ -652,7 +653,7 @@ router.put('/', (req: Request, res: Response): void => { } try { - mutateUnifiedConfig((currentConfig) => { + mutateConfig((currentConfig) => { if ('setup_completed' in config) { currentConfig.setup_completed = config.setup_completed; } diff --git a/src/web-server/routes/copilot-routes.ts b/src/web-server/routes/copilot-routes.ts index 4c85d284..919e0748 100644 --- a/src/web-server/routes/copilot-routes.ts +++ b/src/web-server/routes/copilot-routes.ts @@ -23,8 +23,9 @@ import { type CopilotNormalizationWarning, } from '../../copilot/copilot-model-normalizer'; import { DEFAULT_COPILOT_CONFIG, type CopilotConfig } from '../../config/unified-config-types'; -import { loadOrCreateUnifiedConfig, mutateUnifiedConfig } from '../../config/unified-config-loader'; + import copilotSettingsRoutes from './copilot-settings-routes'; +import { loadOrCreateUnifiedConfig, mutateConfig } from '../../config/config-loader-facade'; const router = Router(); @@ -211,7 +212,7 @@ router.put('/config', (req: Request, res: Response): void => { let nextCopilotConfig: CopilotConfig = { ...DEFAULT_COPILOT_CONFIG }; let warnings: CopilotNormalizationWarning[] = []; - mutateUnifiedConfig((config) => { + mutateConfig((config) => { const currentConfig = config.copilot ?? DEFAULT_COPILOT_CONFIG; const result = normalizeCopilotConfigWithWarnings({ enabled: diff --git a/src/web-server/routes/copilot-settings-routes.ts b/src/web-server/routes/copilot-settings-routes.ts index 015da32b..54a748e0 100644 --- a/src/web-server/routes/copilot-settings-routes.ts +++ b/src/web-server/routes/copilot-settings-routes.ts @@ -10,8 +10,11 @@ import { normalizeCopilotSettingsWithWarnings, } from '../../copilot/copilot-model-normalizer'; import { DEFAULT_COPILOT_CONFIG, type CopilotConfig } from '../../config/unified-config-types'; -import { loadOrCreateUnifiedConfig, mutateUnifiedConfig } from '../../config/unified-config-loader'; -import { getCcsDir } from '../../utils/config-manager'; +import { + getCcsDir, + loadOrCreateUnifiedConfig, + mutateConfig, +} from '../../config/config-loader-facade'; const router = Router(); @@ -150,7 +153,7 @@ router.put('/raw', (req: Request, res: Response): void => { ); try { - mutateUnifiedConfig((config) => { + mutateConfig((config) => { config.copilot = settingsResult.effectiveConfig; }); } catch (error) { diff --git a/src/web-server/routes/cursor-routes.ts b/src/web-server/routes/cursor-routes.ts index defcc96e..220dae9a 100644 --- a/src/web-server/routes/cursor-routes.ts +++ b/src/web-server/routes/cursor-routes.ts @@ -15,8 +15,9 @@ import { saveCredentials, validateToken, } from '../../cursor'; -import { getCursorConfig } from '../../config/unified-config-loader'; + import cursorSettingsRoutes from './cursor-settings-routes'; +import { getCursorConfig } from '../../config/config-loader-facade'; const router = Router(); diff --git a/src/web-server/routes/cursor-settings-routes.ts b/src/web-server/routes/cursor-settings-routes.ts index 56c9dcc1..42c7105a 100644 --- a/src/web-server/routes/cursor-settings-routes.ts +++ b/src/web-server/routes/cursor-settings-routes.ts @@ -7,10 +7,11 @@ import { Router } from 'express'; import * as fs from 'fs'; import { promises as fsp } from 'fs'; import * as path from 'path'; -import { getCcsDir } from '../../utils/config-manager'; + import { DEFAULT_CURSOR_CONFIG } from '../../config/unified-config-types'; -import { mutateUnifiedConfig, getCursorConfig } from '../../config/unified-config-loader'; + import type { CursorConfig } from '../../config/unified-config-types'; +import { getCcsDir, getCursorConfig, mutateConfig } from '../../config/config-loader-facade'; const router = Router(); @@ -181,7 +182,7 @@ router.put('/', async (req: Request, res: Response): Promise => { } const normalizedModel = parseRequiredModel(updates.model); - const config = mutateUnifiedConfig((currentConfig) => { + const config = mutateConfig((currentConfig) => { currentConfig.cursor = { enabled: updates.enabled ?? currentConfig.cursor?.enabled ?? DEFAULT_CURSOR_CONFIG.enabled, port: updates.port ?? currentConfig.cursor?.port ?? DEFAULT_CURSOR_CONFIG.port, @@ -294,7 +295,7 @@ router.put('/raw', (req: Request, res: Response): void => { // Keep unified config aligned with raw settings edits (parity with Copilot raw editor). const parsedPort = parseLocalCursorPort(settings); const env = (settings as { env?: Record }).env ?? {}; - mutateUnifiedConfig((config) => { + mutateConfig((config) => { const model = parseRequiredModel(env.ANTHROPIC_MODEL) ?? config.cursor?.model; config.cursor = { diff --git a/src/web-server/routes/image-analysis-routes.ts b/src/web-server/routes/image-analysis-routes.ts index 22f21c47..25ec7fc9 100644 --- a/src/web-server/routes/image-analysis-routes.ts +++ b/src/web-server/routes/image-analysis-routes.ts @@ -1,6 +1,6 @@ import { Router, type Request, type Response } from 'express'; import * as fs from 'fs'; -import { getImageAnalysisConfig, mutateUnifiedConfig } from '../../config/unified-config-loader'; + import { CLIPROXY_PROVIDER_IDS, getProviderDisplayName, @@ -10,7 +10,7 @@ import type { CLIProxyProvider } from '../../cliproxy/types'; import { listApiProfiles, resolveCliproxyBridgeMetadata } from '../../api/services'; import { requireLocalAccessWhenAuthDisabled } from '../middleware/auth-middleware'; import { expandPath } from '../../utils/helpers'; -import { loadSettings } from '../../utils/config-manager'; + import type { Settings } from '../../types/config'; import { extractProviderFromPathname } from '../../cliproxy/ai-providers/model-id-normalizer'; import { @@ -23,6 +23,11 @@ import { hasImageAnalysisMcpReady, repairImageAnalysisRuntimeState, } from '../../utils/image-analysis'; +import { + getImageAnalysisConfig, + loadSettings, + mutateConfig, +} from '../../config/config-loader-facade'; const router = Router(); const IMAGE_ANALYSIS_LOCAL_ACCESS_ERROR = @@ -448,7 +453,7 @@ router.put('/', async (req: Request, res: Response): Promise => { nextProfileBackends[trimmedProfileName] = normalizedBackend; } - mutateUnifiedConfig((config) => { + mutateConfig((config) => { config.image_analysis = { enabled: body.enabled ?? currentConfig.enabled, timeout: body.timeout ?? currentConfig.timeout, diff --git a/src/web-server/routes/misc-routes.ts b/src/web-server/routes/misc-routes.ts index ce95c457..39a96a94 100644 --- a/src/web-server/routes/misc-routes.ts +++ b/src/web-server/routes/misc-routes.ts @@ -5,14 +5,9 @@ import { Router, Request, Response } from 'express'; import * as fs from 'fs'; import * as path from 'path'; -import { getCcsDir } from '../../utils/config-manager'; + import { expandPath } from '../../utils/helpers'; -import { - mutateUnifiedConfig, - getGlobalEnvConfig, - getThinkingConfig, - getConfigYamlPath, -} from '../../config/unified-config-loader'; + import type { ThinkingConfig } from '../../config/unified-config-types'; import { THINKING_BUDGET_MIN, @@ -23,6 +18,13 @@ import { } from '../../cliproxy'; import { validateFilePath } from './route-helpers'; import { requireLocalAccessWhenAuthDisabled } from '../middleware/auth-middleware'; +import { + getCcsDir, + getConfigYamlPath, + getGlobalEnvConfig, + getThinkingConfig, + mutateConfig, +} from '../../config/config-loader-facade'; const router = Router(); @@ -244,7 +246,7 @@ router.put('/global-env', (req: Request, res: Response): void => { try { // Atomic read-modify-write — avoids race between load and save - const updated = mutateUnifiedConfig((config) => { + const updated = mutateConfig((config) => { config.global_env = { enabled: enabled ?? config.global_env?.enabled ?? true, env: env ?? config.global_env?.env ?? {}, @@ -445,7 +447,7 @@ router.put('/thinking', (req: Request, res: Response): void => { Object.keys(sanitizedOverrides).length > 0 ? sanitizedOverrides : undefined; } - const config = mutateUnifiedConfig((currentConfig) => { + const config = mutateConfig((currentConfig) => { currentConfig.thinking = { mode: updates.mode ?? currentConfig.thinking?.mode ?? 'auto', override: shouldClearOverride diff --git a/src/web-server/routes/proxy-routes.ts b/src/web-server/routes/proxy-routes.ts index 22100e42..e25b440b 100644 --- a/src/web-server/routes/proxy-routes.ts +++ b/src/web-server/routes/proxy-routes.ts @@ -8,7 +8,7 @@ */ import { Router, Request, Response } from 'express'; -import { loadOrCreateUnifiedConfig, mutateUnifiedConfig } from '../../config/unified-config-loader'; + import { testConnection } from '../../cliproxy/services/remote-proxy-client'; import { isProxyRunning } from '../../cliproxy/services/proxy-lifecycle-service'; import { DEFAULT_BACKEND } from '../../cliproxy/binary/platform-detector'; @@ -18,6 +18,7 @@ import { } from '../../config/unified-config-types'; import { CLIPROXY_PROVIDER_IDS } from '../../cliproxy/provider-capabilities'; import { requireLocalAccessWhenAuthDisabled } from '../middleware/auth-middleware'; +import { loadOrCreateUnifiedConfig, mutateConfig } from '../../config/config-loader-facade'; const router = Router(); @@ -54,7 +55,7 @@ router.put('/', (req: Request, res: Response) => { const updates = req.body as Partial; // Atomic read-modify-write — avoids race between load and save - const updated = mutateUnifiedConfig((config) => { + const updated = mutateConfig((config) => { config.cliproxy_server = { remote: { ...DEFAULT_CLIPROXY_SERVER_CONFIG.remote, @@ -125,7 +126,7 @@ router.put('/backend', (req: Request, res: Response) => { } // Atomic write — avoids race between load and save - mutateUnifiedConfig((config) => { + mutateConfig((config) => { if (!config.cliproxy) { config.cliproxy = { backend, diff --git a/src/web-server/routes/route-helpers.ts b/src/web-server/routes/route-helpers.ts index 3251a064..827fffee 100644 --- a/src/web-server/routes/route-helpers.ts +++ b/src/web-server/routes/route-helpers.ts @@ -5,7 +5,7 @@ import * as fs from 'fs'; import * as path from 'path'; import type { Response } from 'express'; -import { getCcsDir, getConfigPath, loadConfigSafe, loadSettings } from '../../utils/config-manager'; +import { getConfigPath } from '../../utils/config-manager'; import { expandPath } from '../../utils/helpers'; import { getClaudeSettingsPath } from '../../utils/claude-config-path'; import { resolveDroidProvider } from '../../targets/droid-provider'; @@ -20,6 +20,7 @@ import type { Config, Settings } from '../../types/config'; import type { TargetType } from '../../targets/target-adapter'; import { isPersistedTargetType } from '../../targets/target-metadata'; import { ValidationError } from '../../errors/error-types'; +import { getCcsDir, loadConfigSafe, loadSettings } from '../../config/config-loader-facade'; /** Model mapping for API profiles */ export interface ModelMapping { diff --git a/src/web-server/routes/settings-routes.ts b/src/web-server/routes/settings-routes.ts index 0bed44be..2faa3f4c 100644 --- a/src/web-server/routes/settings-routes.ts +++ b/src/web-server/routes/settings-routes.ts @@ -6,7 +6,7 @@ import { Router, Request, Response } from 'express'; import * as fs from 'fs'; import * as path from 'path'; import * as lockfile from 'proper-lockfile'; -import { getCcsDir, loadConfigSafe, loadSettings } from '../../utils/config-manager'; + import { isSensitiveKey, maskSensitiveValue } from '../../utils/sensitive-keys'; import { listVariants } from '../../cliproxy/services/variant-service'; import { @@ -21,11 +21,7 @@ import { regenerateConfig } from '../../cliproxy/config/config-generator'; import { deduplicateCcsHooks } from '../../utils/websearch/hook-utils'; import { removeCcsImageAnalyzerHooks } from '../../utils/hooks/image-analyzer-hook-utils'; import { resolveCliproxyBridgeMetadata } from '../../api/services'; -import { - getImageAnalysisConfig, - loadOrCreateUnifiedConfig, - mutateUnifiedConfig, -} from '../../config/unified-config-loader'; + import { requireLocalAccessWhenAuthDisabled } from '../middleware/auth-middleware'; import type { Settings } from '../../types/config'; import type { CLIProxyProvider } from '../../cliproxy/types'; @@ -44,6 +40,14 @@ import { } from '../../utils/hooks/image-analyzer-profile-hook-injector'; import { hasImageAnalyzerHook } from '../../utils/hooks/image-analyzer-hook-installer'; import { resolveImageAnalysisRuntimeStatus } from '../../utils/hooks'; +import { + getCcsDir, + getImageAnalysisConfig, + loadConfigSafe, + loadOrCreateUnifiedConfig, + loadSettings, + mutateConfig, +} from '../../config/config-loader-facade'; const router = Router(); const MODEL_ENV_KEYS = [ @@ -765,7 +769,7 @@ router.put('/auth/antigravity-risk', (req: Request, res: Response): void => { return; } - const updatedConfig = mutateUnifiedConfig((config) => { + const updatedConfig = mutateConfig((config) => { config.cliproxy.safety = { ...(config.cliproxy.safety ?? {}), antigravity_ack_bypass: antigravityAckBypass, diff --git a/src/web-server/routes/websearch-routes.ts b/src/web-server/routes/websearch-routes.ts index 22f88100..4b2220ca 100644 --- a/src/web-server/routes/websearch-routes.ts +++ b/src/web-server/routes/websearch-routes.ts @@ -3,7 +3,7 @@ */ import { Router, Request, Response } from 'express'; -import { mutateUnifiedConfig, getWebSearchConfig } from '../../config/unified-config-loader'; + import type { WebSearchConfig } from '../../config/unified-config-types'; import { getWebSearchReadiness, getWebSearchCliProviders } from '../../utils/websearch-manager'; import { @@ -14,6 +14,7 @@ import { } from '../../utils/websearch/provider-secrets'; import { normalizeSearxngBaseUrl } from '../../utils/websearch/types'; import { requireLocalAccessWhenAuthDisabled } from '../middleware/auth-middleware'; +import { getWebSearchConfig, mutateConfig } from '../../config/config-loader-facade'; const router = Router(); const WEBSEARCH_LOCAL_ACCESS_ERROR = @@ -143,7 +144,7 @@ router.put('/', (req: Request, res: Response): void => { } try { - mutateUnifiedConfig((config) => { + mutateConfig((config) => { const existingSearxngUrl = normalizeSearxngBaseUrl(config.websearch?.providers?.searxng?.url) ?? ''; diff --git a/src/web-server/services/claude-extension-binding-service.ts b/src/web-server/services/claude-extension-binding-service.ts index ded0d77d..5d969b2e 100644 --- a/src/web-server/services/claude-extension-binding-service.ts +++ b/src/web-server/services/claude-extension-binding-service.ts @@ -4,7 +4,7 @@ import * as path from 'path'; import ProfileDetector from '../../auth/profile-detector'; import type { ClaudeExtensionHost } from '../../shared/claude-extension-hosts'; import { expandPath } from '../../utils/helpers'; -import { getCcsDir } from '../../utils/config-manager'; +import { getCcsDir } from '../../config/config-loader-facade'; export interface ClaudeExtensionBinding { id: string; diff --git a/src/web-server/services/logs-dashboard-service.ts b/src/web-server/services/logs-dashboard-service.ts index 58c6a84c..c50c87c7 100644 --- a/src/web-server/services/logs-dashboard-service.ts +++ b/src/web-server/services/logs-dashboard-service.ts @@ -1,4 +1,3 @@ -import { mutateUnifiedConfig } from '../../config/unified-config-loader'; import { getResolvedLoggingConfig, invalidateLoggingConfigCache, @@ -7,13 +6,14 @@ import { } from '../../services/logging'; import type { LoggingConfig } from '../../config/unified-config-types'; import type { ReadLogEntriesOptions } from '../../services/logging'; +import { mutateConfig } from '../../config/config-loader-facade'; export function getDashboardLoggingConfig(): LoggingConfig { return getResolvedLoggingConfig(); } export function updateDashboardLoggingConfig(updates: Partial): LoggingConfig { - const updated = mutateUnifiedConfig((config) => { + const updated = mutateConfig((config) => { config.logging = { ...getResolvedLoggingConfig(), ...config.logging, diff --git a/src/web-server/shared-routes.ts b/src/web-server/shared-routes.ts index ade2e0c3..05830d71 100644 --- a/src/web-server/shared-routes.ts +++ b/src/web-server/shared-routes.ts @@ -8,9 +8,10 @@ import { Router, Request, Response } from 'express'; import * as fs from 'fs'; import * as path from 'path'; import * as yaml from 'js-yaml'; -import { getCcsDir } from '../utils/config-manager'; + import { getClaudeConfigDir } from '../utils/claude-config-path'; import { requireLocalAccessWhenAuthDisabled } from './middleware/auth-middleware'; +import { getCcsDir } from '../config/config-loader-facade'; export const sharedRoutes = Router(); diff --git a/src/web-server/usage/aggregator.ts b/src/web-server/usage/aggregator.ts index 129f2d73..537da727 100644 --- a/src/web-server/usage/aggregator.ts +++ b/src/web-server/usage/aggregator.ts @@ -24,7 +24,7 @@ import { getCacheAge, } from './disk-cache'; import { ok, info, fail } from '../../utils/ui'; -import { getCcsDir } from '../../utils/config-manager'; + import { getClaudeConfigDir, getDefaultClaudeConfigDir } from '../../utils/claude-config-path'; import { loadCachedCliproxyData, @@ -40,6 +40,7 @@ import { getModelsUsed, getProviderModelKey, } from './model-identity'; +import { getCcsDir } from '../../config/config-loader-facade'; // ============================================================================ // Multi-Instance Support - Aggregate usage from CCS profiles diff --git a/src/web-server/usage/cliproxy-usage-syncer.ts b/src/web-server/usage/cliproxy-usage-syncer.ts index 6ab48cc7..83d15a69 100644 --- a/src/web-server/usage/cliproxy-usage-syncer.ts +++ b/src/web-server/usage/cliproxy-usage-syncer.ts @@ -19,8 +19,9 @@ import { type CliproxyUsageHistoryDetail, } from './cliproxy-usage-transformer'; import type { DailyUsage, HourlyUsage, MonthlyUsage } from './types'; -import { getCcsDir } from '../../utils/config-manager'; + import { ok, info, warn } from '../../utils/ui'; +import { getCcsDir } from '../../config/config-loader-facade'; interface CliproxyUsageSnapshot { version: number; diff --git a/src/web-server/usage/disk-cache.ts b/src/web-server/usage/disk-cache.ts index a2bc1e86..5edfdf7d 100644 --- a/src/web-server/usage/disk-cache.ts +++ b/src/web-server/usage/disk-cache.ts @@ -12,7 +12,7 @@ import * as fs from 'fs'; import * as path from 'path'; import type { DailyUsage, HourlyUsage, MonthlyUsage, SessionUsage } from './types'; import { ok, info, warn } from '../../utils/ui'; -import { getCcsDir } from '../../utils/config-manager'; +import { getCcsDir } from '../../config/config-loader-facade'; // Cache configuration function getCacheDir() { diff --git a/tests/unit/utils/browser/browser-setup.test.ts b/tests/unit/utils/browser/browser-setup.test.ts index fd180579..755dc8d7 100644 --- a/tests/unit/utils/browser/browser-setup.test.ts +++ b/tests/unit/utils/browser/browser-setup.test.ts @@ -111,7 +111,7 @@ describe('browser setup', () => { const deps: BrowserSetupDeps = { getBrowserConfig: () => config.browser, - mutateUnifiedConfig: (mutator) => { + mutateConfig: (mutator) => { mutator(config); return config; }, @@ -166,7 +166,7 @@ describe('browser setup', () => { const deps: BrowserSetupDeps = { getBrowserConfig: () => config.browser, - mutateUnifiedConfig: (mutator) => { + mutateConfig: (mutator) => { mutator(config); return config; },