mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-17 06:17:09 +00:00
fix(cliproxy): add session check on delete and atomic settings writes
- Block variant deletion when CLIProxy has active sessions - Use temp file + rename pattern for atomic settings writes - Prevents partial writes on crash/interruption
This commit is contained in:
@@ -15,7 +15,7 @@ import { loadOrCreateUnifiedConfig } from '../../config/unified-config-loader';
|
||||
import { DEFAULT_BACKEND } from '../platform-detector';
|
||||
import { isUnifiedMode } from '../../config/unified-config-loader';
|
||||
import { deleteConfigForPort } from '../config-generator';
|
||||
import { deleteSessionLockForPort } from '../session-tracker';
|
||||
import { hasActiveSessions, deleteSessionLockForPort } from '../session-tracker';
|
||||
import { warn } from '../../utils/ui';
|
||||
import {
|
||||
createSettingsFile,
|
||||
@@ -154,6 +154,22 @@ export function createVariant(
|
||||
*/
|
||||
export function removeVariant(name: string): VariantOperationResult {
|
||||
try {
|
||||
// First check if variant exists and has active sessions
|
||||
const variants = listVariantsFromConfig();
|
||||
const existingVariant = variants[name];
|
||||
|
||||
if (!existingVariant) {
|
||||
return { success: false, error: `Variant '${name}' not found` };
|
||||
}
|
||||
|
||||
// Check for active sessions on this variant's port before deletion
|
||||
if (existingVariant.port && hasActiveSessions(existingVariant.port)) {
|
||||
return {
|
||||
success: false,
|
||||
error: `Cannot delete variant '${name}': CLIProxy is running with active sessions. Stop the session first.`,
|
||||
};
|
||||
}
|
||||
|
||||
let variant: VariantConfig | null;
|
||||
|
||||
if (isUnifiedMode()) {
|
||||
@@ -179,11 +195,7 @@ export function removeVariant(name: string): VariantOperationResult {
|
||||
}
|
||||
}
|
||||
|
||||
if (!variant) {
|
||||
return { success: false, error: `Variant '${name}' not found` };
|
||||
}
|
||||
|
||||
return { success: true, variant };
|
||||
return { success: true, variant: variant ?? undefined };
|
||||
} catch (error) {
|
||||
return { success: false, error: (error as Error).message };
|
||||
}
|
||||
|
||||
@@ -63,10 +63,13 @@ function ensureDir(dir: string): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Write settings file atomically
|
||||
* Write settings file atomically using temp file + rename.
|
||||
* The renameSync is atomic on POSIX systems, preventing partial writes on crash.
|
||||
*/
|
||||
function writeSettings(filePath: string, settings: SettingsFile): void {
|
||||
fs.writeFileSync(filePath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
|
||||
const tempPath = `${filePath}.tmp.${process.pid}`;
|
||||
fs.writeFileSync(tempPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
|
||||
fs.renameSync(tempPath, filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -248,7 +251,9 @@ export function updateSettingsModel(settingsPath: string, model: string): void {
|
||||
delete (settings.env as unknown as Record<string, string>).ANTHROPIC_MODEL;
|
||||
}
|
||||
|
||||
fs.writeFileSync(resolvedPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
|
||||
const tempPath = `${resolvedPath}.tmp.${process.pid}`;
|
||||
fs.writeFileSync(tempPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
|
||||
fs.renameSync(tempPath, resolvedPath);
|
||||
} catch {
|
||||
// Ignore errors - settings file may be invalid
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user