fix(cliproxy): pin routing config regeneration path

- capture the resolved local cliproxy config/auth paths before regenerating
  routing strategy config
- thread explicit override paths into regenerateConfig so scoped config writes
  stay deterministic during the full test suite
- add regression coverage for explicit config path overrides
This commit is contained in:
Tam Nhu Tran
2026-04-16 23:29:10 -04:00
parent 41bf5075e0
commit d3de83e157
3 changed files with 34 additions and 4 deletions
+12 -3
View File
@@ -42,6 +42,11 @@ export const CCS_CONTROL_PANEL_SECRET = 'ccs';
*/
export const CLIPROXY_CONFIG_VERSION = 17;
interface RegenerateConfigOptions {
configPath?: string;
authDir?: string;
}
interface OAuthModelAliasEntry {
name: string;
alias: string;
@@ -739,8 +744,12 @@ function extractYamlSection(content: string, sectionKey: string): string {
* @param port - Default port to use if not found in existing config
* @returns Path to new config file
*/
export function regenerateConfig(port: number = CLIPROXY_DEFAULT_PORT): string {
const configPath = getConfigPathForPort(port);
export function regenerateConfig(
port: number = CLIPROXY_DEFAULT_PORT,
options?: RegenerateConfigOptions
): string {
const configPath = options?.configPath ?? getConfigPathForPort(port);
const authDir = options?.authDir ?? getAuthDir();
// Preserve user settings from existing config
let effectivePort = port;
@@ -787,7 +796,7 @@ export function regenerateConfig(port: number = CLIPROXY_DEFAULT_PORT): string {
// Ensure directories exist
fs.mkdirSync(path.dirname(configPath), { recursive: true });
fs.mkdirSync(getAuthDir(), { recursive: true, mode: 0o700 });
fs.mkdirSync(authDir, { recursive: true, mode: 0o700 });
// Generate fresh config with preserved user API keys and aliases
let configContent = generateUnifiedConfigContent(effectivePort, userApiKeys, existingAliases);
+4 -1
View File
@@ -1,5 +1,6 @@
import { mutateUnifiedConfig, loadOrCreateUnifiedConfig } from '../config/unified-config-loader';
import { regenerateConfig } from './config/generator';
import { getAuthDir, getConfigPathForPort } from './config/path-resolver';
import {
fetchCliproxyRoutingResponse,
getCliproxyRoutingTarget,
@@ -98,6 +99,8 @@ export async function applyCliproxyRoutingStrategy(
strategy: CliproxyRoutingStrategy
): Promise<CliproxyRoutingApplyResult> {
const target = getCliproxyRoutingTarget();
const configPath = getConfigPathForPort(target.port);
const authDir = getAuthDir();
if (target.isRemote) {
await updateLiveCliproxyRoutingStrategy(strategy);
@@ -116,7 +119,7 @@ export async function applyCliproxyRoutingStrategy(
config.cliproxy.routing = { strategy };
}
});
regenerateConfig(target.port);
regenerateConfig(target.port, { configPath, authDir });
try {
await updateLiveCliproxyRoutingStrategy(strategy);
@@ -185,6 +185,24 @@ describe('Config Generator Port', function () {
// Port should still be 8325
assert.ok(content.includes(`port: ${variantPort}`));
});
it('honors an explicit config path override', function () {
const variantPort = 8318;
const overrideDir = path.join(testHome, '.ccs-scope-override', 'cliproxy');
const overrideConfigPath = path.join(overrideDir, `config-${variantPort}.yaml`);
const overrideAuthDir = path.join(overrideDir, 'auth');
regenerateConfig(variantPort, {
configPath: overrideConfigPath,
authDir: overrideAuthDir,
});
assert.ok(fs.existsSync(overrideConfigPath), 'Should create config at the override path');
assert.ok(fs.existsSync(overrideAuthDir), 'Should create auth dir at the override path');
const defaultConfigPath = path.join(cliproxyDir, `config-${variantPort}.yaml`);
assert.strictEqual(fs.existsSync(defaultConfigPath), false);
});
});
describe('deleteConfigForPort', function () {