mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-13 20:14:34 +00:00
fix(proxy): disambiguate activate without profile
This commit is contained in:
1 parent
46db668636
commit
630a493cca
3 files changed
+69
-9
No files matched your search
@@ -22,6 +22,20 @@ function parseOptionValue(args: string[], key: string): string | undefined {
|
|||||||
return withEquals ? withEquals.slice(prefix.length) : 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 {
|
function showHelp(): number {
|
||||||
console.log('OpenAI-Compatible Proxy');
|
console.log('OpenAI-Compatible Proxy');
|
||||||
console.log('');
|
console.log('');
|
||||||
@@ -63,7 +77,7 @@ function resolveProfile(profileName: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handleStart(args: string[]): Promise<number> {
|
async function handleStart(args: string[]): Promise<number> {
|
||||||
const profileName = args.find((arg) => !arg.startsWith('-'));
|
const profileName = findPositionalArg(args, ['--port', '--host']);
|
||||||
if (!profileName) {
|
if (!profileName) {
|
||||||
console.error(
|
console.error(
|
||||||
fail('Usage: ccs proxy start <profile> [--port <n>] [--host <addr>] [--insecure]')
|
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> {
|
async function handleStatus(args: string[] = []): Promise<number> {
|
||||||
const profileName = args.find((arg) => !arg.startsWith('-'));
|
const profileName = findPositionalArg(args);
|
||||||
const running = profileName
|
const running = profileName
|
||||||
? [await getOpenAICompatProxyStatus(profileName)].filter((status) => status.running)
|
? [await getOpenAICompatProxyStatus(profileName)].filter((status) => status.running)
|
||||||
: (await listOpenAICompatProxyStatuses()).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> {
|
async function handleActivate(args: string[]): Promise<number> {
|
||||||
const profileName = args.find((arg) => !arg.startsWith('-'));
|
const profileName = findPositionalArg(args, ['--shell']);
|
||||||
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;
|
|
||||||
}
|
|
||||||
if (!profileName) {
|
if (!profileName) {
|
||||||
const running = (await listOpenAICompatProxyStatuses()).filter((entry) => entry.running);
|
const running = (await listOpenAICompatProxyStatuses()).filter((entry) => entry.running);
|
||||||
if (running.length > 1) {
|
if (running.length > 1) {
|
||||||
@@ -145,6 +154,11 @@ async function handleActivate(args: string[]): Promise<number> {
|
|||||||
return 1;
|
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'));
|
const shell = detectShell(args.includes('--fish') ? 'fish' : parseOptionValue(args, '--shell'));
|
||||||
let profile;
|
let profile;
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ export async function getOpenAICompatProxyStatus(
|
|||||||
const statuses = await listOpenAICompatProxyStatuses();
|
const statuses = await listOpenAICompatProxyStatuses();
|
||||||
const running = statuses.filter((status) => status.running);
|
const running = statuses.filter((status) => status.running);
|
||||||
if (running.length === 1) {
|
if (running.length === 1) {
|
||||||
return running[0] || { running: false };
|
return running[0];
|
||||||
}
|
}
|
||||||
if (running.length > 1) {
|
if (running.length > 1) {
|
||||||
return { running: true };
|
return { running: true };
|
||||||
|
|||||||
@@ -107,4 +107,50 @@ describe('proxy command e2e', () => {
|
|||||||
const stopped = runCli(['proxy', 'stop']);
|
const stopped = runCli(['proxy', 'stop']);
|
||||||
expect(stopped.status).toBe(0);
|
expect(stopped.status).toBe(0);
|
||||||
}, 35000);
|
}, 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);
|
||||||
});
|
});
|
||||||
Reference in new issue
Block a user