mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 06:16:37 +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
217 lines
6.1 KiB
TypeScript
217 lines
6.1 KiB
TypeScript
/**
|
|
* CLIProxy Binary Service
|
|
*
|
|
* Handles CLIProxyAPI binary version management:
|
|
* - Get current version status
|
|
* - Install specific versions
|
|
* - Install latest version
|
|
* - Version pinning
|
|
*/
|
|
|
|
import {
|
|
getInstalledCliproxyVersion,
|
|
installCliproxyVersion,
|
|
fetchLatestCliproxyVersion,
|
|
isCLIProxyInstalled,
|
|
getCLIProxyPath,
|
|
getPinnedVersion,
|
|
savePinnedVersion,
|
|
clearPinnedVersion,
|
|
isVersionPinned,
|
|
resolveLocalBackend,
|
|
} from '../binary-manager';
|
|
import { BACKEND_CONFIG, DEFAULT_BACKEND } from '../binary/platform-detector';
|
|
import { CLIProxyBackend } from '../types';
|
|
import { loadOrCreateUnifiedConfig } from '../../config/config-loader-facade';
|
|
|
|
/** Binary status result */
|
|
export interface BinaryStatusResult {
|
|
installed: boolean;
|
|
currentVersion: string | null;
|
|
pinnedVersion: string | null;
|
|
binaryPath: string;
|
|
fallbackVersion: string;
|
|
backend: CLIProxyBackend;
|
|
}
|
|
|
|
/** Install result */
|
|
export interface InstallResult {
|
|
success: boolean;
|
|
version: string;
|
|
error?: string;
|
|
wasPinned?: boolean;
|
|
}
|
|
|
|
/** Latest version check result */
|
|
export interface LatestVersionResult {
|
|
success: boolean;
|
|
latestVersion?: string;
|
|
currentVersion?: string;
|
|
updateAvailable?: boolean;
|
|
error?: string;
|
|
}
|
|
|
|
/**
|
|
* Get current binary status for a specific backend
|
|
*/
|
|
export function getBinaryStatus(backend?: CLIProxyBackend): BinaryStatusResult {
|
|
const configuredBackend =
|
|
backend ?? loadOrCreateUnifiedConfig().cliproxy?.backend ?? DEFAULT_BACKEND;
|
|
const effectiveBackend = resolveLocalBackend(configuredBackend, { notifyOnPlus: true });
|
|
const backendConfig = BACKEND_CONFIG[effectiveBackend];
|
|
return {
|
|
installed: isCLIProxyInstalled(effectiveBackend),
|
|
currentVersion: getInstalledCliproxyVersion(effectiveBackend),
|
|
pinnedVersion: getPinnedVersion(effectiveBackend),
|
|
binaryPath: getCLIProxyPath(effectiveBackend),
|
|
fallbackVersion: backendConfig.fallbackVersion,
|
|
backend: effectiveBackend,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Check for latest version
|
|
*/
|
|
export async function checkLatestVersion(backend?: CLIProxyBackend): Promise<LatestVersionResult> {
|
|
const configuredBackend =
|
|
backend ?? loadOrCreateUnifiedConfig().cliproxy?.backend ?? DEFAULT_BACKEND;
|
|
const effectiveBackend = resolveLocalBackend(configuredBackend, { notifyOnPlus: true });
|
|
|
|
try {
|
|
// Use checkCliproxyUpdate which is backend-aware (uses correct GitHub repo)
|
|
const { checkCliproxyUpdate } = await import('../binary-manager');
|
|
const updateResult = await checkCliproxyUpdate(effectiveBackend);
|
|
const latestVersion = updateResult.latestVersion;
|
|
const currentVersion = getInstalledCliproxyVersion(effectiveBackend);
|
|
const updateAvailable = latestVersion !== currentVersion;
|
|
|
|
return {
|
|
success: true,
|
|
latestVersion,
|
|
currentVersion: currentVersion || undefined,
|
|
updateAvailable,
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
success: false,
|
|
error: (error as Error).message,
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validate version format (supports X.Y.Z or X.Y.Z-N suffix)
|
|
*/
|
|
export function isValidVersionFormat(version: string): boolean {
|
|
return /^\d+\.\d+\.\d+(-\d+)?$/.test(version);
|
|
}
|
|
|
|
/**
|
|
* Install a specific version and pin it
|
|
*/
|
|
export async function installVersion(
|
|
version: string,
|
|
verbose = false,
|
|
backend?: CLIProxyBackend
|
|
): Promise<InstallResult> {
|
|
if (!isValidVersionFormat(version)) {
|
|
return {
|
|
success: false,
|
|
version,
|
|
error: 'Invalid version format. Expected format: X.Y.Z (e.g., 6.5.53)',
|
|
};
|
|
}
|
|
|
|
const configuredBackend =
|
|
backend ?? loadOrCreateUnifiedConfig().cliproxy?.backend ?? DEFAULT_BACKEND;
|
|
const effectiveBackend = resolveLocalBackend(configuredBackend, { notifyOnPlus: true });
|
|
|
|
try {
|
|
await installCliproxyVersion(version, verbose, effectiveBackend);
|
|
savePinnedVersion(version, effectiveBackend);
|
|
|
|
return {
|
|
success: true,
|
|
version,
|
|
wasPinned: true,
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
success: false,
|
|
version,
|
|
error: (error as Error).message,
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Install latest version and clear any pin
|
|
*/
|
|
export async function installLatest(
|
|
verbose = false,
|
|
backend?: CLIProxyBackend
|
|
): Promise<InstallResult> {
|
|
const configuredBackend =
|
|
backend ?? loadOrCreateUnifiedConfig().cliproxy?.backend ?? DEFAULT_BACKEND;
|
|
const effectiveBackend = resolveLocalBackend(configuredBackend, { notifyOnPlus: true });
|
|
|
|
try {
|
|
const latestVersion = await fetchLatestCliproxyVersion(effectiveBackend);
|
|
const currentVersion = getInstalledCliproxyVersion(effectiveBackend);
|
|
const wasPinned = isVersionPinned(effectiveBackend);
|
|
|
|
if (isCLIProxyInstalled(effectiveBackend) && latestVersion === currentVersion && !wasPinned) {
|
|
return {
|
|
success: true,
|
|
version: latestVersion,
|
|
error: `Already running latest version: v${latestVersion}`,
|
|
};
|
|
}
|
|
|
|
await installCliproxyVersion(latestVersion, verbose, effectiveBackend);
|
|
clearPinnedVersion(effectiveBackend);
|
|
|
|
return {
|
|
success: true,
|
|
version: latestVersion,
|
|
wasPinned,
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
success: false,
|
|
version: '',
|
|
error: (error as Error).message,
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if a version is pinned
|
|
*/
|
|
export function isPinned(backend?: CLIProxyBackend): boolean {
|
|
const configuredBackend =
|
|
backend ?? loadOrCreateUnifiedConfig().cliproxy?.backend ?? DEFAULT_BACKEND;
|
|
const effectiveBackend = resolveLocalBackend(configuredBackend, { notifyOnPlus: true });
|
|
return isVersionPinned(effectiveBackend);
|
|
}
|
|
|
|
/**
|
|
* Get pinned version if any
|
|
*/
|
|
export function getPinned(backend?: CLIProxyBackend): string | null {
|
|
const configuredBackend =
|
|
backend ?? loadOrCreateUnifiedConfig().cliproxy?.backend ?? DEFAULT_BACKEND;
|
|
const effectiveBackend = resolveLocalBackend(configuredBackend, { notifyOnPlus: true });
|
|
return getPinnedVersion(effectiveBackend);
|
|
}
|
|
|
|
/**
|
|
* Clear version pin
|
|
*/
|
|
export function clearPin(backend?: CLIProxyBackend): void {
|
|
const configuredBackend =
|
|
backend ?? loadOrCreateUnifiedConfig().cliproxy?.backend ?? DEFAULT_BACKEND;
|
|
const effectiveBackend = resolveLocalBackend(configuredBackend, { notifyOnPlus: true });
|
|
clearPinnedVersion(effectiveBackend);
|
|
}
|