/** * Tests for headless-executor CLI flag passthrough feature * Covers: duplicate flag filtering, undefined checks, flag construction */ import { describe, it, expect } from 'bun:test'; describe('HeadlessExecutor flag construction', () => { // Test the flag construction logic by simulating the filtering behavior // Since HeadlessExecutor.execute() spawns a process, we test the logic directly describe('Duplicate flag filtering', () => { function filterExtraArgs(extraArgs: string[], explicitFlags: Set): string[] { const filteredExtras: string[] = []; for (let i = 0; i < extraArgs.length; i++) { if (explicitFlags.has(extraArgs[i])) { // Skip this flag and its value (next element) if (i + 1 < extraArgs.length && !extraArgs[i + 1].startsWith('-')) { i++; // Skip value too } continue; } filteredExtras.push(extraArgs[i]); } return filteredExtras; } const explicitFlags = new Set(['--max-turns', '--fallback-model', '--agents', '--betas']); it('removes duplicate --max-turns from extraArgs', () => { const result = filterExtraArgs(['--max-turns', '10', '--verbose'], explicitFlags); expect(result).not.toContain('--max-turns'); expect(result).not.toContain('10'); expect(result).toContain('--verbose'); }); it('removes duplicate --fallback-model from extraArgs', () => { const result = filterExtraArgs(['--fallback-model', 'opus', '--debug'], explicitFlags); expect(result).not.toContain('--fallback-model'); expect(result).not.toContain('opus'); expect(result).toContain('--debug'); }); it('removes duplicate --agents from extraArgs', () => { const result = filterExtraArgs(['--agents', '{"x":1}', '--json'], explicitFlags); expect(result).not.toContain('--agents'); expect(result).not.toContain('{"x":1}'); expect(result).toContain('--json'); }); it('removes duplicate --betas from extraArgs', () => { const result = filterExtraArgs(['--betas', 'feature1', '--output', 'json'], explicitFlags); expect(result).not.toContain('--betas'); expect(result).not.toContain('feature1'); expect(result).toContain('--output'); expect(result).toContain('json'); }); it('handles flag at end of array without value', () => { const result = filterExtraArgs(['--verbose', '--max-turns'], explicitFlags); expect(result).toContain('--verbose'); expect(result).not.toContain('--max-turns'); }); it('handles flag with dash-prefixed next arg (not a value)', () => { const result = filterExtraArgs(['--max-turns', '--verbose'], explicitFlags); // --max-turns is filtered, but --verbose is kept because it starts with - expect(result).not.toContain('--max-turns'); expect(result).toContain('--verbose'); }); it('preserves unknown flags', () => { const result = filterExtraArgs(['--custom-flag', 'value', '--another'], explicitFlags); expect(result).toEqual(['--custom-flag', 'value', '--another']); }); it('handles empty array', () => { const result = filterExtraArgs([], explicitFlags); expect(result).toEqual([]); }); it('removes multiple duplicate flags', () => { const result = filterExtraArgs( ['--max-turns', '5', '--agents', '{}', '--fallback-model', 'sonnet'], explicitFlags ); expect(result).toEqual([]); }); }); describe('Flag undefined vs truthy checks', () => { // Simulate the flag construction logic function buildArgs(options: { maxTurns?: number; fallbackModel?: string; agents?: string; betas?: string; }): string[] { const args: string[] = []; const { maxTurns, fallbackModel, agents, betas } = options; if (maxTurns !== undefined && maxTurns > 0) { args.push('--max-turns', String(maxTurns)); } if (fallbackModel !== undefined && fallbackModel) { args.push('--fallback-model', fallbackModel); } if (agents !== undefined && agents) { args.push('--agents', agents); } if (betas !== undefined && betas) { args.push('--betas', betas); } return args; } it('handles all undefined options', () => { const args = buildArgs({}); expect(args).toEqual([]); }); it('handles maxTurns = 0 (should not add flag)', () => { const args = buildArgs({ maxTurns: 0 }); expect(args).toEqual([]); }); it('handles maxTurns > 0', () => { const args = buildArgs({ maxTurns: 10 }); expect(args).toEqual(['--max-turns', '10']); }); it('handles empty string fallbackModel (should not add flag)', () => { const args = buildArgs({ fallbackModel: '' }); expect(args).toEqual([]); }); it('handles valid fallbackModel', () => { const args = buildArgs({ fallbackModel: 'sonnet' }); expect(args).toEqual(['--fallback-model', 'sonnet']); }); it('handles empty string agents (should not add flag)', () => { const args = buildArgs({ agents: '' }); expect(args).toEqual([]); }); it('handles valid JSON agents', () => { const args = buildArgs({ agents: '{"name":"test"}' }); expect(args).toEqual(['--agents', '{"name":"test"}']); }); it('handles all valid options', () => { const args = buildArgs({ maxTurns: 5, fallbackModel: 'opus', agents: '{}', betas: 'feature1', }); expect(args).toContain('--max-turns'); expect(args).toContain('--fallback-model'); expect(args).toContain('--agents'); expect(args).toContain('--betas'); }); }); });