fix(proxy): disambiguate activate without profile

This commit is contained in:
Wooseong Kim
2026-04-20 13:28:25 +09:00
parent 46db668636
commit 630a493cca
3 changed files with 69 additions and 9 deletions
+22 -8
View File
@@ -22,6 +22,20 @@ function parseOptionValue(args: string[], key: string): string | undefined {
return withEquals ? withEquals.slice(prefix.length) : undefined;
}
function findPositionalArg(args: string[], optionsWithValues: string[] = []): string | undefined {
for (let i = 0; i < args.length; i += 1) {
const arg = args[i];
if (arg.startsWith('-')) {
if (optionsWithValues.includes(arg)) {
i += 1;
}
continue;
}
return arg;
}
return undefined;
}
function showHelp(): number {
console.log('OpenAI-Compatible Proxy');
console.log('');
@@ -63,7 +77,7 @@ function resolveProfile(profileName: string) {
}
async function handleStart(args: string[]): Promise<number> {
const profileName = args.find((arg) => !arg.startsWith('-'));
const profileName = findPositionalArg(args, ['--port', '--host']);
if (!profileName) {
console.error(
fail('Usage: ccs proxy start <profile> [--port <n>] [--host <addr>] [--insecure]')
@@ -102,7 +116,7 @@ async function handleStart(args: string[]): Promise<number> {
}
async function handleStatus(args: string[] = []): Promise<number> {
const profileName = args.find((arg) => !arg.startsWith('-'));
const profileName = findPositionalArg(args);
const running = profileName
? [await getOpenAICompatProxyStatus(profileName)].filter((status) => status.running)
: (await listOpenAICompatProxyStatuses()).filter((status) => status.running);
@@ -130,12 +144,7 @@ async function handleStatus(args: string[] = []): Promise<number> {
}
async function handleActivate(args: string[]): Promise<number> {
const profileName = args.find((arg) => !arg.startsWith('-'));
const status = await getOpenAICompatProxyStatus(profileName);
if (!status.running || !status.profileName || !status.port || !status.authToken) {
console.error(fail('Proxy is not running. Start it with: ccs proxy start <profile>'));
return 1;
}
const profileName = findPositionalArg(args, ['--shell']);
if (!profileName) {
const running = (await listOpenAICompatProxyStatuses()).filter((entry) => entry.running);
if (running.length > 1) {
@@ -145,6 +154,11 @@ async function handleActivate(args: string[]): Promise<number> {
return 1;
}
}
const status = await getOpenAICompatProxyStatus(profileName);
if (!status.running || !status.profileName || !status.port || !status.authToken) {
console.error(fail('Proxy is not running. Start it with: ccs proxy start <profile>'));
return 1;
}
const shell = detectShell(args.includes('--fish') ? 'fish' : parseOptionValue(args, '--shell'));
let profile;
+1 -1
View File
@@ -185,7 +185,7 @@ export async function getOpenAICompatProxyStatus(
const statuses = await listOpenAICompatProxyStatuses();
const running = statuses.filter((status) => status.running);
if (running.length === 1) {
return running[0] || { running: false };
return running[0];
}
if (running.length > 1) {
return { running: true };
+46
View File
@@ -107,4 +107,50 @@ describe('proxy command e2e', () => {
const stopped = runCli(['proxy', 'stop']);
expect(stopped.status).toBe(0);
}, 35000);
it('requires an explicit profile when activating with multiple running proxies', async () => {
const firstPort = await getPort();
const ccsDir = path.join(tempDir, '.ccs');
fs.mkdirSync(ccsDir, { recursive: true });
const firstSettingsPath = path.join(ccsDir, 'ccg.settings.json');
const secondSettingsPath = path.join(ccsDir, 'ccgm.settings.json');
fs.writeFileSync(
path.join(ccsDir, 'config.json'),
JSON.stringify({ profiles: { ccg: firstSettingsPath, ccgm: secondSettingsPath } }, null, 2),
'utf8'
);
fs.writeFileSync(
firstSettingsPath,
JSON.stringify({
env: {
ANTHROPIC_BASE_URL: 'http://127.0.0.1:11434',
ANTHROPIC_AUTH_TOKEN: 'ollama-ccg',
ANTHROPIC_MODEL: 'qwen3-coder',
CCS_DROID_PROVIDER: 'generic-chat-completion-api',
},
}),
'utf8'
);
fs.writeFileSync(
secondSettingsPath,
JSON.stringify({
env: {
ANTHROPIC_BASE_URL: 'https://api.openai.com/v1',
ANTHROPIC_AUTH_TOKEN: 'sk-ccgm',
ANTHROPIC_MODEL: 'gpt-4.1',
},
}),
'utf8'
);
expect(runCli(['proxy', 'start', 'ccg', '--port', String(firstPort)]).status).toBe(0);
const secondPort = await getPort();
expect(runCli(['proxy', 'start', 'ccgm', '--port', String(secondPort)]).status).toBe(0);
const activate = runCli(['proxy', 'activate', '--shell', 'bash']);
expect(activate.status).toBe(1);
expect(activate.stderr).toContain(
'Multiple proxies are running. Specify a profile: ccs proxy activate <profile>'
);
}, 35000);
});