import { describe, it, expect, afterEach } from 'bun:test' import { mkdtempSync, rmSync } from 'fs' import { tmpdir } from 'os' import { readFileSync } from 'fs' import { join } from 'path' import { loadConfig } from '../src/bootstrap/loadConfig.js' describe('run command result presentation', () => { const source = readFileSync(join(import.meta.dir, '../src/commands/run.ts'), 'utf-8') it('prefers WorkerResult.changed_files over recent filesystem scan', () => { expect(source).toContain('get_result_for_task') expect(source).toContain('workerResult?.changed_files') }) it('filters .air internals from produced files', () => { expect(source).toContain("file.startsWith('.air/')") expect(source).toContain("e.startsWith('.')") }) it('routes destructive confirmation before slash/main dispatch', () => { expect(source).toContain('pendingConfirmation') expect(source).toContain('handle_confirmation(true)') expect(source).toContain('handle_confirmation(false)') expect(source).toContain('No task was created') }) }) describe('ask command architecture boundary', () => { const source = readFileSync(join(import.meta.dir, '../src/commands/ask.ts'), 'utf-8') it('dispatches delegate work through Scheduler and WorkerManager', () => { expect(source).toContain('app.scheduler.create_tasks') expect(source).toContain('app.scheduler.run_until_idle') expect(source).toContain('app.worker_manager.get_result_for_task') }) it('does not implement an inline LLM-to-tool loop', () => { expect(source).not.toContain('parseToolCalls') expect(source).not.toContain('toolRegistry.call') expect(source).not.toContain('while (turn <') }) }) describe('project root configuration', () => { const created: string[] = [] afterEach(() => { delete process.env.AIRCODING_PROJECT_ROOT for (const dir of created.splice(0)) rmSync(dir, { recursive: true, force: true }) }) it('uses AIRCODING_PROJECT_ROOT when no explicit project path is passed', () => { const projectRoot = mkdtempSync(join(tmpdir(), 'air-load-config-')) created.push(projectRoot) process.env.AIRCODING_PROJECT_ROOT = projectRoot expect(loadConfig().project_root).toBe(projectRoot) }) it('explicit project path wins over AIRCODING_PROJECT_ROOT', () => { const envRoot = mkdtempSync(join(tmpdir(), 'air-load-config-env-')) const explicitRoot = mkdtempSync(join(tmpdir(), 'air-load-config-explicit-')) created.push(envRoot, explicitRoot) process.env.AIRCODING_PROJECT_ROOT = envRoot expect(loadConfig(explicitRoot).project_root).toBe(explicitRoot) }) })