From c8800b418a8ee2143366a2e199c42384ff5693f4 Mon Sep 17 00:00:00 2001 From: Tam Nhu Tran Date: Wed, 11 Feb 2026 11:35:44 +0700 Subject: [PATCH] fix(config): resolve remaining hardcoded paths and improve readability - Replace hardcoded ~/.ccs in error messages: ccs.ts (lines 83, 151) and delegation-handler.ts (line 333) now use getCcsDir() - Cache repeated getter calls in local vars for readability: openrouter-catalog.ts getCachedModels/setCachedModels, aggregator.ts getInstancePaths - Add path.resolve() for CCS_HOME env var consistency with CCS_DIR --- src/api/services/openrouter-catalog.ts | 10 ++++++---- src/ccs.ts | 6 +++--- src/delegation/delegation-handler.ts | 3 ++- src/utils/config-manager.ts | 5 +++-- src/web-server/usage/aggregator.ts | 7 ++++--- 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/api/services/openrouter-catalog.ts b/src/api/services/openrouter-catalog.ts index 601f90eb..bfcb784e 100644 --- a/src/api/services/openrouter-catalog.ts +++ b/src/api/services/openrouter-catalog.ts @@ -32,8 +32,9 @@ interface CacheData { /** Check if cached data is valid */ function getCachedModels(): OpenRouterModel[] | null { try { - if (!fs.existsSync(getCacheFile())) return null; - const data = JSON.parse(fs.readFileSync(getCacheFile(), 'utf8')) as CacheData; + const cacheFile = getCacheFile(); + if (!fs.existsSync(cacheFile)) return null; + const data = JSON.parse(fs.readFileSync(cacheFile, 'utf8')) as CacheData; if (Date.now() - data.fetchedAt > CACHE_TTL_MS) return null; return data.models; } catch { @@ -44,10 +45,11 @@ function getCachedModels(): OpenRouterModel[] | null { /** Save models to cache */ function setCachedModels(models: OpenRouterModel[]): void { try { - const dir = path.dirname(getCacheFile()); + const cacheFile = getCacheFile(); + const dir = path.dirname(cacheFile); if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); fs.writeFileSync( - getCacheFile(), + cacheFile, JSON.stringify({ models, fetchedAt: Date.now(), diff --git a/src/ccs.ts b/src/ccs.ts index c0a39550..6ee9da64 100644 --- a/src/ccs.ts +++ b/src/ccs.ts @@ -2,7 +2,7 @@ import { spawn, ChildProcess } from 'child_process'; import * as path from 'path'; import * as fs from 'fs'; import { detectClaudeCli } from './utils/claude-detector'; -import { getSettingsPath, loadSettings } from './utils/config-manager'; +import { getSettingsPath, loadSettings, getCcsDir } from './utils/config-manager'; import { validateGlmKey, validateMiniMaxKey } from './utils/api-key-validator'; import { ErrorManager } from './utils/error-manager'; import { execClaudeWithCLIProxy, CLIProxyProvider } from './cliproxy'; @@ -80,7 +80,7 @@ async function execClaudeWithProxy( if (!apiKey || apiKey === 'YOUR_GLM_API_KEY_HERE') { console.error(fail('GLMT profile requires Z.AI API key')); - console.error(' Edit ~/.ccs/glmt.settings.json and set ANTHROPIC_AUTH_TOKEN'); + console.error(` Edit ${getCcsDir()}/glmt.settings.json and set ANTHROPIC_AUTH_TOKEN`); process.exit(1); } @@ -148,7 +148,7 @@ async function execClaudeWithProxy( console.error('Workarounds:'); console.error(' - Use non-thinking mode: ccs glm "prompt"'); console.error(' - Enable verbose logging: ccs glmt --verbose "prompt"'); - console.error(' - Check proxy logs in ~/.ccs/logs/ (if debug enabled)'); + console.error(` - Check proxy logs in ${getCcsDir()}/logs/ (if debug enabled)`); console.error(''); proxy.kill(); process.exit(1); diff --git a/src/delegation/delegation-handler.ts b/src/delegation/delegation-handler.ts index 75c75f6f..cfe85138 100644 --- a/src/delegation/delegation-handler.ts +++ b/src/delegation/delegation-handler.ts @@ -6,6 +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'; /** * Parse and validate a string flag value @@ -330,7 +331,7 @@ export class DelegationHandler { console.error(` ${validation.error}`); console.error(''); console.error(' Run: ccs doctor'); - console.error(` Or configure: ~/.ccs/${profile}.settings.json`); + console.error(` Or configure: ${getCcsDir()}/${profile}.settings.json`); process.exit(1); } } diff --git a/src/utils/config-manager.ts b/src/utils/config-manager.ts index 8512efec..ffadad5a 100644 --- a/src/utils/config-manager.ts +++ b/src/utils/config-manager.ts @@ -38,7 +38,7 @@ export function getCcsHome(): string { export function getCcsDir(): string { if (_globalConfigDir) return _globalConfigDir; if (process.env.CCS_DIR) return path.resolve(process.env.CCS_DIR); - if (process.env.CCS_HOME) return path.join(process.env.CCS_HOME, '.ccs'); + if (process.env.CCS_HOME) return path.join(path.resolve(process.env.CCS_HOME), '.ccs'); return path.join(os.homedir(), '.ccs'); } @@ -49,7 +49,8 @@ export function getCcsDir(): string { export function getCcsDirSource(): [string, string] { if (_globalConfigDir) return ['--config-dir', _globalConfigDir]; if (process.env.CCS_DIR) return ['CCS_DIR', path.resolve(process.env.CCS_DIR)]; - if (process.env.CCS_HOME) return ['CCS_HOME', path.join(process.env.CCS_HOME, '.ccs')]; + if (process.env.CCS_HOME) + return ['CCS_HOME', path.join(path.resolve(process.env.CCS_HOME), '.ccs')]; return ['default', path.join(os.homedir(), '.ccs')]; } diff --git a/src/web-server/usage/aggregator.ts b/src/web-server/usage/aggregator.ts index 7bbe4e79..5d30676e 100644 --- a/src/web-server/usage/aggregator.ts +++ b/src/web-server/usage/aggregator.ts @@ -40,15 +40,16 @@ function getCcsInstancesDir() { * Only returns instances with existing projects/ directory */ function getInstancePaths(): string[] { - if (!fs.existsSync(getCcsInstancesDir())) { + const instancesDir = getCcsInstancesDir(); + if (!fs.existsSync(instancesDir)) { return []; } try { - const entries = fs.readdirSync(getCcsInstancesDir(), { withFileTypes: true }); + const entries = fs.readdirSync(instancesDir, { withFileTypes: true }); return entries .filter((entry) => entry.isDirectory()) - .map((entry) => path.join(getCcsInstancesDir(), entry.name)) + .map((entry) => path.join(instancesDir, entry.name)) .filter((instancePath) => { // Only include instances that have a projects directory const projectsPath = path.join(instancePath, 'projects');