diff --git a/packages/mukti-cli/src/index.ts b/packages/mukti-cli/src/index.ts index 15ffc247..05cf209e 100644 --- a/packages/mukti-cli/src/index.ts +++ b/packages/mukti-cli/src/index.ts @@ -92,7 +92,7 @@ const HELP = ` --api-port Port for the API (default ${DEFAULT_API_PORT}) --data-dir Where to keep the database and logs (default ~/.mukti, or $MUKTI_HOME) - --provider AI CLI to run on: ${SUPPORTED_PROVIDERS.map((p) => p.id).join(' or ')} + --provider AI CLI to run on: ${SUPPORTED_PROVIDERS.map((p) => `${p.id} (${p.binary})`).join(' or ')} (default: your saved choice, else $AI_PROVIDER, else whichever CLI is ready) --save Save --provider as your default for later runs diff --git a/packages/mukti-cli/src/launcher/__tests__/providers.test.ts b/packages/mukti-cli/src/launcher/__tests__/providers.test.ts index e039625e..c22f8fe2 100644 --- a/packages/mukti-cli/src/launcher/__tests__/providers.test.ts +++ b/packages/mukti-cli/src/launcher/__tests__/providers.test.ts @@ -143,11 +143,27 @@ test('choosing again without a terminal asks for the flag instead', async () => }); test('an unknown explicit provider is refused', async () => { - assert.deepEqual(await resolve({ explicit: 'agy', run: scripted(BOTH_READY_ANSWERS).run }), { - kind: 'unsupported', - source: 'option', - value: 'agy', - }); + assert.deepEqual( + await resolve({ explicit: 'gemini-cli', run: scripted(BOTH_READY_ANSWERS).run }), + { + kind: 'unsupported', + source: 'option', + value: 'gemini-cli', + } + ); +}); + +test('a provider can be named by the command it runs as', async () => { + for (const [name, id] of [ + ['agy', 'antigravity'], + ['claude', 'claude-code'], + ]) { + const explicit = await resolve({ explicit: name, run: scripted(BOTH_READY_ANSWERS).run }); + assert.equal(explicit.kind === 'chosen' && explicit.provider.id, id); + + const env = await resolve({ env: name, run: scripted(BOTH_READY_ANSWERS).run }); + assert.equal(env.kind === 'chosen' && env.provider.id, id); + } }); test('an unknown AI_PROVIDER is refused', async () => { @@ -251,6 +267,7 @@ test('an unsupported value is explained with every supported id', () => { assert.match(message, /gemini-cli/); for (const provider of SUPPORTED_PROVIDERS) { assert.ok(message.includes(provider.id)); + assert.ok(message.includes(provider.binary)); } }); diff --git a/packages/mukti-cli/src/launcher/providers.ts b/packages/mukti-cli/src/launcher/providers.ts index 453b25e3..6286c4aa 100644 --- a/packages/mukti-cli/src/launcher/providers.ts +++ b/packages/mukti-cli/src/launcher/providers.ts @@ -37,7 +37,7 @@ export interface LocalCliProvider { * leaves on their machine, told before they discover it. */ readonly disclosure?: string; - /** The `AI_PROVIDER` value, and what `--provider` accepts. */ + /** The `AI_PROVIDER` value, and what `--provider` accepts alongside {@link LocalCliProvider.binary}. */ readonly id: LocalCliProviderId; readonly installRemediation: string; /** Signed in and usable. Must not consume model tokens. */ @@ -236,7 +236,7 @@ export function describeUnsupportedProvider(options: { readonly value: string; }): string { const origin = options.source === 'option' ? '--provider' : 'AI_PROVIDER'; - const ids = SUPPORTED_PROVIDERS.map((p) => p.id).join(', '); + const ids = SUPPORTED_PROVIDERS.map((p) => `${p.id} (or ${p.binary})`).join(', '); return `${origin} is "${options.value}", which is not a supported local AI CLI. Use one of: ${ids}.`; } @@ -254,8 +254,12 @@ export async function probeProvider( return { provider, readiness: signedIn ? 'ready' : 'signed-out', version }; } +/** + * The provider a `--provider` or `AI_PROVIDER` value names: its id, or the + * command it runs as (`agy`, `claude`) — the name people know the CLI by. + */ export function providerById(id: string): LocalCliProvider | undefined { - return SUPPORTED_PROVIDERS.find((p) => p.id === id); + return SUPPORTED_PROVIDERS.find((p) => p.id === id || p.binary === id); } /**