mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 06:16:37 +00:00
fix(cli): document gitlab shortcut flags and harden cursor routing
This commit is contained in:
+14
-6
@@ -65,7 +65,8 @@ import {
|
|||||||
resolveOfficialChannelsLaunchPlan,
|
resolveOfficialChannelsLaunchPlan,
|
||||||
} from './channels/official-channels-runtime';
|
} from './channels/official-channels-runtime';
|
||||||
import { getOfficialChannelReadiness } from './channels/official-channels-store';
|
import { getOfficialChannelReadiness } from './channels/official-channels-store';
|
||||||
import { isCursorSubcommandToken } from './cursor/constants';
|
import { isCursorSubcommandToken, shouldUseCursorCliproxyShortcut } from './cursor/constants';
|
||||||
|
import { isCLIProxyProvider } from './cliproxy/provider-capabilities';
|
||||||
|
|
||||||
// Import centralized error handling
|
// Import centralized error handling
|
||||||
import { handleError, runCleanup } from './errors';
|
import { handleError, runCleanup } from './errors';
|
||||||
@@ -123,7 +124,6 @@ interface RuntimeReasoningResolution {
|
|||||||
sourceDisplay: string | undefined;
|
sourceDisplay: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CURSOR_CLIPROXY_SHORTCUT_FLAGS = new Set(['--auth', '--logout', '--config', '--accounts']);
|
|
||||||
const CODEX_RUNTIME_REASONING_LEVELS = new Set(['minimal', 'low', 'medium', 'high', 'xhigh']);
|
const CODEX_RUNTIME_REASONING_LEVELS = new Set(['minimal', 'low', 'medium', 'high', 'xhigh']);
|
||||||
const CODEX_NATIVE_PASSTHROUGH_FLAGS = new Set(['--help', '-h', '--version', '-v']);
|
const CODEX_NATIVE_PASSTHROUGH_FLAGS = new Set(['--help', '-h', '--version', '-v']);
|
||||||
|
|
||||||
@@ -149,10 +149,6 @@ function detectProfile(args: string[]): DetectedProfile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function shouldUseCursorCliproxyShortcut(args: string[]): boolean {
|
|
||||||
return args[0] === 'cursor' && CURSOR_CLIPROXY_SHORTCUT_FLAGS.has(args[1] || '');
|
|
||||||
}
|
|
||||||
|
|
||||||
function resolveRuntimeReasoningFlags(
|
function resolveRuntimeReasoningFlags(
|
||||||
args: string[],
|
args: string[],
|
||||||
envThinkingValue: string | undefined
|
envThinkingValue: string | undefined
|
||||||
@@ -490,6 +486,18 @@ async function main(): Promise<void> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof firstArg === 'string' &&
|
||||||
|
isCLIProxyProvider(firstArg) &&
|
||||||
|
firstArg !== 'cursor' &&
|
||||||
|
args.length > 1 &&
|
||||||
|
(args.includes('--help') || args.includes('-h'))
|
||||||
|
) {
|
||||||
|
const { showProviderShortcutHelp } = await import('./commands/help-command');
|
||||||
|
await showProviderShortcutHelp(firstArg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Special case: copilot command (GitHub Copilot integration)
|
// Special case: copilot command (GitHub Copilot integration)
|
||||||
// Route known subcommands to command handler, keep all other args as profile passthrough.
|
// Route known subcommands to command handler, keep all other args as profile passthrough.
|
||||||
if (firstArg === 'copilot' && args.length > 1) {
|
if (firstArg === 'copilot' && args.length > 1) {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import packageJson from '../../package.json';
|
import packageJson from '../../package.json';
|
||||||
|
import type { CLIProxyProvider } from '../cliproxy';
|
||||||
import { color, dim, header, initUI, subheader } from '../utils/ui';
|
import { color, dim, header, initUI, subheader } from '../utils/ui';
|
||||||
import {
|
import {
|
||||||
BUILTIN_PROVIDER_SHORTCUTS,
|
BUILTIN_PROVIDER_SHORTCUTS,
|
||||||
@@ -82,10 +83,80 @@ async function showProvidersHelp(writeLine: HelpWriter): Promise<void> {
|
|||||||
],
|
],
|
||||||
writeLine
|
writeLine
|
||||||
);
|
);
|
||||||
|
writeCommandTable(
|
||||||
|
'GitLab Duo Flags',
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: 'ccs gitlab --auth --gitlab-token-login',
|
||||||
|
summary: 'Authenticate with a GitLab Personal Access Token',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ccs gitlab --auth --token-login',
|
||||||
|
summary: 'Legacy alias for GitLab PAT login (still supported)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ccs gitlab --auth --gitlab-url <url>',
|
||||||
|
summary: 'Use a self-hosted GitLab base URL during OAuth or PAT auth',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
writeLine
|
||||||
|
);
|
||||||
writeLine(` ${dim('Deep help: ccs cliproxy --help | ccs api --help')}`);
|
writeLine(` ${dim('Deep help: ccs cliproxy --help | ccs api --help')}`);
|
||||||
writeLine('');
|
writeLine('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function showProviderShortcutHelp(
|
||||||
|
provider: CLIProxyProvider,
|
||||||
|
writeLine: HelpWriter = console.log
|
||||||
|
): Promise<void> {
|
||||||
|
if (provider === 'kiro') {
|
||||||
|
await showKiroHelp(writeLine);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await initUI();
|
||||||
|
|
||||||
|
const providerEntry = BUILTIN_PROVIDER_SHORTCUTS.find((entry) => entry.name === provider);
|
||||||
|
writeLine(header(`CCS ${provider} Shortcut Help`));
|
||||||
|
writeLine('');
|
||||||
|
writeLine(` ${providerEntry?.summary || 'CLIProxy OAuth provider shortcut'}.`);
|
||||||
|
writeLine('');
|
||||||
|
writeCommandTable(
|
||||||
|
'Common Commands',
|
||||||
|
[
|
||||||
|
{ name: `ccs ${provider} --auth`, summary: 'Authenticate the provider account via CLIProxy' },
|
||||||
|
{ name: `ccs ${provider} --accounts`, summary: 'List or manage stored CLIProxy accounts' },
|
||||||
|
{ name: `ccs ${provider} --config`, summary: 'Open the provider config flow' },
|
||||||
|
{ name: `ccs ${provider} "task"`, summary: 'Run Claude through this provider shortcut' },
|
||||||
|
],
|
||||||
|
writeLine
|
||||||
|
);
|
||||||
|
|
||||||
|
if (provider === 'gitlab') {
|
||||||
|
writeCommandTable(
|
||||||
|
'GitLab Duo Flags',
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: '--gitlab-token-login',
|
||||||
|
summary: 'Use a GitLab Personal Access Token instead of browser OAuth',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '--token-login',
|
||||||
|
summary: 'Legacy alias for `--gitlab-token-login`',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '--gitlab-url <url>',
|
||||||
|
summary: 'Target a self-hosted GitLab base URL',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
writeLine
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
writeLine(` ${dim('See also: ccs help providers | ccs cliproxy --help')}`);
|
||||||
|
writeLine('');
|
||||||
|
}
|
||||||
|
|
||||||
async function showKiroHelp(writeLine: HelpWriter): Promise<void> {
|
async function showKiroHelp(writeLine: HelpWriter): Promise<void> {
|
||||||
await initUI();
|
await initUI();
|
||||||
writeLine(header('CCS Kiro Help'));
|
writeLine(header('CCS Kiro Help'));
|
||||||
|
|||||||
@@ -12,8 +12,35 @@ export const CURSOR_SUBCOMMANDS = [
|
|||||||
'-h',
|
'-h',
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
|
export const CURSOR_CLIPROXY_SHORTCUT_FLAGS = new Set([
|
||||||
|
'--auth',
|
||||||
|
'--logout',
|
||||||
|
'--config',
|
||||||
|
'--accounts',
|
||||||
|
]);
|
||||||
|
|
||||||
export function isCursorSubcommandToken(token?: string): boolean {
|
export function isCursorSubcommandToken(token?: string): boolean {
|
||||||
return (
|
return (
|
||||||
Boolean(token) && CURSOR_SUBCOMMANDS.includes(token as (typeof CURSOR_SUBCOMMANDS)[number])
|
Boolean(token) && CURSOR_SUBCOMMANDS.includes(token as (typeof CURSOR_SUBCOMMANDS)[number])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function shouldUseCursorCliproxyShortcut(args: string[]): boolean {
|
||||||
|
if (args[0] !== 'cursor') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const token of args.slice(1)) {
|
||||||
|
if (token === '--') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (CURSOR_CLIPROXY_SHORTCUT_FLAGS.has(token)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!token.startsWith('-')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -99,6 +99,20 @@ describe('npm CLI', () => {
|
|||||||
assert(output.includes('Cursor Live Probe'), 'Should render the cursor probe command output');
|
assert(output.includes('Cursor Live Probe'), 'Should render the cursor probe command output');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('routes gitlab --help to provider shortcut help instead of starting auth', function() {
|
||||||
|
const output = execSync(`bun "${srcCcsPath}" gitlab --help`, {
|
||||||
|
encoding: 'utf8',
|
||||||
|
timeout: 3000,
|
||||||
|
env: { ...process.env, CCS_HOME: testCcsHome }
|
||||||
|
});
|
||||||
|
|
||||||
|
assert(output.includes('CCS gitlab Shortcut Help'), 'Should render provider shortcut help');
|
||||||
|
assert(output.includes('--gitlab-token-login'), 'Should document canonical GitLab PAT flag');
|
||||||
|
assert(output.includes('--token-login'), 'Should document legacy GitLab PAT alias');
|
||||||
|
assert(output.includes('--gitlab-url <url>'), 'Should document self-hosted GitLab URL flag');
|
||||||
|
assert(!output.includes('Starting GitLab Duo OAuth'), 'Should not start OAuth when help is requested');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Profile handling', () => {
|
describe('Profile handling', () => {
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ describe('help command parity', () => {
|
|||||||
expect(rendered.includes('gitlab')).toBe(true);
|
expect(rendered.includes('gitlab')).toBe(true);
|
||||||
expect(rendered.includes('codebuddy')).toBe(true);
|
expect(rendered.includes('codebuddy')).toBe(true);
|
||||||
expect(rendered.includes('kilo')).toBe(true);
|
expect(rendered.includes('kilo')).toBe(true);
|
||||||
|
expect(rendered.includes('--gitlab-token-login')).toBe(true);
|
||||||
|
expect(rendered.includes('--token-login')).toBe(true);
|
||||||
|
expect(rendered.includes('--gitlab-url <url>')).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('kiro topic documents IDC and callback flags', async () => {
|
test('kiro topic documents IDC and callback flags', async () => {
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { describe, expect, it } from 'bun:test';
|
||||||
|
import { shouldUseCursorCliproxyShortcut } from '../../../src/cursor/constants';
|
||||||
|
|
||||||
|
describe('cursor CLIProxy shortcut routing', () => {
|
||||||
|
it('accepts shortcut flags after leading generic flags', () => {
|
||||||
|
expect(shouldUseCursorCliproxyShortcut(['cursor', '--auth'])).toBe(true);
|
||||||
|
expect(shouldUseCursorCliproxyShortcut(['cursor', '--verbose', '--auth'])).toBe(true);
|
||||||
|
expect(shouldUseCursorCliproxyShortcut(['cursor', '-v', '--accounts'])).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('stops scanning once a positional legacy runtime argument appears', () => {
|
||||||
|
expect(shouldUseCursorCliproxyShortcut(['cursor', 'write', '--auth'])).toBe(false);
|
||||||
|
expect(shouldUseCursorCliproxyShortcut(['cursor', 'status'])).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user