fix(config): migrate all hardcoded paths to getCcsDir() and improve validation

- Replace os.homedir() + '.ccs' with getCcsDir() across 14 instances in 13 files:
  version-command, model-config, openrouter-catalog, config-checks, disk-cache,
  aggregator, auth-middleware, shell-completion, shared-manager, recovery-manager,
  auto-repair, delegation-validator, claude-dir-installer, cliproxy executor
- Add isDirectory() validation for --config-dir argument in ccs.ts
- Make detectCloudSyncPath() case-insensitive for cloud provider matching
- Fix help-command.ts to use dynamic dirDisplay for all path references
- Add 5 new tests: setGlobalConfigDir precedence, relative path resolution,
  reset behavior, getCcsDirSource with --config-dir, case-insensitive detection
- Clean up unused os imports after migration
This commit is contained in:
Tam Nhu Tran
2026-02-11 11:15:08 +07:00
parent 7a0e6a4112
commit 60d6bbd027
18 changed files with 87 additions and 59 deletions
+1 -6
View File
@@ -197,12 +197,7 @@ export class ClaudeDirInstaller {
cleanupDeprecated(silent = false): CleanupResult {
const deprecatedFile = path.join(this.ccsClaudeDir, 'agents', 'ccs-delegator.md');
const userSymlinkFile = path.join(this.homeDir, '.claude', 'agents', 'ccs-delegator.md');
const migrationMarker = path.join(
this.homeDir,
'.ccs',
'.migrations',
'v435-delegator-cleanup'
);
const migrationMarker = path.join(getCcsDir(), '.migrations', 'v435-delegator-cleanup');
const cleanedFiles: string[] = [];
+3 -3
View File
@@ -72,10 +72,10 @@ const CLOUD_SYNC_PATTERNS = [
* @returns Detected service name or null
*/
export function detectCloudSyncPath(dir: string): string | null {
const normalized = dir.replace(/\\/g, '/');
const normalized = dir.replace(/\\/g, '/').toLowerCase();
for (const pattern of CLOUD_SYNC_PATTERNS) {
if (normalized.includes(pattern)) {
return pattern;
if (normalized.includes(pattern.toLowerCase())) {
return pattern; // Return original casing for display
}
}
return null;
+3 -5
View File
@@ -2,9 +2,9 @@
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
import { Settings } from '../types';
import { ValidationResult } from '../types/utils';
import { getCcsDir } from './config-manager';
/**
* Extended validation result for delegation profiles
@@ -28,8 +28,7 @@ export class DelegationValidator {
* @returns Validation result { valid: boolean, error?: string, settingsPath?: string }
*/
static validate(profileName: string): DelegationValidationResult {
const homeDir = os.homedir();
const settingsPath = path.join(homeDir, '.ccs', `${profileName}.settings.json`);
const settingsPath = path.join(getCcsDir(), `${profileName}.settings.json`);
// Check if profile directory exists
if (!fs.existsSync(settingsPath)) {
@@ -144,8 +143,7 @@ export class DelegationValidator {
* @returns List of profile names ready for delegation
*/
static getReadyProfiles(): string[] {
const homeDir = os.homedir();
const ccsDir = path.join(homeDir, '.ccs');
const ccsDir = getCcsDir();
const configPath = path.join(ccsDir, 'config.yaml');
if (!fs.existsSync(ccsDir)) {
+2 -1
View File
@@ -1,6 +1,7 @@
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
import { getCcsDir } from './config-manager';
// import { execSync } from 'child_process'; // Currently unused
type ShellType = 'bash' | 'zsh' | 'fish' | 'powershell' | null;
@@ -24,7 +25,7 @@ export class ShellCompletionInstaller {
constructor() {
this.homeDir = os.homedir();
this.ccsDir = path.join(this.homeDir, '.ccs');
this.ccsDir = getCcsDir();
this.completionDir = path.join(this.ccsDir, 'completions');
this.scriptsDir = path.join(__dirname, '../../scripts/completion');
}