@eldrforge/kodrdriv 1.2.131 → 1.2.133

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.
Files changed (48) hide show
  1. package/AI-GUIDE.md +834 -0
  2. package/README.md +35 -6
  3. package/agentic-reflection-commit-2025-12-27T22-56-06-143Z.md +50 -0
  4. package/agentic-reflection-commit-2025-12-27T23-01-57-294Z.md +50 -0
  5. package/agentic-reflection-commit-2025-12-27T23-11-57-811Z.md +50 -0
  6. package/agentic-reflection-commit-2025-12-27T23-12-50-645Z.md +50 -0
  7. package/agentic-reflection-commit-2025-12-27T23-13-59-347Z.md +52 -0
  8. package/agentic-reflection-commit-2025-12-27T23-14-36-001Z.md +50 -0
  9. package/agentic-reflection-commit-2025-12-27T23-18-59-832Z.md +50 -0
  10. package/agentic-reflection-commit-2025-12-27T23-25-20-667Z.md +62 -0
  11. package/dist/application.js +3 -0
  12. package/dist/application.js.map +1 -1
  13. package/dist/arguments.js +54 -21
  14. package/dist/arguments.js.map +1 -1
  15. package/dist/commands/audio-commit.js +2 -1
  16. package/dist/commands/audio-commit.js.map +1 -1
  17. package/dist/commands/audio-review.js +4 -2
  18. package/dist/commands/audio-review.js.map +1 -1
  19. package/dist/commands/commit.js +109 -288
  20. package/dist/commands/commit.js.map +1 -1
  21. package/dist/commands/publish.js +48 -6
  22. package/dist/commands/publish.js.map +1 -1
  23. package/dist/commands/release.js +79 -292
  24. package/dist/commands/release.js.map +1 -1
  25. package/dist/commands/review.js +1 -1
  26. package/dist/commands/review.js.map +1 -1
  27. package/dist/commands/tree.js +29 -33
  28. package/dist/commands/tree.js.map +1 -1
  29. package/dist/constants.js +3 -1
  30. package/dist/constants.js.map +1 -1
  31. package/dist/util/loggerAdapter.js +17 -0
  32. package/dist/util/loggerAdapter.js.map +1 -1
  33. package/dist/util/storageAdapter.js +9 -2
  34. package/dist/util/storageAdapter.js.map +1 -1
  35. package/guide/ai-system.md +519 -0
  36. package/guide/architecture.md +346 -0
  37. package/guide/commands.md +380 -0
  38. package/guide/configuration.md +513 -0
  39. package/guide/debugging.md +584 -0
  40. package/guide/development.md +629 -0
  41. package/guide/index.md +212 -0
  42. package/guide/integration.md +507 -0
  43. package/guide/monorepo.md +530 -0
  44. package/guide/quickstart.md +223 -0
  45. package/guide/testing.md +460 -0
  46. package/guide/tree-operations.md +618 -0
  47. package/guide/usage.md +575 -0
  48. package/package.json +9 -9
@@ -4,8 +4,8 @@ import 'dotenv/config';
4
4
  import { DEFAULT_TO_COMMIT_ALIAS, DEFAULT_MAX_DIFF_BYTES, DEFAULT_EXCLUDED_PATTERNS, DEFAULT_OUTPUT_DIRECTORY } from '../constants.js';
5
5
  import { getCurrentBranch, getDefaultFromRef, safeJsonParse } from '@eldrforge/git-tools';
6
6
  import { create } from '../content/log.js';
7
- import { create as create$1, truncateDiffByFiles } from '../content/diff.js';
8
- import { runAgenticRelease, requireTTY, createReleasePrompt, createCompletionWithRetry, getUserChoice, STANDARD_CHOICES, getLLMFeedbackInEditor, editContentInEditor } from '@eldrforge/ai-service';
7
+ import { create as create$1 } from '../content/diff.js';
8
+ import { runAgenticRelease, requireTTY, generateReflectionReport, getUserChoice, STANDARD_CHOICES, getLLMFeedbackInEditor, editContentInEditor, createCompletionWithRetry, createReleasePrompt } from '@eldrforge/ai-service';
9
9
  import { improveContentWithLLM } from '../util/interactive.js';
10
10
  import { toAIConfig } from '../util/aiAdapter.js';
11
11
  import { createStorageAdapter } from '../util/storageAdapter.js';
@@ -17,6 +17,24 @@ import { validateReleaseSummary } from '../util/validation.js';
17
17
  import * as GitHub from '@eldrforge/github-tools';
18
18
  import { filterContent } from '../util/stopContext.js';
19
19
 
20
+ // Helper function to read context files
21
+ async function readContextFiles(contextFiles, logger) {
22
+ if (!contextFiles || contextFiles.length === 0) {
23
+ return '';
24
+ }
25
+ const storage = createStorage();
26
+ const contextParts = [];
27
+ for (const filePath of contextFiles){
28
+ try {
29
+ const content = await storage.readFile(filePath, 'utf8');
30
+ contextParts.push(`## Context from ${filePath}\n\n${content}\n`);
31
+ logger.debug(`Read context from file: ${filePath}`);
32
+ } catch (error) {
33
+ logger.warn(`Failed to read context file ${filePath}: ${error.message}`);
34
+ }
35
+ }
36
+ return contextParts.join('\n---\n\n');
37
+ }
20
38
  // Helper function to edit release notes using editor
21
39
  async function editReleaseNotesInteractively(releaseSummary) {
22
40
  const templateLines = [
@@ -65,7 +83,7 @@ Please revise the release notes according to the user's feedback while maintaini
65
83
  callLLM: async (request, runConfig, outputDirectory)=>{
66
84
  var _aiConfig_commands_release, _aiConfig_commands, _aiConfig_commands_release1, _aiConfig_commands1;
67
85
  const aiConfig = toAIConfig(runConfig);
68
- const aiStorageAdapter = createStorageAdapter();
86
+ const aiStorageAdapter = createStorageAdapter(outputDirectory);
69
87
  const aiLogger = createLoggerAdapter(false);
70
88
  const modelToUse = ((_aiConfig_commands = aiConfig.commands) === null || _aiConfig_commands === void 0 ? void 0 : (_aiConfig_commands_release = _aiConfig_commands.release) === null || _aiConfig_commands_release === void 0 ? void 0 : _aiConfig_commands_release.model) || aiConfig.model || 'gpt-4o-mini';
71
89
  const openaiReasoning = ((_aiConfig_commands1 = aiConfig.commands) === null || _aiConfig_commands1 === void 0 ? void 0 : (_aiConfig_commands_release1 = _aiConfig_commands1.release) === null || _aiConfig_commands_release1 === void 0 ? void 0 : _aiConfig_commands_release1.reasoning) || aiConfig.reasoning;
@@ -88,166 +106,23 @@ Please revise the release notes according to the user's feedback while maintaini
88
106
  };
89
107
  return await improveContentWithLLM(releaseSummary, runConfig, promptConfig, promptContext, outputDirectory, improvementConfig);
90
108
  }
91
- // Helper function to generate self-reflection output for release notes
109
+ // Helper function to generate self-reflection output for release notes using observability module
92
110
  async function generateSelfReflection(agenticResult, outputDirectory, storage, logger) {
93
111
  try {
94
112
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('.')[0];
95
113
  const reflectionPath = getOutputPath(outputDirectory, `agentic-reflection-release-${timestamp}.md`);
96
- // Calculate tool effectiveness metrics
97
- const toolMetrics = agenticResult.toolMetrics || [];
98
- const toolStats = new Map();
99
- for (const metric of toolMetrics){
100
- if (!toolStats.has(metric.name)) {
101
- toolStats.set(metric.name, {
102
- total: 0,
103
- success: 0,
104
- failures: 0,
105
- totalDuration: 0
106
- });
107
- }
108
- const stats = toolStats.get(metric.name);
109
- stats.total++;
110
- stats.totalDuration += metric.duration;
111
- if (metric.success) {
112
- stats.success++;
113
- } else {
114
- stats.failures++;
115
- }
116
- }
117
- // Build reflection document
118
- const sections = [];
119
- sections.push('# Agentic Release Notes - Self-Reflection Report');
120
- sections.push('');
121
- sections.push(`Generated: ${new Date().toISOString()}`);
122
- sections.push('');
123
- sections.push('## Execution Summary');
124
- sections.push('');
125
- sections.push(`- **Iterations**: ${agenticResult.iterations}`);
126
- sections.push(`- **Tool Calls**: ${agenticResult.toolCallsExecuted}`);
127
- sections.push(`- **Unique Tools Used**: ${toolStats.size}`);
128
- sections.push('');
129
- sections.push('## Tool Effectiveness Analysis');
130
- sections.push('');
131
- if (toolStats.size === 0) {
132
- sections.push('*No tools were called during execution.*');
133
- sections.push('');
134
- } else {
135
- sections.push('| Tool | Calls | Success Rate | Avg Duration | Total Time |');
136
- sections.push('|------|-------|--------------|--------------|------------|');
137
- const sortedTools = Array.from(toolStats.entries()).sort((a, b)=>b[1].total - a[1].total);
138
- for (const [toolName, stats] of sortedTools){
139
- const successRate = (stats.success / stats.total * 100).toFixed(1);
140
- const avgDuration = (stats.totalDuration / stats.total).toFixed(0);
141
- const totalTime = stats.totalDuration.toFixed(0);
142
- sections.push(`| ${toolName} | ${stats.total} | ${successRate}% | ${avgDuration}ms | ${totalTime}ms |`);
143
- }
144
- sections.push('');
145
- }
146
- // Tool usage insights
147
- sections.push('## Tool Usage Insights');
148
- sections.push('');
149
- if (toolStats.size > 0) {
150
- const mostUsedTool = Array.from(toolStats.entries()).sort((a, b)=>b[1].total - a[1].total)[0];
151
- sections.push(`- **Most Used Tool**: \`${mostUsedTool[0]}\` (${mostUsedTool[1].total} calls)`);
152
- const slowestTool = Array.from(toolStats.entries()).sort((a, b)=>b[1].totalDuration / b[1].total - a[1].totalDuration / a[1].total)[0];
153
- const slowestAvg = (slowestTool[1].totalDuration / slowestTool[1].total).toFixed(0);
154
- sections.push(`- **Slowest Tool**: \`${slowestTool[0]}\` (${slowestAvg}ms average)`);
155
- const failedTools = Array.from(toolStats.entries()).filter(([_, stats])=>stats.failures > 0);
156
- if (failedTools.length > 0) {
157
- sections.push(`- **Tools with Failures**: ${failedTools.length} tool(s) had at least one failure`);
158
- for (const [toolName, stats] of failedTools){
159
- sections.push(` - \`${toolName}\`: ${stats.failures}/${stats.total} calls failed`);
160
- }
161
- } else {
162
- sections.push('- **Reliability**: All tool calls succeeded ✓');
163
- }
164
- }
165
- sections.push('');
166
- // Execution patterns
167
- sections.push('## Execution Patterns');
168
- sections.push('');
169
- const iterationsPerToolCall = agenticResult.toolCallsExecuted > 0 ? (agenticResult.iterations / agenticResult.toolCallsExecuted).toFixed(2) : 'N/A';
170
- sections.push(`- **Iterations per Tool Call**: ${iterationsPerToolCall}`);
171
- const totalExecutionTime = Array.from(toolStats.values()).reduce((sum, stats)=>sum + stats.totalDuration, 0);
172
- sections.push(`- **Total Tool Execution Time**: ${totalExecutionTime.toFixed(0)}ms`);
173
- if (agenticResult.toolCallsExecuted > 0) {
174
- const avgTimePerCall = (totalExecutionTime / agenticResult.toolCallsExecuted).toFixed(0);
175
- sections.push(`- **Average Time per Tool Call**: ${avgTimePerCall}ms`);
176
- }
177
- sections.push('');
178
- // Recommendations
179
- sections.push('## Recommendations');
180
- sections.push('');
181
- const recommendations = [];
182
- const failedTools = Array.from(toolStats.entries()).filter(([_, stats])=>stats.failures > 0);
183
- if (failedTools.length > 0) {
184
- recommendations.push('- **Tool Reliability**: Some tools failed during execution. Review error messages and consider improving error handling or tool implementation.');
185
- }
186
- const slowTools = Array.from(toolStats.entries()).filter(([_, stats])=>stats.totalDuration / stats.total > 1000);
187
- if (slowTools.length > 0) {
188
- recommendations.push('- **Performance**: Consider optimizing slow tools or caching results to improve execution speed.');
189
- }
190
- if (agenticResult.iterations >= (agenticResult.maxIterations || 30)) {
191
- recommendations.push('- **Max Iterations Reached**: The agent reached maximum iterations. Consider increasing the limit or improving tool efficiency to allow the agent to complete naturally.');
192
- }
193
- const underutilizedTools = Array.from(toolStats.entries()).filter(([_, stats])=>stats.total === 1);
194
- if (underutilizedTools.length > 3) {
195
- recommendations.push('- **Underutilized Tools**: Many tools were called only once. Consider whether all tools are necessary or if the agent needs better guidance on when to use them.');
196
- }
197
- if (agenticResult.toolCallsExecuted === 0) {
198
- recommendations.push('- **No Tools Used**: The agent completed without calling any tools. This might indicate the initial prompt provided sufficient information, or the agent may benefit from more explicit guidance to use tools.');
199
- }
200
- if (recommendations.length === 0) {
201
- sections.push('*No specific recommendations at this time. Execution appears optimal.*');
202
- } else {
203
- for (const rec of recommendations){
204
- sections.push(rec);
205
- }
206
- }
207
- sections.push('');
208
- // Add detailed execution timeline
209
- sections.push('## Detailed Execution Timeline');
210
- sections.push('');
211
- if (toolMetrics.length === 0) {
212
- sections.push('*No tool execution timeline available.*');
213
- } else {
214
- sections.push('| Time | Iteration | Tool | Result | Duration |');
215
- sections.push('|------|-----------|------|--------|----------|');
216
- for (const metric of toolMetrics){
217
- const time = new Date(metric.timestamp).toLocaleTimeString();
218
- const result = metric.success ? '✅ Success' : `❌ ${metric.error || 'Failed'}`;
219
- sections.push(`| ${time} | ${metric.iteration} | ${metric.name} | ${result} | ${metric.duration}ms |`);
220
- }
221
- sections.push('');
222
- }
223
- // Add conversation history
224
- sections.push('## Conversation History');
225
- sections.push('');
226
- sections.push('<details>');
227
- sections.push('<summary>Click to expand full agentic interaction</summary>');
228
- sections.push('');
229
- sections.push('```json');
230
- sections.push(JSON.stringify(agenticResult.conversationHistory, null, 2));
231
- sections.push('```');
232
- sections.push('');
233
- sections.push('</details>');
234
- sections.push('');
235
- // Add generated release notes
236
- sections.push('## Generated Release Notes');
237
- sections.push('');
238
- sections.push('### Title');
239
- sections.push('```');
240
- sections.push(agenticResult.releaseNotes.title);
241
- sections.push('```');
242
- sections.push('');
243
- sections.push('### Body');
244
- sections.push('```markdown');
245
- sections.push(agenticResult.releaseNotes.body);
246
- sections.push('```');
247
- sections.push('');
248
- // Write the reflection file
249
- const reflectionContent = sections.join('\n');
250
- await storage.writeFile(reflectionPath, reflectionContent, 'utf-8');
114
+ // Use new observability reflection generator
115
+ const report = await generateReflectionReport({
116
+ iterations: agenticResult.iterations || 0,
117
+ toolCallsExecuted: agenticResult.toolCallsExecuted || 0,
118
+ maxIterations: agenticResult.maxIterations || 30,
119
+ toolMetrics: agenticResult.toolMetrics || [],
120
+ conversationHistory: agenticResult.conversationHistory || [],
121
+ releaseNotes: agenticResult.releaseNotes,
122
+ logger
123
+ });
124
+ // Save the report to output directory
125
+ await storage.writeFile(reflectionPath, report, 'utf8');
251
126
  logger.info('');
252
127
  logger.info('═'.repeat(80));
253
128
  logger.info('📊 SELF-REFLECTION REPORT GENERATED');
@@ -256,9 +131,12 @@ async function generateSelfReflection(agenticResult, outputDirectory, storage, l
256
131
  logger.info('📁 Location: %s', reflectionPath);
257
132
  logger.info('');
258
133
  logger.info('📈 Report Summary:');
259
- logger.info(' • %d iterations completed', agenticResult.iterations);
260
- logger.info(' • %d tool calls executed', agenticResult.toolCallsExecuted);
261
- logger.info(' • %d unique tools used', toolStats.size);
134
+ const iterations = agenticResult.iterations || 0;
135
+ const toolCalls = agenticResult.toolCallsExecuted || 0;
136
+ const uniqueTools = new Set((agenticResult.toolMetrics || []).map((m)=>m.name)).size;
137
+ logger.info(` • ${iterations} iterations completed`);
138
+ logger.info(` • ${toolCalls} tool calls executed`);
139
+ logger.info(` • ${uniqueTools} unique tools used`);
262
140
  logger.info('');
263
141
  logger.info('💡 Use this report to:');
264
142
  logger.info(' • Understand which tools were most effective');
@@ -326,7 +204,7 @@ async function handleInteractiveReleaseFeedback(releaseSummary, runConfig, promp
326
204
  }
327
205
  }
328
206
  const execute = async (runConfig)=>{
329
- var _runConfig_release, _runConfig_release1, _runConfig_release2, _runConfig_release3, _runConfig_release4, _runConfig_release5, _runConfig_release6, _runConfig_release7, _runConfig_release8, _runConfig_release9, _aiConfig_commands_release, _aiConfig_commands, _aiConfig_commands_release1, _aiConfig_commands1, _runConfig_release10;
207
+ var _runConfig_release, _runConfig_release1, _runConfig_release2, _runConfig_release3, _runConfig_release4, _runConfig_release5, _runConfig_release6, _runConfig_release7, _runConfig_release8, _runConfig_release9, _aiConfig_commands_release, _aiConfig_commands, _runConfig_release10, _aiConfig_commands_release1, _aiConfig_commands1, _runConfig_release11, _runConfig_release12;
330
208
  const isDryRun = runConfig.dryRun || false;
331
209
  const logger = getDryRunLogger(isDryRun);
332
210
  // Get current branch to help determine best tag comparison
@@ -413,152 +291,61 @@ const execute = async (runConfig)=>{
413
291
  } else {
414
292
  logger.debug('Milestone integration disabled via --no-milestones');
415
293
  }
416
- // Create adapters for ai-service
417
- const aiConfig = toAIConfig(runConfig);
418
- const aiStorageAdapter = createStorageAdapter();
419
- const aiLogger = createLoggerAdapter(isDryRun);
420
294
  // Always ensure output directory exists for request/response files
421
295
  const outputDirectory = runConfig.outputDirectory || DEFAULT_OUTPUT_DIRECTORY;
422
296
  const storage = createStorage();
423
297
  await storage.ensureDirectory(outputDirectory);
424
- // Check if agentic mode is enabled
425
- if ((_runConfig_release7 = runConfig.release) === null || _runConfig_release7 === void 0 ? void 0 : _runConfig_release7.agentic) {
426
- var _runConfig_release11, _runConfig_release12, _aiConfig_commands_release2, _aiConfig_commands2, _runConfig_release13, _aiConfig_commands_release3, _aiConfig_commands3, _runConfig_release14, _runConfig_release15;
427
- logger.info('🤖 Using agentic mode for release notes generation');
428
- // Run agentic release notes generation
429
- const agenticResult = await runAgenticRelease({
430
- fromRef,
431
- toRef,
432
- logContent,
433
- diffContent,
434
- milestoneIssues: milestoneIssuesContent,
435
- releaseFocus: (_runConfig_release11 = runConfig.release) === null || _runConfig_release11 === void 0 ? void 0 : _runConfig_release11.focus,
436
- userContext: (_runConfig_release12 = runConfig.release) === null || _runConfig_release12 === void 0 ? void 0 : _runConfig_release12.context,
437
- model: ((_aiConfig_commands2 = aiConfig.commands) === null || _aiConfig_commands2 === void 0 ? void 0 : (_aiConfig_commands_release2 = _aiConfig_commands2.release) === null || _aiConfig_commands_release2 === void 0 ? void 0 : _aiConfig_commands_release2.model) || aiConfig.model || 'gpt-4o',
438
- maxIterations: ((_runConfig_release13 = runConfig.release) === null || _runConfig_release13 === void 0 ? void 0 : _runConfig_release13.maxAgenticIterations) || 30,
439
- debug: runConfig.debug,
440
- debugRequestFile: getOutputPath(outputDirectory, getTimestampedRequestFilename('release-agentic')),
441
- debugResponseFile: getOutputPath(outputDirectory, getTimestampedResponseFilename('release-agentic')),
442
- storage: aiStorageAdapter,
443
- logger: aiLogger,
444
- openaiReasoning: ((_aiConfig_commands3 = aiConfig.commands) === null || _aiConfig_commands3 === void 0 ? void 0 : (_aiConfig_commands_release3 = _aiConfig_commands3.release) === null || _aiConfig_commands_release3 === void 0 ? void 0 : _aiConfig_commands_release3.reasoning) || aiConfig.reasoning
445
- });
446
- logger.info('🔍 Agentic analysis complete: %d iterations, %d tool calls', agenticResult.iterations, agenticResult.toolCallsExecuted);
447
- // Generate self-reflection output if enabled
448
- if ((_runConfig_release14 = runConfig.release) === null || _runConfig_release14 === void 0 ? void 0 : _runConfig_release14.selfReflection) {
449
- await generateSelfReflection(agenticResult, outputDirectory, storage, logger);
450
- }
451
- // Apply stop-context filtering to release notes
452
- const titleFilterResult = filterContent(agenticResult.releaseNotes.title, runConfig.stopContext);
453
- const bodyFilterResult = filterContent(agenticResult.releaseNotes.body, runConfig.stopContext);
454
- let releaseSummary = {
455
- title: titleFilterResult.filtered,
456
- body: bodyFilterResult.filtered
457
- };
458
- // Handle interactive mode
459
- if (((_runConfig_release15 = runConfig.release) === null || _runConfig_release15 === void 0 ? void 0 : _runConfig_release15.interactive) && !isDryRun) {
460
- var _runConfig_release16;
461
- requireTTY('Interactive mode requires a terminal. Use --dry-run instead.');
462
- const interactivePromptContext = {
463
- context: (_runConfig_release16 = runConfig.release) === null || _runConfig_release16 === void 0 ? void 0 : _runConfig_release16.context,
464
- directories: runConfig.contextDirectories
465
- };
466
- const interactiveResult = await handleInteractiveReleaseFeedback(releaseSummary, runConfig, promptConfig, interactivePromptContext, outputDirectory, storage, logContent, diffContent);
467
- if (interactiveResult.action === 'skip') {
468
- logger.info('RELEASE_ABORTED: Release notes generation aborted by user | Reason: User choice | Status: cancelled');
469
- } else {
470
- logger.info('RELEASE_FINALIZED: Release notes finalized and accepted | Status: ready | Next: Create release or save');
471
- }
472
- releaseSummary = interactiveResult.finalSummary;
473
- }
474
- // Save timestamped copy of release notes to output directory
475
- try {
476
- const timestampedFilename = getTimestampedReleaseNotesFilename();
477
- const outputPath = getOutputPath(outputDirectory, timestampedFilename);
478
- // Format the release notes as markdown
479
- const releaseNotesContent = `# ${releaseSummary.title}\n\n${releaseSummary.body}`;
480
- await storage.writeFile(outputPath, releaseNotesContent, 'utf-8');
481
- logger.debug('Saved timestamped release notes: %s', outputPath);
482
- } catch (error) {
483
- logger.warn('RELEASE_SAVE_FAILED: Failed to save timestamped release notes | Error: %s | Impact: Notes not persisted to file', error.message);
484
- }
485
- if (isDryRun) {
486
- logger.info('RELEASE_SUMMARY_COMPLETE: Generated release summary successfully | Status: completed');
487
- logger.info('RELEASE_SUMMARY_TITLE: %s', releaseSummary.title);
488
- logger.info('RELEASE_SUMMARY_BODY: %s', releaseSummary.body);
489
- }
490
- return releaseSummary;
491
- }
492
- // Non-agentic mode: use traditional prompt-based approach
493
- const promptContent = {
298
+ // Create adapters for ai-service
299
+ const aiConfig = toAIConfig(runConfig);
300
+ const aiStorageAdapter = createStorageAdapter(outputDirectory);
301
+ const aiLogger = createLoggerAdapter(isDryRun);
302
+ // Read context from files if provided
303
+ const contextFromFiles = await readContextFiles((_runConfig_release7 = runConfig.release) === null || _runConfig_release7 === void 0 ? void 0 : _runConfig_release7.contextFiles, logger);
304
+ // Combine file context with existing context
305
+ const combinedContext = [
306
+ (_runConfig_release8 = runConfig.release) === null || _runConfig_release8 === void 0 ? void 0 : _runConfig_release8.context,
307
+ contextFromFiles
308
+ ].filter(Boolean).join('\n\n---\n\n');
309
+ // Run agentic release notes generation
310
+ const agenticResult = await runAgenticRelease({
311
+ fromRef,
312
+ toRef,
494
313
  logContent,
495
314
  diffContent,
496
- releaseFocus: (_runConfig_release8 = runConfig.release) === null || _runConfig_release8 === void 0 ? void 0 : _runConfig_release8.focus,
497
- milestoneIssues: milestoneIssuesContent
498
- };
499
- const promptContext = {
500
- context: (_runConfig_release9 = runConfig.release) === null || _runConfig_release9 === void 0 ? void 0 : _runConfig_release9.context,
501
- directories: runConfig.contextDirectories
502
- };
503
- const promptResult = await createReleasePrompt(promptConfig, promptContent, promptContext);
504
- const modelToUse = ((_aiConfig_commands = aiConfig.commands) === null || _aiConfig_commands === void 0 ? void 0 : (_aiConfig_commands_release = _aiConfig_commands.release) === null || _aiConfig_commands_release === void 0 ? void 0 : _aiConfig_commands_release.model) || aiConfig.model || 'gpt-4o-mini';
505
- const request = Formatter.create({
506
- logger
507
- }).formatPrompt(modelToUse, promptResult.prompt);
508
- logger.debug('Release analysis: isLargeRelease=%s, maxTokens=%d', promptResult.isLargeRelease, promptResult.maxTokens);
509
- // Create retry callback that reduces diff size on token limit errors
510
- const createRetryCallback = (originalDiffContent, originalLogContent)=>async (attempt)=>{
511
- var _runConfig_release, _runConfig_release1;
512
- logger.info('RELEASE_RETRY: Retrying with reduced diff size | Attempt: %d | Strategy: Truncate diff | Reason: Previous attempt failed', attempt);
513
- // Progressively reduce the diff size on retries
514
- const reductionFactor = Math.pow(0.5, attempt - 1); // 50% reduction per retry
515
- const reducedMaxDiffBytes = Math.max(512, Math.floor(maxDiffBytes * reductionFactor));
516
- logger.debug('Reducing maxDiffBytes from %d to %d for retry', maxDiffBytes, reducedMaxDiffBytes);
517
- // Re-truncate the diff with smaller limits
518
- const reducedDiffContent = originalDiffContent.length > reducedMaxDiffBytes ? truncateDiffByFiles(originalDiffContent, reducedMaxDiffBytes) : originalDiffContent;
519
- // Rebuild the prompt with the reduced diff
520
- const reducedPromptContent = {
521
- logContent: originalLogContent,
522
- diffContent: reducedDiffContent,
523
- releaseFocus: (_runConfig_release = runConfig.release) === null || _runConfig_release === void 0 ? void 0 : _runConfig_release.focus,
524
- milestoneIssues: milestoneIssuesContent
525
- };
526
- const reducedPromptContext = {
527
- context: (_runConfig_release1 = runConfig.release) === null || _runConfig_release1 === void 0 ? void 0 : _runConfig_release1.context,
528
- directories: runConfig.contextDirectories
529
- };
530
- const retryPromptResult = await createReleasePrompt(promptConfig, reducedPromptContent, reducedPromptContext);
531
- const retryRequest = Formatter.create({
532
- logger
533
- }).formatPrompt(modelToUse, retryPromptResult.prompt);
534
- return retryRequest.messages;
535
- };
536
- const summary = await createCompletionWithRetry(request.messages, {
537
- model: modelToUse,
538
- openaiReasoning: ((_aiConfig_commands1 = aiConfig.commands) === null || _aiConfig_commands1 === void 0 ? void 0 : (_aiConfig_commands_release1 = _aiConfig_commands1.release) === null || _aiConfig_commands_release1 === void 0 ? void 0 : _aiConfig_commands_release1.reasoning) || aiConfig.reasoning,
539
- maxTokens: promptResult.maxTokens,
540
- responseFormat: {
541
- type: 'json_object'
542
- },
315
+ milestoneIssues: milestoneIssuesContent,
316
+ releaseFocus: (_runConfig_release9 = runConfig.release) === null || _runConfig_release9 === void 0 ? void 0 : _runConfig_release9.focus,
317
+ userContext: combinedContext || undefined,
318
+ model: ((_aiConfig_commands = aiConfig.commands) === null || _aiConfig_commands === void 0 ? void 0 : (_aiConfig_commands_release = _aiConfig_commands.release) === null || _aiConfig_commands_release === void 0 ? void 0 : _aiConfig_commands_release.model) || aiConfig.model || 'gpt-4o',
319
+ maxIterations: ((_runConfig_release10 = runConfig.release) === null || _runConfig_release10 === void 0 ? void 0 : _runConfig_release10.maxAgenticIterations) || 30,
543
320
  debug: runConfig.debug,
544
321
  debugRequestFile: getOutputPath(outputDirectory, getTimestampedRequestFilename('release')),
545
322
  debugResponseFile: getOutputPath(outputDirectory, getTimestampedResponseFilename('release')),
546
323
  storage: aiStorageAdapter,
547
- logger: aiLogger
548
- }, createRetryCallback(diffContent, logContent));
549
- // Validate and safely cast the response
550
- const rawReleaseSummary = validateReleaseSummary(summary);
324
+ logger: aiLogger,
325
+ openaiReasoning: ((_aiConfig_commands1 = aiConfig.commands) === null || _aiConfig_commands1 === void 0 ? void 0 : (_aiConfig_commands_release1 = _aiConfig_commands1.release) === null || _aiConfig_commands_release1 === void 0 ? void 0 : _aiConfig_commands_release1.reasoning) || aiConfig.reasoning
326
+ });
327
+ const iterations = agenticResult.iterations || 0;
328
+ const toolCalls = agenticResult.toolCallsExecuted || 0;
329
+ logger.info(`🔍 Analysis complete: ${iterations} iterations, ${toolCalls} tool calls`);
330
+ // Generate self-reflection output if enabled
331
+ if ((_runConfig_release11 = runConfig.release) === null || _runConfig_release11 === void 0 ? void 0 : _runConfig_release11.selfReflection) {
332
+ await generateSelfReflection(agenticResult, outputDirectory, storage, logger);
333
+ }
551
334
  // Apply stop-context filtering to release notes
552
- const titleFilterResult = filterContent(rawReleaseSummary.title, runConfig.stopContext);
553
- const bodyFilterResult = filterContent(rawReleaseSummary.body, runConfig.stopContext);
335
+ const titleFilterResult = filterContent(agenticResult.releaseNotes.title, runConfig.stopContext);
336
+ const bodyFilterResult = filterContent(agenticResult.releaseNotes.body, runConfig.stopContext);
554
337
  let releaseSummary = {
555
338
  title: titleFilterResult.filtered,
556
339
  body: bodyFilterResult.filtered
557
340
  };
558
341
  // Handle interactive mode
559
- if (((_runConfig_release10 = runConfig.release) === null || _runConfig_release10 === void 0 ? void 0 : _runConfig_release10.interactive) && !isDryRun) {
342
+ if (((_runConfig_release12 = runConfig.release) === null || _runConfig_release12 === void 0 ? void 0 : _runConfig_release12.interactive) && !isDryRun) {
560
343
  requireTTY('Interactive mode requires a terminal. Use --dry-run instead.');
561
- const interactiveResult = await handleInteractiveReleaseFeedback(releaseSummary, runConfig, promptConfig, promptContext, outputDirectory, storage, logContent, diffContent);
344
+ const interactivePromptContext = {
345
+ context: combinedContext || undefined,
346
+ directories: runConfig.contextDirectories
347
+ };
348
+ const interactiveResult = await handleInteractiveReleaseFeedback(releaseSummary, runConfig, promptConfig, interactivePromptContext, outputDirectory, storage, logContent, diffContent);
562
349
  if (interactiveResult.action === 'skip') {
563
350
  logger.info('RELEASE_ABORTED: Release notes generation aborted by user | Reason: User choice | Status: cancelled');
564
351
  } else {