import { spawnSync } from 'node:child_process'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { describe, expect, it } from 'vitest'; const testDir = path.dirname(fileURLToPath(import.meta.url)); const repoRoot = path.resolve(testDir, '../..'); const cliEntry = path.join(repoRoot, 'src/cli/index.ts'); function runHelp(command: string) { return spawnSync(process.execPath, ['--import', 'tsx', cliEntry, command, '--help'], { cwd: repoRoot, encoding: 'utf8', }); } describe('CLI help surface', () => { it('query help keeps advanced search options without importing analyze deps', () => { const result = runHelp('query'); expect(result.status).toBe(0); expect(result.stdout).toContain('--context '); expect(result.stdout).toContain('--goal '); expect(result.stdout).toContain('--content'); expect(result.stderr).not.toContain('tree-sitter-kotlin'); }); it('context help keeps optional name and disambiguation flags', () => { const result = runHelp('context'); expect(result.status).toBe(0); expect(result.stdout).toContain('context [options] [name]'); expect(result.stdout).toContain('--uid '); expect(result.stdout).toContain('--file '); }); it('impact help keeps repo and include-tests flags', () => { const result = runHelp('impact'); expect(result.status).toBe(0); expect(result.stdout).toContain('--depth '); expect(result.stdout).toContain('--include-tests'); expect(result.stdout).toContain('--repo '); }); it('detect-changes help exposes compare scope and base-ref flags', () => { const result = runHelp('detect-changes'); expect(result.status).toBe(0); expect(result.stdout).toContain('gitnexus detect-changes|detect_changes [options]'); expect(result.stdout).toContain('--scope '); expect(result.stdout).toContain('--base-ref '); expect(result.stdout).toContain('--repo '); }); it('wiki help shows provider, review, and verbose flags', () => { const result = runHelp('wiki'); expect(result.status).toBe(0); expect(result.stdout).toContain('--provider '); expect(result.stdout).toContain('--review'); expect(result.stdout).toContain('-v, --verbose'); expect(result.stdout).toContain('--model '); expect(result.stdout).toContain('--gist'); }); it('publish help names the registry, the token env var, and the opt-out behaviour', () => { const result = runHelp('publish'); expect(result.status).toBe(0); expect(result.stdout).toContain('--id '); expect(result.stdout).toContain('--skip-git'); // Discoverability contract: a contributor scanning `--help` must see // (a) which registry this dispatches to, and (b) the env var that // gates the opt-in. Both are part of the no-token contract. expect(result.stdout).toContain('understand-quickly'); expect(result.stdout).toContain('UNDERSTAND_QUICKLY_TOKEN'); }); });