feat(cli): add agent picker and remove Claude default

Separate top-level help and version flags from agent arguments. Require explicit agents in scripts and preserve command argument boundaries.

Validation: bun typecheck, bun run test, targeted runner integration tests, and PTY/source/compiled argv smoke checks.
This commit is contained in:
weishu
2026-09-12 12:03:59 +08:00
parent 23e1cdde78
commit fc2fdfc25b
22 changed files with 687 additions and 147 deletions
+56
View File
@@ -0,0 +1,56 @@
import { basename } from 'node:path'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { normalizeCliArgs } from './cliArgs'
describe('CLI argv normalization', () => {
const exec = process.execPath
const entrypoint = '/workspace/cli/src/index.ts'
afterEach(() => { vi.unstubAllGlobals() })
it.each([
[exec],
[basename(exec)],
[exec, entrypoint],
['bun', entrypoint],
[exec, entrypoint, '--']
])('strips the runtime wrapper %j without consuming command arguments', (...prefix) => {
const args = ['codex', '--', '--help', '--version', 'prompt with spaces']
expect(normalizeCliArgs([...prefix, ...args])).toEqual(args)
})
it('preserves a separator in already normalized arguments', () => {
expect(normalizeCliArgs(['claude', '--', '--model', 'literal']))
.toEqual(['claude', '--', '--model', 'literal'])
expect(normalizeCliArgs(['--', '--help'])).toEqual(['--', '--help'])
})
it('preserves runner handoff arguments for compiled and source entrypoints', () => {
const args = ['runner', 'start-sync', '--workspace-root', '/my project']
expect(normalizeCliArgs([exec, ...args])).toEqual(args)
expect(normalizeCliArgs([exec, entrypoint, ...args])).toEqual(args)
})
it('returns an empty command for bare invocations', () => {
expect(normalizeCliArgs([])).toEqual([])
expect(normalizeCliArgs([exec])).toEqual([])
expect(normalizeCliArgs([exec, entrypoint])).toEqual([])
})
it('preserves filenames used as prompts instead of treating them as entrypoints', () => {
vi.stubGlobal('Bun', { main: entrypoint })
expect(normalizeCliArgs([exec, entrypoint, 'prompt.ts', 'another.js']))
.toEqual(['prompt.ts', 'another.js'])
expect(normalizeCliArgs(['prompt.ts'])).toEqual(['prompt.ts'])
})
it('handles Bun virtual entrypoints and compiled process argv', () => {
const main = '/$bunfs/root/hapi'
vi.stubGlobal('Bun', { main })
expect(normalizeCliArgs(['bun', main, 'codex', '--', '--help']))
.toEqual(['codex', '--', '--help'])
expect(normalizeCliArgs(['bun', main, 'prompt.ts'])).toEqual(['prompt.ts'])
expect(normalizeCliArgs([exec, 'prompt.ts'])).toEqual(['prompt.ts'])
expect(normalizeCliArgs(['bun', main])).toEqual([])
})
})