import { tap, expect } from '@git.zone/tstest/tapbundle'; import * as path from 'path'; import { IterativeContextBuilder } from '../ts/context/iterative-context-builder.js'; import type { IIterativeConfig, TaskType } from '../ts/context/types.js'; import * as qenv from '@push.rocks/qenv'; // Test project directory const testProjectRoot = path.join(process.cwd()); // Helper to check if OPENAI_TOKEN is available async function hasOpenAIToken(): Promise { try { const qenvInstance = new qenv.Qenv(); const token = await qenvInstance.getEnvVarOnDemand('OPENAI_TOKEN'); return !!token; } catch (error) { return false; } } tap.test('IterativeContextBuilder should create instance with default config', async () => { const builder = new IterativeContextBuilder(testProjectRoot); expect(builder).toBeInstanceOf(IterativeContextBuilder); }); tap.test('IterativeContextBuilder should create instance with custom config', async () => { const customConfig: Partial = { maxIterations: 3, firstPassFileLimit: 5, subsequentPassFileLimit: 3, temperature: 0.5, model: 'gpt-4', }; const builder = new IterativeContextBuilder(testProjectRoot, customConfig); expect(builder).toBeInstanceOf(IterativeContextBuilder); }); tap.test('IterativeContextBuilder should initialize successfully', async () => { if (!(await hasOpenAIToken())) { console.log('⚠️ Skipping initialization test - OPENAI_TOKEN not available'); return; } const builder = new IterativeContextBuilder(testProjectRoot); await builder.initialize(); // If we get here without error, initialization succeeded expect(true).toEqual(true); }); tap.test('IterativeContextBuilder should build context iteratively for readme task', async () => { if (!(await hasOpenAIToken())) { console.log('⚠️ Skipping iterative build test - OPENAI_TOKEN not available'); return; } const builder = new IterativeContextBuilder(testProjectRoot, { maxIterations: 2, // Limit iterations for testing firstPassFileLimit: 3, subsequentPassFileLimit: 2, }); await builder.initialize(); const result = await builder.buildContextIteratively('readme'); // Verify result structure expect(result).toBeTypeOf('object'); expect(result.context).toBeTypeOf('string'); expect(result.context.length).toBeGreaterThan(0); expect(result.tokenCount).toBeTypeOf('number'); expect(result.tokenCount).toBeGreaterThan(0); expect(result.includedFiles).toBeInstanceOf(Array); expect(result.includedFiles.length).toBeGreaterThan(0); expect(result.iterationCount).toBeTypeOf('number'); expect(result.iterationCount).toBeGreaterThan(0); expect(result.iterationCount).toBeLessThanOrEqual(2); expect(result.iterations).toBeInstanceOf(Array); expect(result.iterations.length).toEqual(result.iterationCount); expect(result.apiCallCount).toBeTypeOf('number'); expect(result.apiCallCount).toBeGreaterThan(0); expect(result.totalDuration).toBeTypeOf('number'); expect(result.totalDuration).toBeGreaterThan(0); // Verify iteration structure for (const iteration of result.iterations) { expect(iteration.iteration).toBeTypeOf('number'); expect(iteration.filesLoaded).toBeInstanceOf(Array); expect(iteration.tokensUsed).toBeTypeOf('number'); expect(iteration.totalTokensUsed).toBeTypeOf('number'); expect(iteration.decision).toBeTypeOf('object'); expect(iteration.duration).toBeTypeOf('number'); } console.log(`✅ Iterative context build completed:`); console.log(` Iterations: ${result.iterationCount}`); console.log(` Files: ${result.includedFiles.length}`); console.log(` Tokens: ${result.tokenCount}`); console.log(` API calls: ${result.apiCallCount}`); console.log(` Duration: ${(result.totalDuration / 1000).toFixed(2)}s`); }); tap.test('IterativeContextBuilder should respect token budget', async () => { if (!(await hasOpenAIToken())) { console.log('⚠️ Skipping token budget test - OPENAI_TOKEN not available'); return; } const builder = new IterativeContextBuilder(testProjectRoot, { maxIterations: 5, }); await builder.initialize(); const result = await builder.buildContextIteratively('description'); // Token count should not exceed budget significantly (allow 5% margin for safety) const configManager = (await import('../ts/context/config-manager.js')).ConfigManager.getInstance(); const maxTokens = configManager.getMaxTokens(); expect(result.tokenCount).toBeLessThanOrEqual(maxTokens * 1.05); console.log(`✅ Token budget respected: ${result.tokenCount}/${maxTokens}`); }); tap.test('IterativeContextBuilder should work with different task types', async () => { if (!(await hasOpenAIToken())) { console.log('⚠️ Skipping task types test - OPENAI_TOKEN not available'); return; } const taskTypes: TaskType[] = ['readme', 'description', 'commit']; for (const taskType of taskTypes) { const builder = new IterativeContextBuilder(testProjectRoot, { maxIterations: 2, firstPassFileLimit: 2, }); await builder.initialize(); const result = await builder.buildContextIteratively(taskType); expect(result.includedFiles.length).toBeGreaterThan(0); console.log(`✅ ${taskType}: ${result.includedFiles.length} files, ${result.tokenCount} tokens`); } }); export default tap.start();