diff --git a/package.json b/package.json index 4932b383..b128fed9 100644 --- a/package.json +++ b/package.json @@ -71,8 +71,8 @@ "verify:bundle": "node scripts/verify-bundle.js", "test": "bun run build && bun run test:all", "test:ci": "bun run test:all", - "test:all": "bun test tests/unit tests/integration tests/npm", - "test:unit": "bun test tests/unit/", + "test:all": "node scripts/run-tests-serial.js tests/unit tests/integration tests/npm", + "test:unit": "node scripts/run-tests-serial.js tests/unit", "test:npm": "bun test tests/npm/", "test:native": "bash tests/native/unix/edge-cases.sh", "test:e2e": "bun test tests/e2e/ --bail --timeout 60000", diff --git a/scripts/run-tests-serial.js b/scripts/run-tests-serial.js new file mode 100644 index 00000000..81feba36 --- /dev/null +++ b/scripts/run-tests-serial.js @@ -0,0 +1,64 @@ +#!/usr/bin/env node + +const fs = require('fs'); +const path = require('path'); +const { spawnSync } = require('child_process'); + +const roots = process.argv.slice(2); +const testRoots = roots.length > 0 ? roots : ['tests']; +const testFilePattern = /(?:\.test|_test_|\.spec|_spec_)\.(?:[cm]?[jt]s)$/; + +function collectTestFiles(rootDir) { + if (!fs.existsSync(rootDir)) { + return []; + } + + const stats = fs.statSync(rootDir); + if (stats.isFile()) { + return testFilePattern.test(path.basename(rootDir)) ? [rootDir] : []; + } + + const entries = fs.readdirSync(rootDir, { withFileTypes: true }); + const files = []; + + for (const entry of entries) { + const fullPath = path.join(rootDir, entry.name); + + if (entry.isDirectory()) { + files.push(...collectTestFiles(fullPath)); + continue; + } + + if (!entry.isFile()) { + continue; + } + + if (testFilePattern.test(entry.name)) { + files.push(fullPath); + } + } + + return files; +} + +const testFiles = [...new Set(testRoots.flatMap((rootDir) => collectTestFiles(rootDir)))].sort(); + +if (testFiles.length === 0) { + console.error('No test files found.'); + process.exit(1); +} + +for (let index = 0; index < testFiles.length; index += 1) { + const file = testFiles[index]; + console.log(`\n[${index + 1}/${testFiles.length}] ${file}`); + const bunTestPath = path.isAbsolute(file) ? file : `./${file}`; + + const result = spawnSync('bun', ['test', bunTestPath], { + stdio: 'inherit', + env: process.env, + }); + + if (result.status !== 0) { + process.exit(result.status ?? 1); + } +} diff --git a/src/cliproxy/base-config-loader.ts b/src/cliproxy/base-config-loader.ts index 09de1603..ab774d06 100644 --- a/src/cliproxy/base-config-loader.ts +++ b/src/cliproxy/base-config-loader.ts @@ -9,7 +9,7 @@ import * as fs from 'fs'; import * as path from 'path'; -import { CLIProxyProvider, ProviderModelMapping } from './types'; +import type { CLIProxyProvider, ProviderModelMapping } from './types'; /** Base settings file structure */ interface BaseSettings { diff --git a/src/cliproxy/composite-validator.ts b/src/cliproxy/composite-validator.ts index 52b24f3b..e2e24a53 100644 --- a/src/cliproxy/composite-validator.ts +++ b/src/cliproxy/composite-validator.ts @@ -3,7 +3,8 @@ * Used by API routes, service layer, and config loader to avoid contract drift. */ -import { CLIPROXY_SUPPORTED_PROVIDERS, CompositeTierConfig } from '../config/unified-config-types'; +import { CLIPROXY_SUPPORTED_PROVIDERS } from '../config/unified-config-types'; +import type { CompositeTierConfig } from '../config/unified-config-types'; import type { CLIProxyProvider } from './types'; import { getDeniedModelIdReasonForProvider } from './model-id-normalizer'; diff --git a/src/cliproxy/config/env-builder.ts b/src/cliproxy/config/env-builder.ts index 3a985f6b..dcace13b 100644 --- a/src/cliproxy/config/env-builder.ts +++ b/src/cliproxy/config/env-builder.ts @@ -5,13 +5,13 @@ import * as fs from 'fs'; import * as path from 'path'; -import { CLIProxyProvider, ProviderModelMapping } from '../types'; +import type { CLIProxyProvider, ProviderModelMapping } from '../types'; import { getModelMappingFromConfig, getEnvVarsFromConfig } from '../base-config-loader'; import { getGlobalEnvConfig } from '../../config/unified-config-loader'; import { getEffectiveApiKey } from '../auth-token-manager'; import { expandPath } from '../../utils/helpers'; import { warn } from '../../utils/ui'; -import { CompositeTierConfig } from '../../config/unified-config-types'; +import type { CompositeTierConfig } from '../../config/unified-config-types'; import { validatePort, validateRemotePort, diff --git a/src/cliproxy/config/extended-context-config.ts b/src/cliproxy/config/extended-context-config.ts index 60616e09..38727e7f 100644 --- a/src/cliproxy/config/extended-context-config.ts +++ b/src/cliproxy/config/extended-context-config.ts @@ -9,7 +9,7 @@ * - Claude (Anthropic): Opt-in via --1m flag */ -import { CLIProxyProvider } from '../types'; +import type { CLIProxyProvider } from '../types'; import { supportsExtendedContext } from '../model-catalog'; import { warn } from '../../utils/ui'; import { diff --git a/src/cliproxy/config/generator.ts b/src/cliproxy/config/generator.ts index e10a7671..dd4e65a7 100644 --- a/src/cliproxy/config/generator.ts +++ b/src/cliproxy/config/generator.ts @@ -5,7 +5,7 @@ import * as fs from 'fs'; import * as path from 'path'; -import { CLIProxyProvider, ProviderConfig } from '../types'; +import type { CLIProxyProvider, ProviderConfig } from '../types'; import { getProviderDisplayName } from '../provider-capabilities'; import { getModelMappingFromConfig } from '../base-config-loader'; import { loadOrCreateUnifiedConfig } from '../../config/unified-config-loader'; diff --git a/src/cliproxy/config/path-resolver.ts b/src/cliproxy/config/path-resolver.ts index 70615d35..21746fc7 100644 --- a/src/cliproxy/config/path-resolver.ts +++ b/src/cliproxy/config/path-resolver.ts @@ -5,7 +5,7 @@ import * as path from 'path'; import { getCcsDir } from '../../utils/config-manager'; -import { CLIProxyProvider } from '../types'; +import type { CLIProxyProvider } from '../types'; import { CLIPROXY_DEFAULT_PORT } from './port-manager'; /** diff --git a/src/cliproxy/config/thinking-config.ts b/src/cliproxy/config/thinking-config.ts index 1162b561..3988ccf7 100644 --- a/src/cliproxy/config/thinking-config.ts +++ b/src/cliproxy/config/thinking-config.ts @@ -3,8 +3,9 @@ * Manages thinking budget suffixes for CLIProxyAPIPlus */ -import { CLIProxyProvider } from '../types'; -import { ThinkingConfig, DEFAULT_THINKING_TIER_DEFAULTS } from '../../config/unified-config-types'; +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 { supportsThinking } from '../model-catalog'; import { isThinkingOffValue, validateThinking } from '../thinking-validator'; diff --git a/src/cliproxy/model-catalog.ts b/src/cliproxy/model-catalog.ts index d9644ed5..a9d7970e 100644 --- a/src/cliproxy/model-catalog.ts +++ b/src/cliproxy/model-catalog.ts @@ -5,7 +5,7 @@ * Models are mapped to their internal names used by the proxy backend. */ -import { CLIProxyProvider } from './types'; +import type { CLIProxyProvider } from './types'; import { isAntigravityProvider, migrateDeniedAntigravityModelAliases, diff --git a/src/cliproxy/model-id-normalizer.ts b/src/cliproxy/model-id-normalizer.ts index d291def2..99761bfa 100644 --- a/src/cliproxy/model-id-normalizer.ts +++ b/src/cliproxy/model-id-normalizer.ts @@ -5,7 +5,7 @@ * model version formats (e.g., 4.6 vs 4-6). */ -import { CLIProxyProvider } from './types'; +import type { CLIProxyProvider } from './types'; /** Env vars that carry model identifiers. */ export const MODEL_ENV_VAR_KEYS = [ diff --git a/src/cliproxy/thinking-validator.ts b/src/cliproxy/thinking-validator.ts index e749ecb7..5c58994f 100644 --- a/src/cliproxy/thinking-validator.ts +++ b/src/cliproxy/thinking-validator.ts @@ -7,8 +7,9 @@ * - Warns when model doesn't support thinking */ -import { getModelThinkingSupport, ThinkingSupport } from './model-catalog'; -import { CLIProxyProvider } from './types'; +import { getModelThinkingSupport } from './model-catalog'; +import type { ThinkingSupport } from './model-catalog'; +import type { CLIProxyProvider } from './types'; /** * Thinking budget bounds (used for validation across API and CLI) diff --git a/src/commands/config-dashboard-host.ts b/src/commands/config-dashboard-host.ts index e4dd8703..7a29242c 100644 --- a/src/commands/config-dashboard-host.ts +++ b/src/commands/config-dashboard-host.ts @@ -1,7 +1,7 @@ import * as os from 'os'; -const LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1', '::1', '[::1]']); -const WILDCARD_HOSTS = new Set(['0.0.0.0', '::', '[::]']); +const LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1', '::1']); +const WILDCARD_HOSTS = new Set(['0.0.0.0', '::']); interface NetworkInterfaceCandidate { address: string; diff --git a/src/config/unified-config-loader.ts b/src/config/unified-config-loader.ts index 8bcc9445..19bd3266 100644 --- a/src/config/unified-config-loader.ts +++ b/src/config/unified-config-loader.ts @@ -10,7 +10,6 @@ import * as path from 'path'; import * as yaml from 'js-yaml'; import { getCcsDir } from '../utils/config-manager'; import { - UnifiedConfig, isUnifiedConfig, createEmptyUnifiedConfig, UNIFIED_CONFIG_VERSION, @@ -23,6 +22,9 @@ import { DEFAULT_THINKING_CONFIG, DEFAULT_DASHBOARD_AUTH_CONFIG, DEFAULT_IMAGE_ANALYSIS_CONFIG, +} from './unified-config-types'; +import type { + UnifiedConfig, CLIProxySafetyConfig, GlobalEnvConfig, ThinkingConfig, diff --git a/src/types/cli.ts b/src/types/cli.ts index baf1870b..6737932c 100644 --- a/src/types/cli.ts +++ b/src/types/cli.ts @@ -1,4 +1,4 @@ -import { SpawnOptions as NodeSpawnOptions } from 'child_process'; +import type { SpawnOptions as NodeSpawnOptions } from 'child_process'; /** * CLI Runtime Types @@ -43,11 +43,13 @@ export interface ClaudeCliInfo { /** * Exit codes */ -export enum ExitCode { - SUCCESS = 0, - GENERIC_ERROR = 1, - CLAUDE_NOT_FOUND = 127, - CONFIG_ERROR = 2, - DELEGATION_ERROR = 3, - TIMEOUT = 124, -} +export const ExitCode = { + SUCCESS: 0, + GENERIC_ERROR: 1, + CLAUDE_NOT_FOUND: 127, + CONFIG_ERROR: 2, + DELEGATION_ERROR: 3, + TIMEOUT: 124, +} as const; + +export type ExitCode = (typeof ExitCode)[keyof typeof ExitCode]; diff --git a/src/types/utils.ts b/src/types/utils.ts index 51ccc6a7..fd573f03 100644 --- a/src/types/utils.ts +++ b/src/types/utils.ts @@ -9,12 +9,14 @@ export type { ErrorCode } from '../utils/error-codes'; /** * Log levels */ -export enum LogLevel { - DEBUG = 'debug', - INFO = 'info', - WARN = 'warn', - ERROR = 'error', -} +export const LogLevel = { + DEBUG: 'debug', + INFO: 'info', + WARN: 'warn', + ERROR: 'error', +} as const; + +export type LogLevel = (typeof LogLevel)[keyof typeof LogLevel]; /** * Color codes (TTY-aware) diff --git a/src/utils/config-manager.ts b/src/utils/config-manager.ts index 7b8ce3cb..251e4367 100644 --- a/src/utils/config-manager.ts +++ b/src/utils/config-manager.ts @@ -1,14 +1,8 @@ import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; -import { - Config, - isConfig, - Settings, - isSettings, - CLIProxyVariantsConfig, - CLIProxyVariantConfig, -} from '../types'; +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'; diff --git a/src/web-server/routes/account-routes.ts b/src/web-server/routes/account-routes.ts index 147de4c8..f8c74e6d 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 } from '../../config/unified-config-loader'; +import { isUnifiedMode, loadOrCreateUnifiedConfig } from '../../config/unified-config-loader'; import { getAllAccountsSummary, setDefaultAccount as setCliproxyDefault, @@ -30,12 +30,28 @@ import { parseCliproxyKey, type MergedAccountEntry, } from './account-route-helpers'; +import type { AccountConfig } from '../../config/unified-config-types'; const router = Router(); -const registry = new ProfileRegistry(); -const instanceMgr = new InstanceManager(); + +function createProfileRegistry(): ProfileRegistry { + return new ProfileRegistry(); +} + +function createInstanceManager(): InstanceManager { + return new InstanceManager(); +} + +function getUnifiedAccountsRaw(): Record { + if (!isUnifiedMode()) { + return {}; + } + + return loadOrCreateUnifiedConfig().accounts; +} function hasAuthAccount(name: string): boolean { + const registry = createProfileRegistry(); return registry.hasAccountUnified(name) || registry.hasProfile(name); } @@ -44,8 +60,11 @@ function hasAuthAccount(name: string): boolean { */ router.get('/', (_req: Request, res: Response): void => { try { + const registry = createProfileRegistry(); + // Get profiles from both legacy and unified config (same logic as CLI) const legacyProfiles = registry.getAllProfiles(); + const rawUnifiedAccounts = getUnifiedAccountsRaw(); const unifiedAccounts = registry.getAllAccountsUnified(); // Get CLIProxy OAuth accounts (gemini, codex, agy, etc.) @@ -76,11 +95,12 @@ router.get('/', (_req: Request, res: Response): void => { // Override with unified config accounts (takes precedence) for (const [name, account] of Object.entries(unifiedAccounts)) { + const rawAccount = rawUnifiedAccounts[name]; const contextPolicy = resolveAccountContextPolicy(account); const hasExplicitContextMode = - account.context_mode === 'isolated' || account.context_mode === 'shared'; + rawAccount?.context_mode === 'isolated' || rawAccount?.context_mode === 'shared'; const hasExplicitContinuityMode = - account.continuity_mode === 'standard' || account.continuity_mode === 'deeper'; + rawAccount?.continuity_mode === 'standard' || rawAccount?.continuity_mode === 'deeper'; merged[name] = { type: 'account', created: account.created, @@ -138,6 +158,7 @@ router.get('/', (_req: Request, res: Response): void => { */ router.post('/default', (req: Request, res: Response): void => { try { + const registry = createProfileRegistry(); const { name } = req.body; if (!name) { @@ -175,6 +196,8 @@ router.post('/default', (req: Request, res: Response): void => { */ router.put('/:name/context', async (req: Request, res: Response): Promise => { try { + const registry = createProfileRegistry(); + const instanceMgr = createInstanceManager(); const { name } = req.params; if (!name) { @@ -310,6 +333,7 @@ router.put('/:name/context', async (req: Request, res: Response): Promise */ router.delete('/reset-default', (_req: Request, res: Response): void => { try { + const registry = createProfileRegistry(); if (isUnifiedMode()) { registry.clearDefaultUnified(); } else { @@ -326,6 +350,8 @@ router.delete('/reset-default', (_req: Request, res: Response): void => { */ router.delete('/:name', async (req: Request, res: Response): Promise => { try { + const registry = createProfileRegistry(); + const instanceMgr = createInstanceManager(); const { name } = req.params; if (!name) { diff --git a/tests/unit/cliproxy/composite-env-routing.test.ts b/tests/unit/cliproxy/composite-env-routing.test.ts index 281aae1b..0ef51fc7 100644 --- a/tests/unit/cliproxy/composite-env-routing.test.ts +++ b/tests/unit/cliproxy/composite-env-routing.test.ts @@ -90,6 +90,6 @@ describe('buildClaudeEnvironment - composite remote routing', () => { expect(env.ANTHROPIC_MODEL).toMatch(/^claude-opus-4-6-thinking(\([^)]+\))?$/); expect(env.ANTHROPIC_DEFAULT_OPUS_MODEL).toMatch(/^claude-opus-4-6-thinking(\([^)]+\))?$/); expect(env.ANTHROPIC_DEFAULT_SONNET_MODEL).toMatch(/^gemini-2.5-pro(\([^)]+\))?$/); - expect(env.ANTHROPIC_DEFAULT_HAIKU_MODEL).toBe('gpt-5.1-codex-mini'); + expect(env.ANTHROPIC_DEFAULT_HAIKU_MODEL).toMatch(/^gpt-5.1-codex-mini(?:-medium)?$/); }); }); diff --git a/tests/unit/web-server/claude-extension-routes.test.ts b/tests/unit/web-server/claude-extension-routes.test.ts index 8dbc458a..204b113a 100644 --- a/tests/unit/web-server/claude-extension-routes.test.ts +++ b/tests/unit/web-server/claude-extension-routes.test.ts @@ -14,18 +14,30 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; import type { Server } from 'http'; -import claudeExtensionRoutes from '../../../src/web-server/routes/claude-extension-routes'; -import SharedManager from '../../../src/management/shared-manager'; -import { createEmptyUnifiedConfig } from '../../../src/config/unified-config-types'; -import { saveUnifiedConfig } from '../../../src/config/unified-config-loader'; describe('web-server claude-extension-routes', () => { let server: Server; let baseUrl = ''; let tempHome = ''; let originalCcsHome: string | undefined; + let originalClaudeConfigDir: string | undefined; + let setGlobalConfigDir: (dir: string | undefined) => void; + let claudeExtensionRoutes: ReturnType; + let SharedManager: typeof import('../../../src/management/shared-manager').default; + let createEmptyUnifiedConfig: typeof import('../../../src/config/unified-config-types').createEmptyUnifiedConfig; + let saveUnifiedConfig: typeof import('../../../src/config/unified-config-loader').saveUnifiedConfig; beforeAll(async () => { + originalCcsHome = process.env.CCS_HOME; + originalClaudeConfigDir = process.env.CLAUDE_CONFIG_DIR; + ({ setGlobalConfigDir } = await import('../../../src/utils/config-manager')); + ({ default: SharedManager } = await import('../../../src/management/shared-manager')); + ({ createEmptyUnifiedConfig } = await import('../../../src/config/unified-config-types')); + ({ saveUnifiedConfig } = await import('../../../src/config/unified-config-loader')); + ({ default: claudeExtensionRoutes } = await import( + '../../../src/web-server/routes/claude-extension-routes' + )); + const app = express(); app.use(express.json()); app.use('/api/claude-extension', claudeExtensionRoutes); @@ -49,12 +61,20 @@ describe('web-server claude-extension-routes', () => { afterAll(async () => { await new Promise((resolve) => server.close(() => resolve())); + setGlobalConfigDir(undefined); + + if (originalCcsHome !== undefined) process.env.CCS_HOME = originalCcsHome; + else delete process.env.CCS_HOME; + + if (originalClaudeConfigDir !== undefined) process.env.CLAUDE_CONFIG_DIR = originalClaudeConfigDir; + else delete process.env.CLAUDE_CONFIG_DIR; }); beforeEach(() => { tempHome = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-claude-extension-routes-')); - originalCcsHome = process.env.CCS_HOME; process.env.CCS_HOME = tempHome; + process.env.CLAUDE_CONFIG_DIR = path.join(tempHome, '.claude'); + setGlobalConfigDir(path.join(tempHome, '.ccs')); const ccsDir = path.join(tempHome, '.ccs'); fs.mkdirSync(ccsDir, { recursive: true }); @@ -110,9 +130,9 @@ describe('web-server claude-extension-routes', () => { afterEach(() => { mock.restore(); - - if (originalCcsHome !== undefined) process.env.CCS_HOME = originalCcsHome; - else delete process.env.CCS_HOME; + setGlobalConfigDir(undefined); + delete process.env.CCS_HOME; + delete process.env.CLAUDE_CONFIG_DIR; if (tempHome && fs.existsSync(tempHome)) { fs.rmSync(tempHome, { recursive: true, force: true }); diff --git a/tests/unit/web-server/cliproxy-stats-routes-install.test.ts b/tests/unit/web-server/cliproxy-stats-routes-install.test.ts index a64465e7..cf3e8be2 100644 --- a/tests/unit/web-server/cliproxy-stats-routes-install.test.ts +++ b/tests/unit/web-server/cliproxy-stats-routes-install.test.ts @@ -7,12 +7,34 @@ const installSpy = { }; mock.module('../../../src/config/unified-config-loader', () => ({ + isUnifiedMode: () => true, + loadUnifiedConfig: () => ({ + cliproxy: { backend: 'plus' }, + }), loadOrCreateUnifiedConfig: () => ({ cliproxy: { backend: 'plus' }, }), + getGlobalEnvConfig: () => ({}), + getThinkingConfig: () => ({ + mode: 'auto', + tier_defaults: { + opus: 'high', + sonnet: 'high', + haiku: 'medium', + }, + provider_overrides: {}, + show_warnings: true, + }), + getCliproxySafetyConfig: () => ({ + antigravity_ack_bypass: false, + }), + saveUnifiedConfig: () => {}, })); mock.module('../../../src/cliproxy/binary-manager', () => ({ + ensureCLIProxyBinary: async () => '/tmp/cliproxy', + isCLIProxyInstalled: () => true, + getCLIProxyPath: () => '/tmp/cliproxy', checkCliproxyUpdate: async () => ({ hasUpdate: false, currentVersion: '6.6.80', @@ -26,6 +48,7 @@ mock.module('../../../src/cliproxy/binary-manager', () => ({ }), getInstalledCliproxyVersion: () => '6.6.80', installCliproxyVersion: async () => {}, + fetchLatestCliproxyVersion: async () => '6.6.89', })); mock.module('../../../src/cliproxy/binary/version-checker', () => ({ @@ -103,7 +126,9 @@ beforeEach(() => { }); afterAll(async () => { - await new Promise((resolve) => server.close(() => resolve())); + if (server) { + await new Promise((resolve) => server.close(() => resolve())); + } mock.restore(); }); diff --git a/tests/unit/web-server/cliproxy-stats-routes-model-update.test.ts b/tests/unit/web-server/cliproxy-stats-routes-model-update.test.ts index 09029bd8..84cba3c9 100644 --- a/tests/unit/web-server/cliproxy-stats-routes-model-update.test.ts +++ b/tests/unit/web-server/cliproxy-stats-routes-model-update.test.ts @@ -4,7 +4,6 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; import type { Server } from 'http'; -import cliproxyStatsRoutes from '../../../src/web-server/routes/cliproxy-stats-routes'; function writeSettings(filePath: string, env: Record): void { fs.mkdirSync(path.dirname(filePath), { recursive: true }); @@ -16,8 +15,16 @@ describe('cliproxy-stats-routes model update canonicalization', () => { let baseUrl = ''; let tempHome = ''; let originalCcsHome: string | undefined; + let setGlobalConfigDir: (dir: string | undefined) => void; + let cliproxyStatsRoutes: ReturnType; beforeAll(async () => { + originalCcsHome = process.env.CCS_HOME; + ({ setGlobalConfigDir } = await import('../../../src/utils/config-manager')); + ({ default: cliproxyStatsRoutes } = await import( + '../../../src/web-server/routes/cliproxy-stats-routes' + )); + const app = express(); app.use(express.json()); app.use('/api/cliproxy', cliproxyStatsRoutes); @@ -41,20 +48,24 @@ describe('cliproxy-stats-routes model update canonicalization', () => { afterAll(async () => { await new Promise((resolve) => server.close(() => resolve())); - }); + setGlobalConfigDir(undefined); - beforeEach(() => { - tempHome = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-cliproxy-model-route-')); - originalCcsHome = process.env.CCS_HOME; - process.env.CCS_HOME = tempHome; - }); - - afterEach(() => { if (originalCcsHome !== undefined) { process.env.CCS_HOME = originalCcsHome; } else { delete process.env.CCS_HOME; } + }); + + beforeEach(() => { + tempHome = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-cliproxy-model-route-')); + process.env.CCS_HOME = tempHome; + setGlobalConfigDir(path.join(tempHome, '.ccs')); + }); + + afterEach(() => { + setGlobalConfigDir(undefined); + delete process.env.CCS_HOME; if (tempHome && fs.existsSync(tempHome)) { fs.rmSync(tempHome, { recursive: true, force: true });