@git.zone/tsdoc 1.6.1 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,495 @@
1
+ import * as plugins from '../plugins.js';
2
+ import * as fs from 'fs';
3
+ import { logger } from '../logging.js';
4
+ import type {
5
+ TaskType,
6
+ IFileMetadata,
7
+ IFileInfo,
8
+ IIterativeContextResult,
9
+ IIterationState,
10
+ IFileSelectionDecision,
11
+ IContextSufficiencyDecision,
12
+ IIterativeConfig,
13
+ } from './types.js';
14
+ import { LazyFileLoader } from './lazy-file-loader.js';
15
+ import { ContextCache } from './context-cache.js';
16
+ import { ContextAnalyzer } from './context-analyzer.js';
17
+ import { ConfigManager } from './config-manager.js';
18
+
19
+ /**
20
+ * Iterative context builder that uses AI to intelligently select files
21
+ * across multiple iterations until sufficient context is gathered
22
+ */
23
+ export class IterativeContextBuilder {
24
+ private projectRoot: string;
25
+ private lazyLoader: LazyFileLoader;
26
+ private cache: ContextCache;
27
+ private analyzer: ContextAnalyzer;
28
+ private config: Required<IIterativeConfig>;
29
+ private tokenBudget: number = 190000;
30
+ private openaiInstance: plugins.smartai.OpenAiProvider;
31
+ private externalOpenaiInstance?: plugins.smartai.OpenAiProvider;
32
+
33
+ /**
34
+ * Creates a new IterativeContextBuilder
35
+ * @param projectRoot - Root directory of the project
36
+ * @param config - Iterative configuration
37
+ * @param openaiInstance - Optional pre-configured OpenAI provider instance
38
+ */
39
+ constructor(
40
+ projectRoot: string,
41
+ config?: Partial<IIterativeConfig>,
42
+ openaiInstance?: plugins.smartai.OpenAiProvider
43
+ ) {
44
+ this.projectRoot = projectRoot;
45
+ this.lazyLoader = new LazyFileLoader(projectRoot);
46
+ this.cache = new ContextCache(projectRoot);
47
+ this.analyzer = new ContextAnalyzer(projectRoot);
48
+ this.externalOpenaiInstance = openaiInstance;
49
+
50
+ // Default configuration
51
+ this.config = {
52
+ maxIterations: config?.maxIterations ?? 5,
53
+ firstPassFileLimit: config?.firstPassFileLimit ?? 10,
54
+ subsequentPassFileLimit: config?.subsequentPassFileLimit ?? 5,
55
+ temperature: config?.temperature ?? 0.3,
56
+ model: config?.model ?? 'gpt-4-turbo-preview',
57
+ };
58
+
59
+ }
60
+
61
+ /**
62
+ * Initialize the builder
63
+ */
64
+ public async initialize(): Promise<void> {
65
+ await this.cache.init();
66
+ const configManager = ConfigManager.getInstance();
67
+ await configManager.initialize(this.projectRoot);
68
+ this.tokenBudget = configManager.getMaxTokens();
69
+
70
+ // Use external OpenAI instance if provided, otherwise create a new one
71
+ if (this.externalOpenaiInstance) {
72
+ this.openaiInstance = this.externalOpenaiInstance;
73
+ } else {
74
+ // Initialize OpenAI instance from environment
75
+ const qenvInstance = new plugins.qenv.Qenv();
76
+ const openaiToken = await qenvInstance.getEnvVarOnDemand('OPENAI_TOKEN');
77
+ if (!openaiToken) {
78
+ throw new Error('OPENAI_TOKEN environment variable is required for iterative context building');
79
+ }
80
+ this.openaiInstance = new plugins.smartai.OpenAiProvider({
81
+ openaiToken,
82
+ });
83
+ await this.openaiInstance.start();
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Build context iteratively using AI decision making
89
+ * @param taskType - Type of task being performed
90
+ * @param additionalContext - Optional additional context (e.g., git diff for commit tasks)
91
+ * @returns Complete iterative context result
92
+ */
93
+ public async buildContextIteratively(taskType: TaskType, additionalContext?: string): Promise<IIterativeContextResult> {
94
+ const startTime = Date.now();
95
+ logger.log('info', '🤖 Starting iterative context building...');
96
+ logger.log('info', ` Task: ${taskType}, Budget: ${this.tokenBudget} tokens, Max iterations: ${this.config.maxIterations}`);
97
+
98
+ // Phase 1: Scan project files for metadata
99
+ logger.log('info', '📋 Scanning project files...');
100
+ const metadata = await this.scanProjectFiles(taskType);
101
+ const totalEstimatedTokens = metadata.reduce((sum, m) => sum + m.estimatedTokens, 0);
102
+ logger.log('info', ` Found ${metadata.length} files (~${totalEstimatedTokens} estimated tokens)`);
103
+
104
+ // Phase 2: Analyze files for initial prioritization
105
+ logger.log('info', '🔍 Analyzing file dependencies and importance...');
106
+ const analysis = await this.analyzer.analyze(metadata, taskType, []);
107
+ logger.log('info', ` Analysis complete in ${analysis.analysisDuration}ms`);
108
+
109
+ // Track state across iterations
110
+ const iterations: IIterationState[] = [];
111
+ let totalTokensUsed = 0;
112
+ let apiCallCount = 0;
113
+ let loadedContent = '';
114
+ const includedFiles: IFileInfo[] = [];
115
+
116
+ // If additional context (e.g., git diff) is provided, prepend it
117
+ if (additionalContext) {
118
+ const diffSection = `
119
+ ====== GIT DIFF ======
120
+
121
+ ${additionalContext}
122
+
123
+ ====== END OF GIT DIFF ======
124
+ `;
125
+ loadedContent = diffSection;
126
+ const diffTokens = this.countTokens(diffSection);
127
+ totalTokensUsed += diffTokens;
128
+ logger.log('info', `📝 Added git diff to context (${diffTokens} tokens)`);
129
+ }
130
+
131
+ // Phase 3: Iterative file selection and loading
132
+ for (let iteration = 1; iteration <= this.config.maxIterations; iteration++) {
133
+ const iterationStart = Date.now();
134
+ logger.log('info', `\n🤔 Iteration ${iteration}/${this.config.maxIterations}: Asking AI which files to examine...`);
135
+
136
+ const remainingBudget = this.tokenBudget - totalTokensUsed;
137
+ logger.log('info', ` Token budget remaining: ${remainingBudget}/${this.tokenBudget} (${Math.round((remainingBudget / this.tokenBudget) * 100)}%)`);
138
+
139
+ // Get AI decision on which files to load
140
+ const decision = await this.getFileSelectionDecision(
141
+ metadata,
142
+ analysis.files.slice(0, 30), // Top 30 files by importance
143
+ taskType,
144
+ iteration,
145
+ totalTokensUsed,
146
+ remainingBudget,
147
+ loadedContent
148
+ );
149
+ apiCallCount++;
150
+
151
+ logger.log('info', ` AI reasoning: ${decision.reasoning}`);
152
+ logger.log('info', ` AI requested ${decision.filesToLoad.length} files`);
153
+
154
+ // Load requested files
155
+ const iterationFiles: IFileInfo[] = [];
156
+ let iterationTokens = 0;
157
+
158
+ if (decision.filesToLoad.length > 0) {
159
+ logger.log('info', '📥 Loading requested files...');
160
+
161
+ for (const filePath of decision.filesToLoad) {
162
+ try {
163
+ const fileInfo = await this.loadFile(filePath);
164
+ if (totalTokensUsed + fileInfo.tokenCount! <= this.tokenBudget) {
165
+ const formattedFile = this.formatFileForContext(fileInfo);
166
+ loadedContent += formattedFile;
167
+ includedFiles.push(fileInfo);
168
+ iterationFiles.push(fileInfo);
169
+ iterationTokens += fileInfo.tokenCount!;
170
+ totalTokensUsed += fileInfo.tokenCount!;
171
+
172
+ logger.log('info', ` ✓ ${fileInfo.relativePath} (${fileInfo.tokenCount} tokens)`);
173
+ } else {
174
+ logger.log('warn', ` ✗ ${fileInfo.relativePath} - would exceed budget, skipping`);
175
+ }
176
+ } catch (error) {
177
+ logger.log('warn', ` ✗ Failed to load ${filePath}: ${error.message}`);
178
+ }
179
+ }
180
+ }
181
+
182
+ // Record iteration state
183
+ const iterationDuration = Date.now() - iterationStart;
184
+ iterations.push({
185
+ iteration,
186
+ filesLoaded: iterationFiles,
187
+ tokensUsed: iterationTokens,
188
+ totalTokensUsed,
189
+ decision,
190
+ duration: iterationDuration,
191
+ });
192
+
193
+ logger.log('info', ` Iteration ${iteration} complete: ${iterationFiles.length} files loaded, ${iterationTokens} tokens used`);
194
+
195
+ // Check if we should continue
196
+ if (totalTokensUsed >= this.tokenBudget * 0.95) {
197
+ logger.log('warn', '⚠️ Approaching token budget limit, stopping iterations');
198
+ break;
199
+ }
200
+
201
+ // Ask AI if context is sufficient
202
+ if (iteration < this.config.maxIterations) {
203
+ logger.log('info', '🤔 Asking AI if context is sufficient...');
204
+ const sufficiencyDecision = await this.evaluateContextSufficiency(
205
+ loadedContent,
206
+ taskType,
207
+ iteration,
208
+ totalTokensUsed,
209
+ remainingBudget - iterationTokens
210
+ );
211
+ apiCallCount++;
212
+
213
+ logger.log('info', ` AI decision: ${sufficiencyDecision.sufficient ? '✅ SUFFICIENT' : '⏭️ NEEDS MORE'}`);
214
+ logger.log('info', ` Reasoning: ${sufficiencyDecision.reasoning}`);
215
+
216
+ if (sufficiencyDecision.sufficient) {
217
+ logger.log('ok', '✅ Context building complete - AI determined context is sufficient');
218
+ break;
219
+ }
220
+ }
221
+ }
222
+
223
+ const totalDuration = Date.now() - startTime;
224
+ logger.log('ok', `\n✅ Iterative context building complete!`);
225
+ logger.log('info', ` Files included: ${includedFiles.length}`);
226
+ logger.log('info', ` Token usage: ${totalTokensUsed}/${this.tokenBudget} (${Math.round((totalTokensUsed / this.tokenBudget) * 100)}%)`);
227
+ logger.log('info', ` Iterations: ${iterations.length}, API calls: ${apiCallCount}`);
228
+ logger.log('info', ` Total duration: ${(totalDuration / 1000).toFixed(2)}s`);
229
+
230
+ return {
231
+ context: loadedContent,
232
+ tokenCount: totalTokensUsed,
233
+ includedFiles,
234
+ trimmedFiles: [],
235
+ excludedFiles: [],
236
+ tokenSavings: 0,
237
+ iterationCount: iterations.length,
238
+ iterations,
239
+ apiCallCount,
240
+ totalDuration,
241
+ };
242
+ }
243
+
244
+ /**
245
+ * Scan project files based on task type
246
+ */
247
+ private async scanProjectFiles(taskType: TaskType): Promise<IFileMetadata[]> {
248
+ const configManager = ConfigManager.getInstance();
249
+ const taskConfig = configManager.getTaskConfig(taskType);
250
+
251
+ const includeGlobs = taskConfig?.includePaths?.map(p => `${p}/**/*.ts`) || [
252
+ 'ts/**/*.ts',
253
+ 'ts*/**/*.ts'
254
+ ];
255
+
256
+ const configGlobs = [
257
+ 'package.json',
258
+ 'readme.md',
259
+ 'readme.hints.md',
260
+ 'npmextra.json'
261
+ ];
262
+
263
+ return await this.lazyLoader.scanFiles([...configGlobs, ...includeGlobs]);
264
+ }
265
+
266
+ /**
267
+ * Get AI decision on which files to load
268
+ */
269
+ private async getFileSelectionDecision(
270
+ allMetadata: IFileMetadata[],
271
+ analyzedFiles: any[],
272
+ taskType: TaskType,
273
+ iteration: number,
274
+ tokensUsed: number,
275
+ remainingBudget: number,
276
+ loadedContent: string
277
+ ): Promise<IFileSelectionDecision> {
278
+ const isFirstIteration = iteration === 1;
279
+ const fileLimit = isFirstIteration
280
+ ? this.config.firstPassFileLimit
281
+ : this.config.subsequentPassFileLimit;
282
+
283
+ const systemPrompt = this.buildFileSelectionPrompt(
284
+ allMetadata,
285
+ analyzedFiles,
286
+ taskType,
287
+ iteration,
288
+ tokensUsed,
289
+ remainingBudget,
290
+ loadedContent,
291
+ fileLimit
292
+ );
293
+
294
+ const response = await this.openaiInstance.chat({
295
+ systemMessage: `You are an AI assistant that helps select the most relevant files for code analysis.
296
+ You must respond ONLY with valid JSON that can be parsed with JSON.parse().
297
+ Do not wrap the JSON in markdown code blocks or add any other text.`,
298
+ userMessage: systemPrompt,
299
+ messageHistory: [],
300
+ });
301
+
302
+ // Parse JSON response, handling potential markdown formatting
303
+ const content = response.message.replace('```json', '').replace('```', '').trim();
304
+ const parsed = JSON.parse(content);
305
+
306
+ return {
307
+ reasoning: parsed.reasoning || 'No reasoning provided',
308
+ filesToLoad: parsed.files_to_load || [],
309
+ estimatedTokensNeeded: parsed.estimated_tokens_needed,
310
+ };
311
+ }
312
+
313
+ /**
314
+ * Build prompt for file selection
315
+ */
316
+ private buildFileSelectionPrompt(
317
+ metadata: IFileMetadata[],
318
+ analyzedFiles: any[],
319
+ taskType: TaskType,
320
+ iteration: number,
321
+ tokensUsed: number,
322
+ remainingBudget: number,
323
+ loadedContent: string,
324
+ fileLimit: number
325
+ ): string {
326
+ const taskDescriptions = {
327
+ readme: 'generating a comprehensive README that explains the project\'s purpose, features, and API',
328
+ commit: 'analyzing code changes to generate an intelligent commit message',
329
+ description: 'generating a concise project description for package.json',
330
+ };
331
+
332
+ const alreadyLoadedFiles = loadedContent
333
+ ? loadedContent.split('\n======').slice(1).map(section => {
334
+ const match = section.match(/START OF FILE (.+?) ======/);
335
+ return match ? match[1] : '';
336
+ }).filter(Boolean)
337
+ : [];
338
+
339
+ const availableFiles = metadata
340
+ .filter(m => !alreadyLoadedFiles.includes(m.relativePath))
341
+ .map(m => {
342
+ const analysis = analyzedFiles.find(a => a.path === m.path);
343
+ return `- ${m.relativePath} (${m.size} bytes, ~${m.estimatedTokens} tokens${analysis ? `, importance: ${analysis.importanceScore.toFixed(2)}` : ''})`;
344
+ })
345
+ .join('\n');
346
+
347
+ return `You are building context for ${taskDescriptions[taskType]} in a TypeScript project.
348
+
349
+ ITERATION: ${iteration}
350
+ TOKENS USED: ${tokensUsed}/${tokensUsed + remainingBudget} (${Math.round((tokensUsed / (tokensUsed + remainingBudget)) * 100)}%)
351
+ REMAINING BUDGET: ${remainingBudget} tokens
352
+
353
+ ${alreadyLoadedFiles.length > 0 ? `FILES ALREADY LOADED:\n${alreadyLoadedFiles.map(f => `- ${f}`).join('\n')}\n\n` : ''}AVAILABLE FILES (not yet loaded):
354
+ ${availableFiles}
355
+
356
+ Your task: Select up to ${fileLimit} files that will give you the MOST understanding for this ${taskType} task.
357
+
358
+ ${iteration === 1 ? `This is the FIRST iteration. Focus on:
359
+ - Main entry points (index.ts, main exports)
360
+ - Core classes and interfaces
361
+ - Package configuration
362
+ ` : `This is iteration ${iteration}. You've already seen some files. Now focus on:
363
+ - Files that complement what you've already loaded
364
+ - Dependencies of already-loaded files
365
+ - Missing pieces for complete understanding
366
+ `}
367
+
368
+ Consider:
369
+ 1. File importance scores (if provided)
370
+ 2. File paths (ts/index.ts is likely more important than ts/internal/utils.ts)
371
+ 3. Token efficiency (prefer smaller files if they provide good information)
372
+ 4. Remaining budget (${remainingBudget} tokens)
373
+
374
+ Respond in JSON format:
375
+ {
376
+ "reasoning": "Brief explanation of why you're selecting these files",
377
+ "files_to_load": ["path/to/file1.ts", "path/to/file2.ts"],
378
+ "estimated_tokens_needed": 15000
379
+ }`;
380
+ }
381
+
382
+ /**
383
+ * Evaluate if current context is sufficient
384
+ */
385
+ private async evaluateContextSufficiency(
386
+ loadedContent: string,
387
+ taskType: TaskType,
388
+ iteration: number,
389
+ tokensUsed: number,
390
+ remainingBudget: number
391
+ ): Promise<IContextSufficiencyDecision> {
392
+ const prompt = `You have been building context for a ${taskType} task across ${iteration} iterations.
393
+
394
+ CURRENT STATE:
395
+ - Tokens used: ${tokensUsed}
396
+ - Remaining budget: ${remainingBudget}
397
+ - Files loaded: ${loadedContent.split('\n======').length - 1}
398
+
399
+ CONTEXT SO FAR:
400
+ ${loadedContent.substring(0, 3000)}... (truncated for brevity)
401
+
402
+ Question: Do you have SUFFICIENT context to successfully complete the ${taskType} task?
403
+
404
+ Consider:
405
+ - For README: Do you understand the project's purpose, main features, API surface, and usage patterns?
406
+ - For commit: Do you understand what changed and why?
407
+ - For description: Do you understand the project's core value proposition?
408
+
409
+ Respond in JSON format:
410
+ {
411
+ "sufficient": true or false,
412
+ "reasoning": "Detailed explanation of your decision"
413
+ }`;
414
+
415
+ const response = await this.openaiInstance.chat({
416
+ systemMessage: `You are an AI assistant that evaluates whether gathered context is sufficient for a task.
417
+ You must respond ONLY with valid JSON that can be parsed with JSON.parse().
418
+ Do not wrap the JSON in markdown code blocks or add any other text.`,
419
+ userMessage: prompt,
420
+ messageHistory: [],
421
+ });
422
+
423
+ // Parse JSON response, handling potential markdown formatting
424
+ const content = response.message.replace('```json', '').replace('```', '').trim();
425
+ const parsed = JSON.parse(content);
426
+
427
+ return {
428
+ sufficient: parsed.sufficient || false,
429
+ reasoning: parsed.reasoning || 'No reasoning provided',
430
+ };
431
+ }
432
+
433
+ /**
434
+ * Load a single file with caching
435
+ */
436
+ private async loadFile(filePath: string): Promise<IFileInfo> {
437
+ // Try cache first
438
+ const cached = await this.cache.get(filePath);
439
+ if (cached) {
440
+ return {
441
+ path: filePath,
442
+ relativePath: plugins.path.relative(this.projectRoot, filePath),
443
+ contents: cached.contents,
444
+ tokenCount: cached.tokenCount,
445
+ };
446
+ }
447
+
448
+ // Load from disk
449
+ const contents = await plugins.smartfile.fs.toStringSync(filePath);
450
+ const tokenCount = this.countTokens(contents);
451
+ const relativePath = plugins.path.relative(this.projectRoot, filePath);
452
+
453
+ // Cache it
454
+ const stats = await fs.promises.stat(filePath);
455
+ await this.cache.set({
456
+ path: filePath,
457
+ contents,
458
+ tokenCount,
459
+ mtime: Math.floor(stats.mtimeMs),
460
+ cachedAt: Date.now(),
461
+ });
462
+
463
+ return {
464
+ path: filePath,
465
+ relativePath,
466
+ contents,
467
+ tokenCount,
468
+ };
469
+ }
470
+
471
+ /**
472
+ * Format a file for inclusion in context
473
+ */
474
+ private formatFileForContext(file: IFileInfo): string {
475
+ return `
476
+ ====== START OF FILE ${file.relativePath} ======
477
+
478
+ ${file.contents}
479
+
480
+ ====== END OF FILE ${file.relativePath} ======
481
+ `;
482
+ }
483
+
484
+ /**
485
+ * Count tokens in text
486
+ */
487
+ private countTokens(text: string): number {
488
+ try {
489
+ const tokens = plugins.gptTokenizer.encode(text);
490
+ return tokens.length;
491
+ } catch (error) {
492
+ return Math.ceil(text.length / 4);
493
+ }
494
+ }
495
+ }
@@ -1,99 +1,83 @@
1
1
  import * as plugins from '../plugins.js';
2
- import { EnhancedContext } from './enhanced-context.js';
2
+ import { IterativeContextBuilder } from './iterative-context-builder.js';
3
3
  import { ConfigManager } from './config-manager.js';
4
- import type { IContextResult, TaskType } from './types.js';
4
+ import type { IIterativeContextResult, TaskType } from './types.js';
5
5
 
6
6
  /**
7
- * Factory class for creating task-specific context
7
+ * Factory class for creating task-specific context using iterative context building
8
8
  */
9
9
  export class TaskContextFactory {
10
10
  private projectDir: string;
11
11
  private configManager: ConfigManager;
12
-
12
+ private openaiInstance?: any; // OpenAI provider instance
13
+
13
14
  /**
14
15
  * Create a new TaskContextFactory
15
16
  * @param projectDirArg The project directory
17
+ * @param openaiInstance Optional pre-configured OpenAI provider instance
16
18
  */
17
- constructor(projectDirArg: string) {
19
+ constructor(projectDirArg: string, openaiInstance?: any) {
18
20
  this.projectDir = projectDirArg;
19
21
  this.configManager = ConfigManager.getInstance();
22
+ this.openaiInstance = openaiInstance;
20
23
  }
21
-
24
+
22
25
  /**
23
26
  * Initialize the factory
24
27
  */
25
28
  public async initialize(): Promise<void> {
26
29
  await this.configManager.initialize(this.projectDir);
27
30
  }
28
-
31
+
29
32
  /**
30
33
  * Create context for README generation
31
34
  */
32
- public async createContextForReadme(): Promise<IContextResult> {
33
- const contextBuilder = new EnhancedContext(this.projectDir);
34
- await contextBuilder.initialize();
35
-
36
- // Get README-specific configuration
37
- const taskConfig = this.configManager.getTaskConfig('readme');
38
- if (taskConfig.mode) {
39
- contextBuilder.setContextMode(taskConfig.mode);
40
- }
41
-
42
- // Build the context for README task
43
- return await contextBuilder.buildContext('readme');
35
+ public async createContextForReadme(): Promise<IIterativeContextResult> {
36
+ const iterativeBuilder = new IterativeContextBuilder(
37
+ this.projectDir,
38
+ this.configManager.getIterativeConfig(),
39
+ this.openaiInstance
40
+ );
41
+ await iterativeBuilder.initialize();
42
+ return await iterativeBuilder.buildContextIteratively('readme');
44
43
  }
45
-
44
+
46
45
  /**
47
46
  * Create context for description generation
48
47
  */
49
- public async createContextForDescription(): Promise<IContextResult> {
50
- const contextBuilder = new EnhancedContext(this.projectDir);
51
- await contextBuilder.initialize();
52
-
53
- // Get description-specific configuration
54
- const taskConfig = this.configManager.getTaskConfig('description');
55
- if (taskConfig.mode) {
56
- contextBuilder.setContextMode(taskConfig.mode);
57
- }
58
-
59
- // Build the context for description task
60
- return await contextBuilder.buildContext('description');
48
+ public async createContextForDescription(): Promise<IIterativeContextResult> {
49
+ const iterativeBuilder = new IterativeContextBuilder(
50
+ this.projectDir,
51
+ this.configManager.getIterativeConfig(),
52
+ this.openaiInstance
53
+ );
54
+ await iterativeBuilder.initialize();
55
+ return await iterativeBuilder.buildContextIteratively('description');
61
56
  }
62
-
57
+
63
58
  /**
64
59
  * Create context for commit message generation
65
- * @param gitDiff Optional git diff to include
60
+ * @param gitDiff Optional git diff to include in the context
66
61
  */
67
- public async createContextForCommit(gitDiff?: string): Promise<IContextResult> {
68
- const contextBuilder = new EnhancedContext(this.projectDir);
69
- await contextBuilder.initialize();
70
-
71
- // Get commit-specific configuration
72
- const taskConfig = this.configManager.getTaskConfig('commit');
73
- if (taskConfig.mode) {
74
- contextBuilder.setContextMode(taskConfig.mode);
75
- }
76
-
77
- // Build the context for commit task
78
- const contextResult = await contextBuilder.buildContext('commit');
79
-
80
- // If git diff is provided, add it to the context
81
- if (gitDiff) {
82
- contextBuilder.updateWithGitDiff(gitDiff);
83
- }
84
-
85
- return contextBuilder.getContextResult();
62
+ public async createContextForCommit(gitDiff?: string): Promise<IIterativeContextResult> {
63
+ const iterativeBuilder = new IterativeContextBuilder(
64
+ this.projectDir,
65
+ this.configManager.getIterativeConfig(),
66
+ this.openaiInstance
67
+ );
68
+ await iterativeBuilder.initialize();
69
+ return await iterativeBuilder.buildContextIteratively('commit', gitDiff);
86
70
  }
87
-
71
+
88
72
  /**
89
73
  * Create context for any task type
90
74
  * @param taskType The task type to create context for
91
- * @param additionalContent Optional additional content to include
75
+ * @param additionalContent Optional additional content (currently not used)
92
76
  */
93
77
  public async createContextForTask(
94
78
  taskType: TaskType,
95
79
  additionalContent?: string
96
- ): Promise<IContextResult> {
80
+ ): Promise<IIterativeContextResult> {
97
81
  switch (taskType) {
98
82
  case 'readme':
99
83
  return this.createContextForReadme();
@@ -102,13 +86,11 @@ export class TaskContextFactory {
102
86
  case 'commit':
103
87
  return this.createContextForCommit(additionalContent);
104
88
  default:
105
- // Generic context for unknown task types
106
- const contextBuilder = new EnhancedContext(this.projectDir);
107
- await contextBuilder.initialize();
108
- return await contextBuilder.buildContext();
89
+ // Default to readme for unknown task types
90
+ return this.createContextForReadme();
109
91
  }
110
92
  }
111
-
93
+
112
94
  /**
113
95
  * Get token stats for all task types
114
96
  */
@@ -121,7 +103,7 @@ export class TaskContextFactory {
121
103
  }>> {
122
104
  const taskTypes: TaskType[] = ['readme', 'description', 'commit'];
123
105
  const stats: Record<TaskType, any> = {} as any;
124
-
106
+
125
107
  for (const taskType of taskTypes) {
126
108
  const result = await this.createContextForTask(taskType);
127
109
  stats[taskType] = {
@@ -132,7 +114,7 @@ export class TaskContextFactory {
132
114
  excludedFiles: result.excludedFiles.length
133
115
  };
134
116
  }
135
-
117
+
136
118
  return stats;
137
119
  }
138
- }
120
+ }