@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
@@ -3,184 +3,58 @@ import { Formatter } from '@riotprompt/riotprompt';
3
3
  import 'dotenv/config';
4
4
  import shellescape from 'shell-escape';
5
5
  import { DEFAULT_MAX_DIFF_BYTES, DEFAULT_EXCLUDED_PATTERNS, DEFAULT_OUTPUT_DIRECTORY } from '../constants.js';
6
- import { create, hasCriticalExcludedChanges, getMinimalExcludedPatterns, hasStagedChanges, truncateDiffByFiles } from '../content/diff.js';
6
+ import { create, hasCriticalExcludedChanges, getMinimalExcludedPatterns, hasStagedChanges } from '../content/diff.js';
7
7
  import { create as create$2 } from '../content/log.js';
8
8
  import { create as create$1 } from '../content/files.js';
9
- import { ValidationError, ExternalDependencyError, CommandError, createStorage, stringifyJSON, checkForFileDependencies, logFileDependencyWarning, logFileDependencySuggestions } from '@eldrforge/shared';
9
+ import { ValidationError, ExternalDependencyError, CommandError, createStorage, checkForFileDependencies, logFileDependencyWarning, logFileDependencySuggestions } from '@eldrforge/shared';
10
10
  import { getDryRunLogger } from '../logging.js';
11
11
  import { run, validateString, safeJsonParse, validatePackageJson } from '@eldrforge/git-tools';
12
12
  import { sanitizeDirection } from '../util/validation.js';
13
13
  import { filterContent } from '../util/stopContext.js';
14
14
  import { getOutputPath, getTimestampedResponseFilename, getTimestampedRequestFilename, getTimestampedCommitFilename } from '../util/general.js';
15
15
  import { getRecentClosedIssuesForCommit } from '@eldrforge/github-tools';
16
- import { runAgenticCommit, createCommitPrompt, createCompletionWithRetry, requireTTY, getUserChoice, STANDARD_CHOICES, getLLMFeedbackInEditor, editContentInEditor } from '@eldrforge/ai-service';
16
+ import { runAgenticCommit, requireTTY, generateReflectionReport, getUserChoice, STANDARD_CHOICES, getLLMFeedbackInEditor, editContentInEditor, createCompletionWithRetry, createCommitPrompt } from '@eldrforge/ai-service';
17
17
  import { improveContentWithLLM } from '../util/interactive.js';
18
18
  import { toAIConfig } from '../util/aiAdapter.js';
19
19
  import { createStorageAdapter } from '../util/storageAdapter.js';
20
20
  import { createLoggerAdapter } from '../util/loggerAdapter.js';
21
21
 
22
- // Helper function to generate self-reflection output
22
+ // Helper function to read context files
23
+ async function readContextFiles(contextFiles, logger) {
24
+ if (!contextFiles || contextFiles.length === 0) {
25
+ return '';
26
+ }
27
+ const storage = createStorage();
28
+ const contextParts = [];
29
+ for (const filePath of contextFiles){
30
+ try {
31
+ const content = await storage.readFile(filePath, 'utf8');
32
+ contextParts.push(`## Context from ${filePath}\n\n${content}\n`);
33
+ logger.debug(`Read context from file: ${filePath}`);
34
+ } catch (error) {
35
+ logger.warn(`Failed to read context file ${filePath}: ${error.message}`);
36
+ }
37
+ }
38
+ return contextParts.join('\n---\n\n');
39
+ }
40
+ // Helper function to generate self-reflection output using observability module
23
41
  async function generateSelfReflection(agenticResult, outputDirectory, storage, logger) {
24
42
  try {
25
43
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('.')[0];
26
44
  const reflectionPath = getOutputPath(outputDirectory, `agentic-reflection-commit-${timestamp}.md`);
27
- // Calculate tool effectiveness metrics
28
- const toolMetrics = agenticResult.toolMetrics || [];
29
- const toolStats = new Map();
30
- for (const metric of toolMetrics){
31
- if (!toolStats.has(metric.name)) {
32
- toolStats.set(metric.name, {
33
- total: 0,
34
- success: 0,
35
- failures: 0,
36
- totalDuration: 0
37
- });
38
- }
39
- const stats = toolStats.get(metric.name);
40
- stats.total++;
41
- stats.totalDuration += metric.duration;
42
- if (metric.success) {
43
- stats.success++;
44
- } else {
45
- stats.failures++;
46
- }
47
- }
48
- // Build reflection document
49
- const sections = [];
50
- sections.push('# Agentic Commit - Self-Reflection Report');
51
- sections.push('');
52
- sections.push(`Generated: ${new Date().toISOString()}`);
53
- sections.push('');
54
- sections.push('## Execution Summary');
55
- sections.push('');
56
- sections.push(`- **Iterations**: ${agenticResult.iterations}`);
57
- sections.push(`- **Tool Calls**: ${agenticResult.toolCallsExecuted}`);
58
- sections.push(`- **Unique Tools Used**: ${toolStats.size}`);
59
- sections.push('');
60
- sections.push('## Tool Effectiveness Analysis');
61
- sections.push('');
62
- if (toolStats.size === 0) {
63
- sections.push('*No tools were executed during this run.*');
64
- } else {
65
- sections.push('| Tool | Calls | Success | Failures | Success Rate | Avg Duration |');
66
- sections.push('|------|-------|---------|----------|--------------|--------------|');
67
- for (const [toolName, stats] of Array.from(toolStats.entries()).sort((a, b)=>b[1].total - a[1].total)){
68
- const successRate = (stats.success / stats.total * 100).toFixed(1);
69
- const avgDuration = (stats.totalDuration / stats.total).toFixed(0);
70
- sections.push(`| ${toolName} | ${stats.total} | ${stats.success} | ${stats.failures} | ${successRate}% | ${avgDuration}ms |`);
71
- }
72
- sections.push('');
73
- sections.push('### Tool Performance Insights');
74
- sections.push('');
75
- // Identify problematic tools
76
- const failedTools = Array.from(toolStats.entries()).filter(([_, stats])=>stats.failures > 0);
77
- if (failedTools.length > 0) {
78
- sections.push('**Tools with Failures:**');
79
- for (const [toolName, stats] of failedTools){
80
- const failureRate = (stats.failures / stats.total * 100).toFixed(1);
81
- sections.push(`- ${toolName}: ${stats.failures}/${stats.total} failures (${failureRate}%)`);
82
- }
83
- sections.push('');
84
- }
85
- // Identify slow tools
86
- const slowTools = Array.from(toolStats.entries()).filter(([_, stats])=>stats.totalDuration / stats.total > 1000).sort((a, b)=>b[1].totalDuration / b[1].total - a[1].totalDuration / a[1].total);
87
- if (slowTools.length > 0) {
88
- sections.push('**Slow Tools (>1s average):**');
89
- for (const [toolName, stats] of slowTools){
90
- const avgDuration = (stats.totalDuration / stats.total / 1000).toFixed(2);
91
- sections.push(`- ${toolName}: ${avgDuration}s average`);
92
- }
93
- sections.push('');
94
- }
95
- // Identify most useful tools
96
- sections.push('**Most Frequently Used:**');
97
- const topTools = Array.from(toolStats.entries()).slice(0, 3);
98
- for (const [toolName, stats] of topTools){
99
- sections.push(`- ${toolName}: ${stats.total} calls`);
100
- }
101
- sections.push('');
102
- }
103
- sections.push('## Detailed Execution Timeline');
104
- sections.push('');
105
- if (toolMetrics.length === 0) {
106
- sections.push('*No tool execution timeline available.*');
107
- } else {
108
- sections.push('| Time | Iteration | Tool | Result | Duration |');
109
- sections.push('|------|-----------|------|--------|----------|');
110
- for (const metric of toolMetrics){
111
- const time = new Date(metric.timestamp).toLocaleTimeString();
112
- const result = metric.success ? 'āœ… Success' : `āŒ ${metric.error || 'Failed'}`;
113
- sections.push(`| ${time} | ${metric.iteration} | ${metric.name} | ${result} | ${metric.duration}ms |`);
114
- }
115
- sections.push('');
116
- }
117
- sections.push('## Conversation History');
118
- sections.push('');
119
- sections.push('<details>');
120
- sections.push('<summary>Click to expand full agentic interaction</summary>');
121
- sections.push('');
122
- sections.push('```json');
123
- sections.push(JSON.stringify(agenticResult.conversationHistory, null, 2));
124
- sections.push('```');
125
- sections.push('');
126
- sections.push('</details>');
127
- sections.push('');
128
- sections.push('## Generated Commit Message');
129
- sections.push('');
130
- sections.push('```');
131
- sections.push(agenticResult.commitMessage);
132
- sections.push('```');
133
- sections.push('');
134
- if (agenticResult.suggestedSplits && agenticResult.suggestedSplits.length > 1) {
135
- sections.push('## Suggested Commit Splits');
136
- sections.push('');
137
- for(let i = 0; i < agenticResult.suggestedSplits.length; i++){
138
- const split = agenticResult.suggestedSplits[i];
139
- sections.push(`### Split ${i + 1}`);
140
- sections.push('');
141
- sections.push(`**Files**: ${split.files.join(', ')}`);
142
- sections.push('');
143
- sections.push(`**Rationale**: ${split.rationale}`);
144
- sections.push('');
145
- sections.push(`**Message**:`);
146
- sections.push('```');
147
- sections.push(split.message);
148
- sections.push('```');
149
- sections.push('');
150
- }
151
- }
152
- sections.push('## Recommendations for Improvement');
153
- sections.push('');
154
- // Generate recommendations based on metrics
155
- const recommendations = [];
156
- // Recalculate failed tools for recommendations
157
- const toolsWithFailures = Array.from(toolStats.entries()).filter(([_, stats])=>stats.failures > 0);
158
- if (toolsWithFailures.length > 0) {
159
- recommendations.push('- **Tool Failures**: Investigate and fix tools that are failing. This may indicate issues with error handling or tool implementation.');
160
- }
161
- // Recalculate slow tools for recommendations
162
- const slowToolsForRecs = Array.from(toolStats.entries()).filter(([_, stats])=>stats.totalDuration / stats.total > 1000);
163
- if (slowToolsForRecs.length > 0) {
164
- recommendations.push('- **Performance**: Consider optimizing slow tools or caching results to improve execution speed.');
165
- }
166
- if (agenticResult.iterations >= (agenticResult.maxIterations || 10)) {
167
- 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.');
168
- }
169
- const underutilizedTools = Array.from(toolStats.entries()).filter(([_, stats])=>stats.total === 1);
170
- if (underutilizedTools.length > 3) {
171
- 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.');
172
- }
173
- if (recommendations.length === 0) {
174
- sections.push('*No specific recommendations at this time. Execution appears optimal.*');
175
- } else {
176
- for (const rec of recommendations){
177
- sections.push(rec);
178
- }
179
- }
180
- sections.push('');
181
- // Write the reflection file
182
- const reflectionContent = sections.join('\n');
183
- await storage.writeFile(reflectionPath, reflectionContent, 'utf-8');
45
+ // Use new observability reflection generator
46
+ const report = await generateReflectionReport({
47
+ iterations: agenticResult.iterations || 0,
48
+ toolCallsExecuted: agenticResult.toolCallsExecuted || 0,
49
+ maxIterations: agenticResult.maxIterations || 10,
50
+ toolMetrics: agenticResult.toolMetrics || [],
51
+ conversationHistory: agenticResult.conversationHistory || [],
52
+ commitMessage: agenticResult.commitMessage,
53
+ suggestedSplits: agenticResult.suggestedSplits || [],
54
+ logger
55
+ });
56
+ // Save the report to output directory
57
+ await storage.writeFile(reflectionPath, report, 'utf8');
184
58
  logger.info('');
185
59
  logger.info('═'.repeat(80));
186
60
  logger.info('šŸ“Š SELF-REFLECTION REPORT GENERATED');
@@ -189,9 +63,12 @@ async function generateSelfReflection(agenticResult, outputDirectory, storage, l
189
63
  logger.info('šŸ“ Location: %s', reflectionPath);
190
64
  logger.info('');
191
65
  logger.info('šŸ“ˆ Report Summary:');
192
- logger.info(' • %d iterations completed', agenticResult.iterations);
193
- logger.info(' • %d tool calls executed', agenticResult.toolCallsExecuted);
194
- logger.info(' • %d unique tools used', toolStats.size);
66
+ const iterations = agenticResult.iterations || 0;
67
+ const toolCalls = agenticResult.toolCallsExecuted || 0;
68
+ const uniqueTools = new Set((agenticResult.toolMetrics || []).map((m)=>m.name)).size;
69
+ logger.info(` • ${iterations} iterations completed`);
70
+ logger.info(` • ${toolCalls} tool calls executed`);
71
+ logger.info(` • ${uniqueTools} unique tools used`);
195
72
  logger.info('');
196
73
  logger.info('šŸ’” Use this report to:');
197
74
  logger.info(' • Understand which tools were most effective');
@@ -232,7 +109,7 @@ async function improveCommitMessageWithLLM(commitMessage, runConfig, promptConfi
232
109
  const userFeedback = await getLLMFeedbackInEditor('commit message', commitMessage);
233
110
  // Create AI config from kodrdriv config
234
111
  const aiConfig = toAIConfig(runConfig);
235
- const aiStorageAdapter = createStorageAdapter();
112
+ const aiStorageAdapter = createStorageAdapter(outputDirectory);
236
113
  const aiLogger = createLoggerAdapter(false);
237
114
  const improvementConfig = {
238
115
  contentType: 'commit message',
@@ -443,7 +320,7 @@ const saveCommitMessage = async (outputDirectory, summary, storage, logger)=>{
443
320
  }
444
321
  };
445
322
  const executeInternal = async (runConfig)=>{
446
- var _runConfig_commit, _runConfig_commit1, _runConfig_commit2, _runConfig_commit3, _runConfig_commit4, _runConfig_commit5, _runConfig_commit6, _runConfig_commit7, _runConfig_commit8, _runConfig_commit9, _runConfig_commit10;
323
+ var _runConfig_commit, _runConfig_commit1, _runConfig_commit2, _runConfig_commit3, _runConfig_commit4, _runConfig_commit5, _runConfig_commit6, _aiConfig_commands_commit, _aiConfig_commands, _runConfig_commit7, _aiConfig_commands_commit1, _aiConfig_commands1, _runConfig_commit8, _runConfig_commit9, _runConfig_commit10, _runConfig_commit11, _runConfig_commit12, _runConfig_commit13, _runConfig_commit14;
447
324
  const isDryRun = runConfig.dryRun || false;
448
325
  const logger = getDryRunLogger(isDryRun);
449
326
  // Track if user explicitly chose to skip in interactive mode
@@ -462,7 +339,6 @@ const executeInternal = async (runConfig)=>{
462
339
  // Validate sendit state early - now returns boolean instead of throwing
463
340
  validateSenditState(runConfig, cached, isDryRun, logger);
464
341
  let diffContent = '';
465
- let isUsingFileContent = false;
466
342
  var _runConfig_commit_maxDiffBytes;
467
343
  const maxDiffBytes = (_runConfig_commit_maxDiffBytes = (_runConfig_commit1 = runConfig.commit) === null || _runConfig_commit1 === void 0 ? void 0 : _runConfig_commit1.maxDiffBytes) !== null && _runConfig_commit_maxDiffBytes !== void 0 ? _runConfig_commit_maxDiffBytes : DEFAULT_MAX_DIFF_BYTES;
468
344
  var _runConfig_excludedPatterns;
@@ -479,9 +355,9 @@ const executeInternal = async (runConfig)=>{
479
355
  if (!hasActualChanges) {
480
356
  const criticalChanges = await hasCriticalExcludedChanges();
481
357
  if (criticalChanges.hasChanges) {
482
- var _runConfig_commit11;
358
+ var _runConfig_commit15;
483
359
  logger.info('CRITICAL_FILES_DETECTED: No changes with exclusion patterns, but critical files modified | Files: %s | Action: May need to include critical files', criticalChanges.files.join(', '));
484
- if (((_runConfig_commit11 = runConfig.commit) === null || _runConfig_commit11 === void 0 ? void 0 : _runConfig_commit11.sendit) && !isDryRun) {
360
+ if (((_runConfig_commit15 = runConfig.commit) === null || _runConfig_commit15 === void 0 ? void 0 : _runConfig_commit15.sendit) && !isDryRun) {
485
361
  // In sendit mode, automatically include critical files
486
362
  logger.info('SENDIT_INCLUDING_CRITICAL: SendIt mode including critical files in diff | Purpose: Ensure all important changes are captured');
487
363
  var _runConfig_excludedPatterns1;
@@ -513,10 +389,10 @@ const executeInternal = async (runConfig)=>{
513
389
  }
514
390
  }
515
391
  } else {
516
- var _runConfig_commit12;
392
+ var _runConfig_commit16;
517
393
  // No changes at all - try fallback to file content for new repositories
518
394
  logger.info('NO_CHANGES_DETECTED: No changes found in working directory | Status: clean | Action: Nothing to commit');
519
- if (((_runConfig_commit12 = runConfig.commit) === null || _runConfig_commit12 === void 0 ? void 0 : _runConfig_commit12.sendit) && !isDryRun) {
395
+ if (((_runConfig_commit16 = runConfig.commit) === null || _runConfig_commit16 === void 0 ? void 0 : _runConfig_commit16.sendit) && !isDryRun) {
520
396
  logger.warn('No changes detected to commit. Skipping commit operation.');
521
397
  return 'No changes to commit.';
522
398
  } else {
@@ -533,11 +409,10 @@ const executeInternal = async (runConfig)=>{
533
409
  if (fileContent && fileContent.trim().length > 0) {
534
410
  logger.info('FILE_CONTENT_USING: Using file content for commit message generation | Content Length: %d characters | Source: file content', fileContent.length);
535
411
  diffContent = fileContent;
536
- isUsingFileContent = true;
537
412
  hasActualChanges = true; // We have content to work with
538
413
  } else {
539
- var _runConfig_commit13;
540
- if ((_runConfig_commit13 = runConfig.commit) === null || _runConfig_commit13 === void 0 ? void 0 : _runConfig_commit13.sendit) {
414
+ var _runConfig_commit17;
415
+ if ((_runConfig_commit17 = runConfig.commit) === null || _runConfig_commit17 === void 0 ? void 0 : _runConfig_commit17.sendit) {
541
416
  logger.info('COMMIT_SKIPPED: Skipping commit operation | Reason: No changes detected | Action: None');
542
417
  return 'No changes to commit.';
543
418
  } else {
@@ -589,122 +464,68 @@ const executeInternal = async (runConfig)=>{
589
464
  }
590
465
  // Create adapters for ai-service
591
466
  const aiConfig = toAIConfig(runConfig);
592
- const aiStorageAdapter = createStorageAdapter();
467
+ const aiStorageAdapter = createStorageAdapter(outputDirectory);
593
468
  const aiLogger = createLoggerAdapter(isDryRun);
594
- // Define promptContext for use in both agentic and traditional modes
595
- const promptContent = {
596
- diffContent,
597
- userDirection,
598
- isFileContent: isUsingFileContent,
599
- githubIssuesContext
600
- };
469
+ // Read context from files if provided
470
+ const contextFromFiles = await readContextFiles((_runConfig_commit4 = runConfig.commit) === null || _runConfig_commit4 === void 0 ? void 0 : _runConfig_commit4.contextFiles, logger);
471
+ // Combine file context with existing context
472
+ const combinedContext = [
473
+ (_runConfig_commit5 = runConfig.commit) === null || _runConfig_commit5 === void 0 ? void 0 : _runConfig_commit5.context,
474
+ contextFromFiles
475
+ ].filter(Boolean).join('\n\n---\n\n');
476
+ // Define promptContext for use in interactive improvements
601
477
  const promptContext = {
602
478
  logContext,
603
- context: (_runConfig_commit4 = runConfig.commit) === null || _runConfig_commit4 === void 0 ? void 0 : _runConfig_commit4.context,
479
+ context: combinedContext || undefined,
604
480
  directories: runConfig.contextDirectories
605
481
  };
606
- let rawSummary;
607
- // Check if agentic mode is enabled
608
- if ((_runConfig_commit5 = runConfig.commit) === null || _runConfig_commit5 === void 0 ? void 0 : _runConfig_commit5.agentic) {
609
- var _runConfig_commit14, _aiConfig_commands_commit, _aiConfig_commands, _runConfig_commit15, _aiConfig_commands_commit1, _aiConfig_commands1, _runConfig_commit16, _runConfig_commit17;
610
- logger.info('šŸ¤– Using agentic mode for commit message generation');
611
- // Announce self-reflection if enabled
612
- if ((_runConfig_commit14 = runConfig.commit) === null || _runConfig_commit14 === void 0 ? void 0 : _runConfig_commit14.selfReflection) {
613
- logger.info('šŸ“Š Self-reflection enabled - detailed analysis will be generated');
614
- }
615
- // Get list of changed files
616
- const changedFilesResult = await run(`git diff --name-only ${cached ? '--cached' : ''}`);
617
- const changedFilesOutput = typeof changedFilesResult === 'string' ? changedFilesResult : changedFilesResult.stdout;
618
- const changedFiles = changedFilesOutput.split('\n').filter((f)=>f.trim().length > 0);
619
- logger.debug('Changed files for agentic analysis: %d files', changedFiles.length);
620
- // Run agentic commit generation
621
- const agenticResult = await runAgenticCommit({
622
- changedFiles,
623
- diffContent,
624
- userDirection,
625
- logContext,
626
- model: ((_aiConfig_commands = aiConfig.commands) === null || _aiConfig_commands === void 0 ? void 0 : (_aiConfig_commands_commit = _aiConfig_commands.commit) === null || _aiConfig_commands_commit === void 0 ? void 0 : _aiConfig_commands_commit.model) || aiConfig.model,
627
- maxIterations: ((_runConfig_commit15 = runConfig.commit) === null || _runConfig_commit15 === void 0 ? void 0 : _runConfig_commit15.maxAgenticIterations) || 10,
628
- debug: runConfig.debug,
629
- debugRequestFile: getOutputPath(outputDirectory, getTimestampedRequestFilename('commit-agentic')),
630
- debugResponseFile: getOutputPath(outputDirectory, getTimestampedResponseFilename('commit-agentic')),
631
- storage: aiStorageAdapter,
632
- logger: aiLogger,
633
- openaiReasoning: ((_aiConfig_commands1 = aiConfig.commands) === null || _aiConfig_commands1 === void 0 ? void 0 : (_aiConfig_commands_commit1 = _aiConfig_commands1.commit) === null || _aiConfig_commands_commit1 === void 0 ? void 0 : _aiConfig_commands_commit1.reasoning) || aiConfig.reasoning
634
- });
635
- logger.info('šŸ” Agentic analysis complete: %d iterations, %d tool calls', agenticResult.iterations, agenticResult.toolCallsExecuted);
636
- // Generate self-reflection output if enabled
637
- if ((_runConfig_commit16 = runConfig.commit) === null || _runConfig_commit16 === void 0 ? void 0 : _runConfig_commit16.selfReflection) {
638
- await generateSelfReflection(agenticResult, outputDirectory, storage, logger);
639
- }
640
- // Check for suggested splits
641
- if (agenticResult.suggestedSplits.length > 1 && ((_runConfig_commit17 = runConfig.commit) === null || _runConfig_commit17 === void 0 ? void 0 : _runConfig_commit17.allowCommitSplitting)) {
642
- logger.info('\nšŸ“‹ Agent suggests splitting this into %d commits:', agenticResult.suggestedSplits.length);
643
- for(let i = 0; i < agenticResult.suggestedSplits.length; i++){
644
- const split = agenticResult.suggestedSplits[i];
645
- logger.info('\nCommit %d (%d files):', i + 1, split.files.length);
646
- logger.info(' Files: %s', split.files.join(', '));
647
- logger.info(' Rationale: %s', split.rationale);
648
- logger.info(' Message: %s', split.message);
649
- }
650
- logger.info('\nāš ļø Commit splitting is not yet automated. Please stage and commit files separately.');
651
- logger.info('Using combined message for now...\n');
652
- } else if (agenticResult.suggestedSplits.length > 1) {
653
- logger.debug('Agent suggested %d splits but commit splitting is not enabled', agenticResult.suggestedSplits.length);
654
- }
655
- rawSummary = agenticResult.commitMessage;
656
- } else {
657
- var _aiConfig_commands_commit2, _aiConfig_commands2, _aiConfig_commands_commit3, _aiConfig_commands3;
658
- // Traditional single-shot approach
659
- const prompt = await createCommitPrompt(promptConfig, promptContent, promptContext);
660
- // Get the appropriate model for the commit command
661
- const modelToUse = ((_aiConfig_commands2 = aiConfig.commands) === null || _aiConfig_commands2 === void 0 ? void 0 : (_aiConfig_commands_commit2 = _aiConfig_commands2.commit) === null || _aiConfig_commands_commit2 === void 0 ? void 0 : _aiConfig_commands_commit2.model) || aiConfig.model || 'gpt-4o-mini';
662
- // Use consistent model for debug (fix hardcoded model)
663
- if (runConfig.debug) {
664
- const formattedPrompt = Formatter.create({
665
- logger
666
- }).formatPrompt(modelToUse, prompt);
667
- logger.silly('Formatted Prompt: %s', stringifyJSON(formattedPrompt));
482
+ // Announce self-reflection if enabled
483
+ if ((_runConfig_commit6 = runConfig.commit) === null || _runConfig_commit6 === void 0 ? void 0 : _runConfig_commit6.selfReflection) {
484
+ logger.info('šŸ“Š Self-reflection enabled - detailed analysis will be generated');
485
+ }
486
+ // Get list of changed files
487
+ const changedFilesResult = await run(`git diff --name-only ${cached ? '--cached' : ''}`);
488
+ const changedFilesOutput = typeof changedFilesResult === 'string' ? changedFilesResult : changedFilesResult.stdout;
489
+ const changedFiles = changedFilesOutput.split('\n').filter((f)=>f.trim().length > 0);
490
+ logger.debug('Changed files for analysis: %d files', changedFiles.length);
491
+ // Run agentic commit generation
492
+ const agenticResult = await runAgenticCommit({
493
+ changedFiles,
494
+ diffContent,
495
+ userDirection,
496
+ logContext,
497
+ model: ((_aiConfig_commands = aiConfig.commands) === null || _aiConfig_commands === void 0 ? void 0 : (_aiConfig_commands_commit = _aiConfig_commands.commit) === null || _aiConfig_commands_commit === void 0 ? void 0 : _aiConfig_commands_commit.model) || aiConfig.model,
498
+ maxIterations: ((_runConfig_commit7 = runConfig.commit) === null || _runConfig_commit7 === void 0 ? void 0 : _runConfig_commit7.maxAgenticIterations) || 10,
499
+ debug: runConfig.debug,
500
+ debugRequestFile: getOutputPath(outputDirectory, getTimestampedRequestFilename('commit')),
501
+ debugResponseFile: getOutputPath(outputDirectory, getTimestampedResponseFilename('commit')),
502
+ storage: aiStorageAdapter,
503
+ logger: aiLogger,
504
+ openaiReasoning: ((_aiConfig_commands1 = aiConfig.commands) === null || _aiConfig_commands1 === void 0 ? void 0 : (_aiConfig_commands_commit1 = _aiConfig_commands1.commit) === null || _aiConfig_commands_commit1 === void 0 ? void 0 : _aiConfig_commands_commit1.reasoning) || aiConfig.reasoning
505
+ });
506
+ const iterations = agenticResult.iterations || 0;
507
+ const toolCalls = agenticResult.toolCallsExecuted || 0;
508
+ logger.info(`šŸ” Analysis complete: ${iterations} iterations, ${toolCalls} tool calls`);
509
+ // Generate self-reflection output if enabled
510
+ if ((_runConfig_commit8 = runConfig.commit) === null || _runConfig_commit8 === void 0 ? void 0 : _runConfig_commit8.selfReflection) {
511
+ await generateSelfReflection(agenticResult, outputDirectory, storage, logger);
512
+ }
513
+ // Check for suggested splits
514
+ if (agenticResult.suggestedSplits.length > 1 && ((_runConfig_commit9 = runConfig.commit) === null || _runConfig_commit9 === void 0 ? void 0 : _runConfig_commit9.allowCommitSplitting)) {
515
+ logger.info('\nšŸ“‹ AI suggests splitting this into %d commits:', agenticResult.suggestedSplits.length);
516
+ for(let i = 0; i < agenticResult.suggestedSplits.length; i++){
517
+ const split = agenticResult.suggestedSplits[i];
518
+ logger.info('\nCommit %d (%d files):', i + 1, split.files.length);
519
+ logger.info(' Files: %s', split.files.join(', '));
520
+ logger.info(' Rationale: %s', split.rationale);
521
+ logger.info(' Message: %s', split.message);
668
522
  }
669
- const request = Formatter.create({
670
- logger
671
- }).formatPrompt(modelToUse, prompt);
672
- // Create retry callback that reduces diff size on token limit errors
673
- const createRetryCallback = (originalDiffContent)=>async (attempt)=>{
674
- var _runConfig_commit;
675
- logger.info('COMMIT_RETRY: Retrying with reduced diff size | Attempt: %d | Strategy: Truncate diff | Reason: Previous attempt failed', attempt);
676
- // Progressively reduce the diff size on retries
677
- const reductionFactor = Math.pow(0.5, attempt - 1); // 50% reduction per retry
678
- const reducedMaxDiffBytes = Math.max(512, Math.floor(maxDiffBytes * reductionFactor));
679
- logger.debug('Reducing maxDiffBytes from %d to %d for retry', maxDiffBytes, reducedMaxDiffBytes);
680
- // Re-truncate the diff with smaller limits
681
- const reducedDiffContent = originalDiffContent.length > reducedMaxDiffBytes ? truncateDiffByFiles(originalDiffContent, reducedMaxDiffBytes) : originalDiffContent;
682
- // Rebuild the prompt with the reduced diff
683
- const reducedPromptContent = {
684
- diffContent: reducedDiffContent,
685
- userDirection
686
- };
687
- const reducedPromptContext = {
688
- logContext,
689
- context: (_runConfig_commit = runConfig.commit) === null || _runConfig_commit === void 0 ? void 0 : _runConfig_commit.context,
690
- directories: runConfig.contextDirectories
691
- };
692
- const retryPrompt = await createCommitPrompt(promptConfig, reducedPromptContent, reducedPromptContext);
693
- const retryRequest = Formatter.create({
694
- logger
695
- }).formatPrompt(modelToUse, retryPrompt);
696
- return retryRequest.messages;
697
- };
698
- rawSummary = await createCompletionWithRetry(request.messages, {
699
- model: modelToUse,
700
- openaiReasoning: ((_aiConfig_commands3 = aiConfig.commands) === null || _aiConfig_commands3 === void 0 ? void 0 : (_aiConfig_commands_commit3 = _aiConfig_commands3.commit) === null || _aiConfig_commands_commit3 === void 0 ? void 0 : _aiConfig_commands_commit3.reasoning) || aiConfig.reasoning,
701
- debug: runConfig.debug,
702
- debugRequestFile: getOutputPath(runConfig.outputDirectory || DEFAULT_OUTPUT_DIRECTORY, getTimestampedRequestFilename('commit')),
703
- debugResponseFile: getOutputPath(runConfig.outputDirectory || DEFAULT_OUTPUT_DIRECTORY, getTimestampedResponseFilename('commit')),
704
- storage: aiStorageAdapter,
705
- logger: aiLogger
706
- }, createRetryCallback(diffContent));
523
+ logger.info('\nāš ļø Commit splitting is not yet automated. Please stage and commit files separately.');
524
+ logger.info('Using combined message for now...\n');
525
+ } else if (agenticResult.suggestedSplits.length > 1) {
526
+ logger.debug('AI suggested %d splits but commit splitting is not enabled', agenticResult.suggestedSplits.length);
707
527
  }
528
+ const rawSummary = agenticResult.commitMessage;
708
529
  // Apply stop-context filtering to commit message
709
530
  const filterResult = filterContent(rawSummary, runConfig.stopContext);
710
531
  const summary = filterResult.filtered;
@@ -712,8 +533,8 @@ const executeInternal = async (runConfig)=>{
712
533
  await saveCommitMessage(outputDirectory, summary, storage, logger);
713
534
  // šŸ›”ļø Universal Safety Check: Run before ANY commit operation
714
535
  // This protects both direct commits (--sendit) and automated commits (publish, etc.)
715
- const willCreateCommit = ((_runConfig_commit6 = runConfig.commit) === null || _runConfig_commit6 === void 0 ? void 0 : _runConfig_commit6.sendit) && hasActualChanges && cached;
716
- if (willCreateCommit && !((_runConfig_commit7 = runConfig.commit) === null || _runConfig_commit7 === void 0 ? void 0 : _runConfig_commit7.skipFileCheck) && !isDryRun) {
536
+ const willCreateCommit = ((_runConfig_commit10 = runConfig.commit) === null || _runConfig_commit10 === void 0 ? void 0 : _runConfig_commit10.sendit) && hasActualChanges && cached;
537
+ if (willCreateCommit && !((_runConfig_commit11 = runConfig.commit) === null || _runConfig_commit11 === void 0 ? void 0 : _runConfig_commit11.skipFileCheck) && !isDryRun) {
717
538
  logger.debug('Checking for file: dependencies before commit operation...');
718
539
  try {
719
540
  const fileDependencyIssues = await checkForFileDependencies(storage, process.cwd());
@@ -738,11 +559,11 @@ const executeInternal = async (runConfig)=>{
738
559
  logger.warn('Warning: Could not check for file: dependencies: %s', error.message);
739
560
  logger.warn('Proceeding with commit...');
740
561
  }
741
- } else if (((_runConfig_commit8 = runConfig.commit) === null || _runConfig_commit8 === void 0 ? void 0 : _runConfig_commit8.skipFileCheck) && willCreateCommit) {
562
+ } else if (((_runConfig_commit12 = runConfig.commit) === null || _runConfig_commit12 === void 0 ? void 0 : _runConfig_commit12.skipFileCheck) && willCreateCommit) {
742
563
  logger.warn('āš ļø Skipping file: dependency check as requested');
743
564
  }
744
565
  // Handle interactive mode
745
- if (((_runConfig_commit9 = runConfig.commit) === null || _runConfig_commit9 === void 0 ? void 0 : _runConfig_commit9.interactive) && !isDryRun) {
566
+ if (((_runConfig_commit13 = runConfig.commit) === null || _runConfig_commit13 === void 0 ? void 0 : _runConfig_commit13.interactive) && !isDryRun) {
746
567
  var _runConfig_commit19;
747
568
  requireTTY('Interactive mode requires a terminal. Use --sendit or --dry-run instead.');
748
569
  const interactiveResult = await handleInteractiveCommitFeedback(summary, runConfig, promptConfig, promptContext, outputDirectory, storage, diffContent, hasActualChanges, cached);
@@ -792,7 +613,7 @@ const executeInternal = async (runConfig)=>{
792
613
  logger.debug('Skipping sendit logic because user chose to skip in interactive mode');
793
614
  return summary;
794
615
  }
795
- if ((_runConfig_commit10 = runConfig.commit) === null || _runConfig_commit10 === void 0 ? void 0 : _runConfig_commit10.sendit) {
616
+ if ((_runConfig_commit14 = runConfig.commit) === null || _runConfig_commit14 === void 0 ? void 0 : _runConfig_commit14.sendit) {
796
617
  if (isDryRun) {
797
618
  var _runConfig_commit23, _runConfig_commit24;
798
619
  logger.info('Would commit with message: \n\n%s\n\n', summary);