mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-20 18:19:21 +00:00
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
80 lines
1.9 KiB
TypeScript
80 lines
1.9 KiB
TypeScript
/**
|
|
* File Watcher (Phase 04)
|
|
*
|
|
* Watches ~/.ccs/ directory for config file changes using chokidar.
|
|
* Broadcasts changes to WebSocket clients for real-time sync.
|
|
*/
|
|
|
|
import chokidar, { FSWatcher } from 'chokidar';
|
|
import * as path from 'path';
|
|
import { getCcsDir } from '../config/config-loader-facade';
|
|
|
|
export interface FileChangeEvent {
|
|
type: 'config-changed' | 'settings-changed' | 'profiles-changed' | 'proxy-status-changed';
|
|
path: string;
|
|
timestamp: number;
|
|
}
|
|
|
|
export type FileChangeCallback = (event: FileChangeEvent) => void;
|
|
|
|
export function createFileWatcher(onChange: FileChangeCallback): FSWatcher {
|
|
const ccsDir = getCcsDir();
|
|
|
|
const watcher = chokidar.watch(
|
|
[
|
|
path.join(ccsDir, 'config.json'), // Legacy config
|
|
path.join(ccsDir, 'config.yaml'), // Unified config
|
|
path.join(ccsDir, '*.settings.json'),
|
|
path.join(ccsDir, 'profiles.json'),
|
|
path.join(ccsDir, 'cliproxy', 'sessions.json'), // Proxy session tracking
|
|
],
|
|
{
|
|
persistent: true,
|
|
ignoreInitial: true,
|
|
awaitWriteFinish: {
|
|
stabilityThreshold: 100,
|
|
pollInterval: 50,
|
|
},
|
|
}
|
|
);
|
|
|
|
watcher.on('change', (filePath) => {
|
|
const basename = path.basename(filePath);
|
|
let type: FileChangeEvent['type'];
|
|
|
|
if (basename === 'config.json' || basename === 'config.yaml') {
|
|
type = 'config-changed';
|
|
} else if (basename === 'profiles.json') {
|
|
type = 'profiles-changed';
|
|
} else if (basename === 'sessions.json') {
|
|
type = 'proxy-status-changed';
|
|
} else {
|
|
type = 'settings-changed';
|
|
}
|
|
|
|
onChange({
|
|
type,
|
|
path: filePath,
|
|
timestamp: Date.now(),
|
|
});
|
|
});
|
|
|
|
watcher.on('add', (filePath) => {
|
|
onChange({
|
|
type: 'config-changed',
|
|
path: filePath,
|
|
timestamp: Date.now(),
|
|
});
|
|
});
|
|
|
|
watcher.on('unlink', (filePath) => {
|
|
onChange({
|
|
type: 'config-changed',
|
|
path: filePath,
|
|
timestamp: Date.now(),
|
|
});
|
|
});
|
|
|
|
return watcher;
|
|
}
|