@eldrforge/kodrdriv 1.2.123 → 1.2.125
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.
- package/README.md +1 -0
- package/dist/arguments.js +32 -2
- package/dist/arguments.js.map +1 -1
- package/dist/commands/commit.js +320 -75
- package/dist/commands/commit.js.map +1 -1
- package/dist/commands/publish.js +6 -2
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/release.js +9 -1
- package/dist/commands/release.js.map +1 -1
- package/dist/commands/review.js +13 -2
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/tree.js +133 -16
- package/dist/commands/tree.js.map +1 -1
- package/dist/constants.js +1 -1
- package/dist/constants.js.map +1 -1
- package/dist/logging.js +53 -5
- package/dist/logging.js.map +1 -1
- package/dist/util/general.js +3 -114
- package/dist/util/general.js.map +1 -1
- package/dist/util/stopContext.js +146 -0
- package/dist/util/stopContext.js.map +1 -0
- package/dist/util/storageAdapter.js +3 -0
- package/dist/util/storageAdapter.js.map +1 -1
- package/dist/util/validation.js +3 -3
- package/dist/util/validation.js.map +1 -1
- package/package.json +2 -2
package/dist/commands/commit.js
CHANGED
|
@@ -10,15 +10,202 @@ import { ValidationError, ExternalDependencyError, CommandError } from '../error
|
|
|
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
|
+
import { filterContent } from '../util/stopContext.js';
|
|
13
14
|
import { getOutputPath, getTimestampedResponseFilename, getTimestampedRequestFilename, getTimestampedCommitFilename } from '../util/general.js';
|
|
14
15
|
import { createStorage, stringifyJSON, checkForFileDependencies, logFileDependencyWarning, logFileDependencySuggestions } from '@eldrforge/shared';
|
|
15
16
|
import { getRecentClosedIssuesForCommit } from '@eldrforge/github-tools';
|
|
16
|
-
import { createCommitPrompt, createCompletionWithRetry, requireTTY, getUserChoice, STANDARD_CHOICES, getLLMFeedbackInEditor, editContentInEditor } from '@eldrforge/ai-service';
|
|
17
|
+
import { runAgenticCommit, createCommitPrompt, createCompletionWithRetry, requireTTY, getUserChoice, STANDARD_CHOICES, getLLMFeedbackInEditor, editContentInEditor } from '@eldrforge/ai-service';
|
|
17
18
|
import { improveContentWithLLM } from '../util/interactive.js';
|
|
18
19
|
import { toAIConfig } from '../util/aiAdapter.js';
|
|
19
20
|
import { createStorageAdapter } from '../util/storageAdapter.js';
|
|
20
21
|
import { createLoggerAdapter } from '../util/loggerAdapter.js';
|
|
21
22
|
|
|
23
|
+
// Helper function to generate self-reflection output
|
|
24
|
+
async function generateSelfReflection(agenticResult, outputDirectory, storage, logger) {
|
|
25
|
+
try {
|
|
26
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('.')[0];
|
|
27
|
+
const reflectionPath = getOutputPath(outputDirectory, `agentic-reflection-${timestamp}.md`);
|
|
28
|
+
// Calculate tool effectiveness metrics
|
|
29
|
+
const toolMetrics = agenticResult.toolMetrics || [];
|
|
30
|
+
const toolStats = new Map();
|
|
31
|
+
for (const metric of toolMetrics){
|
|
32
|
+
if (!toolStats.has(metric.name)) {
|
|
33
|
+
toolStats.set(metric.name, {
|
|
34
|
+
total: 0,
|
|
35
|
+
success: 0,
|
|
36
|
+
failures: 0,
|
|
37
|
+
totalDuration: 0
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const stats = toolStats.get(metric.name);
|
|
41
|
+
stats.total++;
|
|
42
|
+
stats.totalDuration += metric.duration;
|
|
43
|
+
if (metric.success) {
|
|
44
|
+
stats.success++;
|
|
45
|
+
} else {
|
|
46
|
+
stats.failures++;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Build reflection document
|
|
50
|
+
const sections = [];
|
|
51
|
+
sections.push('# Agentic Commit - Self-Reflection Report');
|
|
52
|
+
sections.push('');
|
|
53
|
+
sections.push(`Generated: ${new Date().toISOString()}`);
|
|
54
|
+
sections.push('');
|
|
55
|
+
sections.push('## Execution Summary');
|
|
56
|
+
sections.push('');
|
|
57
|
+
sections.push(`- **Iterations**: ${agenticResult.iterations}`);
|
|
58
|
+
sections.push(`- **Tool Calls**: ${agenticResult.toolCallsExecuted}`);
|
|
59
|
+
sections.push(`- **Unique Tools Used**: ${toolStats.size}`);
|
|
60
|
+
sections.push('');
|
|
61
|
+
sections.push('## Tool Effectiveness Analysis');
|
|
62
|
+
sections.push('');
|
|
63
|
+
if (toolStats.size === 0) {
|
|
64
|
+
sections.push('*No tools were executed during this run.*');
|
|
65
|
+
} else {
|
|
66
|
+
sections.push('| Tool | Calls | Success | Failures | Success Rate | Avg Duration |');
|
|
67
|
+
sections.push('|------|-------|---------|----------|--------------|--------------|');
|
|
68
|
+
for (const [toolName, stats] of Array.from(toolStats.entries()).sort((a, b)=>b[1].total - a[1].total)){
|
|
69
|
+
const successRate = (stats.success / stats.total * 100).toFixed(1);
|
|
70
|
+
const avgDuration = (stats.totalDuration / stats.total).toFixed(0);
|
|
71
|
+
sections.push(`| ${toolName} | ${stats.total} | ${stats.success} | ${stats.failures} | ${successRate}% | ${avgDuration}ms |`);
|
|
72
|
+
}
|
|
73
|
+
sections.push('');
|
|
74
|
+
sections.push('### Tool Performance Insights');
|
|
75
|
+
sections.push('');
|
|
76
|
+
// Identify problematic tools
|
|
77
|
+
const failedTools = Array.from(toolStats.entries()).filter(([_, stats])=>stats.failures > 0);
|
|
78
|
+
if (failedTools.length > 0) {
|
|
79
|
+
sections.push('**Tools with Failures:**');
|
|
80
|
+
for (const [toolName, stats] of failedTools){
|
|
81
|
+
const failureRate = (stats.failures / stats.total * 100).toFixed(1);
|
|
82
|
+
sections.push(`- ${toolName}: ${stats.failures}/${stats.total} failures (${failureRate}%)`);
|
|
83
|
+
}
|
|
84
|
+
sections.push('');
|
|
85
|
+
}
|
|
86
|
+
// Identify slow tools
|
|
87
|
+
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);
|
|
88
|
+
if (slowTools.length > 0) {
|
|
89
|
+
sections.push('**Slow Tools (>1s average):**');
|
|
90
|
+
for (const [toolName, stats] of slowTools){
|
|
91
|
+
const avgDuration = (stats.totalDuration / stats.total / 1000).toFixed(2);
|
|
92
|
+
sections.push(`- ${toolName}: ${avgDuration}s average`);
|
|
93
|
+
}
|
|
94
|
+
sections.push('');
|
|
95
|
+
}
|
|
96
|
+
// Identify most useful tools
|
|
97
|
+
sections.push('**Most Frequently Used:**');
|
|
98
|
+
const topTools = Array.from(toolStats.entries()).slice(0, 3);
|
|
99
|
+
for (const [toolName, stats] of topTools){
|
|
100
|
+
sections.push(`- ${toolName}: ${stats.total} calls`);
|
|
101
|
+
}
|
|
102
|
+
sections.push('');
|
|
103
|
+
}
|
|
104
|
+
sections.push('## Detailed Execution Timeline');
|
|
105
|
+
sections.push('');
|
|
106
|
+
if (toolMetrics.length === 0) {
|
|
107
|
+
sections.push('*No tool execution timeline available.*');
|
|
108
|
+
} else {
|
|
109
|
+
sections.push('| Time | Iteration | Tool | Result | Duration |');
|
|
110
|
+
sections.push('|------|-----------|------|--------|----------|');
|
|
111
|
+
for (const metric of toolMetrics){
|
|
112
|
+
const time = new Date(metric.timestamp).toLocaleTimeString();
|
|
113
|
+
const result = metric.success ? '✅ Success' : `❌ ${metric.error || 'Failed'}`;
|
|
114
|
+
sections.push(`| ${time} | ${metric.iteration} | ${metric.name} | ${result} | ${metric.duration}ms |`);
|
|
115
|
+
}
|
|
116
|
+
sections.push('');
|
|
117
|
+
}
|
|
118
|
+
sections.push('## Conversation History');
|
|
119
|
+
sections.push('');
|
|
120
|
+
sections.push('<details>');
|
|
121
|
+
sections.push('<summary>Click to expand full agentic interaction</summary>');
|
|
122
|
+
sections.push('');
|
|
123
|
+
sections.push('```json');
|
|
124
|
+
sections.push(JSON.stringify(agenticResult.conversationHistory, null, 2));
|
|
125
|
+
sections.push('```');
|
|
126
|
+
sections.push('');
|
|
127
|
+
sections.push('</details>');
|
|
128
|
+
sections.push('');
|
|
129
|
+
sections.push('## Generated Commit Message');
|
|
130
|
+
sections.push('');
|
|
131
|
+
sections.push('```');
|
|
132
|
+
sections.push(agenticResult.commitMessage);
|
|
133
|
+
sections.push('```');
|
|
134
|
+
sections.push('');
|
|
135
|
+
if (agenticResult.suggestedSplits && agenticResult.suggestedSplits.length > 1) {
|
|
136
|
+
sections.push('## Suggested Commit Splits');
|
|
137
|
+
sections.push('');
|
|
138
|
+
for(let i = 0; i < agenticResult.suggestedSplits.length; i++){
|
|
139
|
+
const split = agenticResult.suggestedSplits[i];
|
|
140
|
+
sections.push(`### Split ${i + 1}`);
|
|
141
|
+
sections.push('');
|
|
142
|
+
sections.push(`**Files**: ${split.files.join(', ')}`);
|
|
143
|
+
sections.push('');
|
|
144
|
+
sections.push(`**Rationale**: ${split.rationale}`);
|
|
145
|
+
sections.push('');
|
|
146
|
+
sections.push(`**Message**:`);
|
|
147
|
+
sections.push('```');
|
|
148
|
+
sections.push(split.message);
|
|
149
|
+
sections.push('```');
|
|
150
|
+
sections.push('');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
sections.push('## Recommendations for Improvement');
|
|
154
|
+
sections.push('');
|
|
155
|
+
// Generate recommendations based on metrics
|
|
156
|
+
const recommendations = [];
|
|
157
|
+
// Recalculate failed tools for recommendations
|
|
158
|
+
const toolsWithFailures = Array.from(toolStats.entries()).filter(([_, stats])=>stats.failures > 0);
|
|
159
|
+
if (toolsWithFailures.length > 0) {
|
|
160
|
+
recommendations.push('- **Tool Failures**: Investigate and fix tools that are failing. This may indicate issues with error handling or tool implementation.');
|
|
161
|
+
}
|
|
162
|
+
// Recalculate slow tools for recommendations
|
|
163
|
+
const slowToolsForRecs = Array.from(toolStats.entries()).filter(([_, stats])=>stats.totalDuration / stats.total > 1000);
|
|
164
|
+
if (slowToolsForRecs.length > 0) {
|
|
165
|
+
recommendations.push('- **Performance**: Consider optimizing slow tools or caching results to improve execution speed.');
|
|
166
|
+
}
|
|
167
|
+
if (agenticResult.iterations >= (agenticResult.maxIterations || 10)) {
|
|
168
|
+
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.');
|
|
169
|
+
}
|
|
170
|
+
const underutilizedTools = Array.from(toolStats.entries()).filter(([_, stats])=>stats.total === 1);
|
|
171
|
+
if (underutilizedTools.length > 3) {
|
|
172
|
+
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.');
|
|
173
|
+
}
|
|
174
|
+
if (recommendations.length === 0) {
|
|
175
|
+
sections.push('*No specific recommendations at this time. Execution appears optimal.*');
|
|
176
|
+
} else {
|
|
177
|
+
for (const rec of recommendations){
|
|
178
|
+
sections.push(rec);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
sections.push('');
|
|
182
|
+
// Write the reflection file
|
|
183
|
+
const reflectionContent = sections.join('\n');
|
|
184
|
+
await storage.writeFile(reflectionPath, reflectionContent, 'utf-8');
|
|
185
|
+
logger.info('');
|
|
186
|
+
logger.info('═'.repeat(80));
|
|
187
|
+
logger.info('📊 SELF-REFLECTION REPORT GENERATED');
|
|
188
|
+
logger.info('═'.repeat(80));
|
|
189
|
+
logger.info('');
|
|
190
|
+
logger.info('📁 Location: %s', reflectionPath);
|
|
191
|
+
logger.info('');
|
|
192
|
+
logger.info('📈 Report Summary:');
|
|
193
|
+
logger.info(' • %d iterations completed', agenticResult.iterations);
|
|
194
|
+
logger.info(' • %d tool calls executed', agenticResult.toolCallsExecuted);
|
|
195
|
+
logger.info(' • %d unique tools used', toolStats.size);
|
|
196
|
+
logger.info('');
|
|
197
|
+
logger.info('💡 Use this report to:');
|
|
198
|
+
logger.info(' • Understand which tools were most effective');
|
|
199
|
+
logger.info(' • Identify performance bottlenecks');
|
|
200
|
+
logger.info(' • Review the complete agentic conversation');
|
|
201
|
+
logger.info(' • Improve tool implementation based on metrics');
|
|
202
|
+
logger.info('');
|
|
203
|
+
logger.info('═'.repeat(80));
|
|
204
|
+
} catch (error) {
|
|
205
|
+
logger.warn('Failed to generate self-reflection output: %s', error.message);
|
|
206
|
+
logger.debug('Self-reflection error details:', error);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
22
209
|
// Helper function to get current version from package.json
|
|
23
210
|
async function getCurrentVersion(storage) {
|
|
24
211
|
try {
|
|
@@ -257,7 +444,7 @@ const saveCommitMessage = async (outputDirectory, summary, storage, logger)=>{
|
|
|
257
444
|
}
|
|
258
445
|
};
|
|
259
446
|
const executeInternal = async (runConfig)=>{
|
|
260
|
-
var _runConfig_commit, _runConfig_commit1, _runConfig_commit2, _runConfig_commit3, _runConfig_commit4,
|
|
447
|
+
var _runConfig_commit, _runConfig_commit1, _runConfig_commit2, _runConfig_commit3, _runConfig_commit4, _runConfig_commit5, _runConfig_commit6, _runConfig_commit7, _runConfig_commit8, _runConfig_commit9, _runConfig_commit10;
|
|
261
448
|
const isDryRun = runConfig.dryRun || false;
|
|
262
449
|
const logger = getDryRunLogger(isDryRun);
|
|
263
450
|
// Track if user explicitly chose to skip in interactive mode
|
|
@@ -293,9 +480,9 @@ const executeInternal = async (runConfig)=>{
|
|
|
293
480
|
if (!hasActualChanges) {
|
|
294
481
|
const criticalChanges = await hasCriticalExcludedChanges();
|
|
295
482
|
if (criticalChanges.hasChanges) {
|
|
296
|
-
var
|
|
483
|
+
var _runConfig_commit11;
|
|
297
484
|
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(', '));
|
|
298
|
-
if (((
|
|
485
|
+
if (((_runConfig_commit11 = runConfig.commit) === null || _runConfig_commit11 === void 0 ? void 0 : _runConfig_commit11.sendit) && !isDryRun) {
|
|
299
486
|
// In sendit mode, automatically include critical files
|
|
300
487
|
logger.info('SENDIT_INCLUDING_CRITICAL: SendIt mode including critical files in diff | Purpose: Ensure all important changes are captured');
|
|
301
488
|
var _runConfig_excludedPatterns1;
|
|
@@ -327,10 +514,10 @@ const executeInternal = async (runConfig)=>{
|
|
|
327
514
|
}
|
|
328
515
|
}
|
|
329
516
|
} else {
|
|
330
|
-
var
|
|
517
|
+
var _runConfig_commit12;
|
|
331
518
|
// No changes at all - try fallback to file content for new repositories
|
|
332
519
|
logger.info('NO_CHANGES_DETECTED: No changes found in working directory | Status: clean | Action: Nothing to commit');
|
|
333
|
-
if (((
|
|
520
|
+
if (((_runConfig_commit12 = runConfig.commit) === null || _runConfig_commit12 === void 0 ? void 0 : _runConfig_commit12.sendit) && !isDryRun) {
|
|
334
521
|
logger.warn('No changes detected to commit. Skipping commit operation.');
|
|
335
522
|
return 'No changes to commit.';
|
|
336
523
|
} else {
|
|
@@ -350,8 +537,8 @@ const executeInternal = async (runConfig)=>{
|
|
|
350
537
|
isUsingFileContent = true;
|
|
351
538
|
hasActualChanges = true; // We have content to work with
|
|
352
539
|
} else {
|
|
353
|
-
var
|
|
354
|
-
if ((
|
|
540
|
+
var _runConfig_commit13;
|
|
541
|
+
if ((_runConfig_commit13 = runConfig.commit) === null || _runConfig_commit13 === void 0 ? void 0 : _runConfig_commit13.sendit) {
|
|
355
542
|
logger.info('COMMIT_SKIPPED: Skipping commit operation | Reason: No changes detected | Action: None');
|
|
356
543
|
return 'No changes to commit.';
|
|
357
544
|
} else {
|
|
@@ -405,6 +592,7 @@ const executeInternal = async (runConfig)=>{
|
|
|
405
592
|
const aiConfig = toAIConfig(runConfig);
|
|
406
593
|
const aiStorageAdapter = createStorageAdapter();
|
|
407
594
|
const aiLogger = createLoggerAdapter(isDryRun);
|
|
595
|
+
// Define promptContext for use in both agentic and traditional modes
|
|
408
596
|
const promptContent = {
|
|
409
597
|
diffContent,
|
|
410
598
|
userDirection,
|
|
@@ -416,65 +604,122 @@ const executeInternal = async (runConfig)=>{
|
|
|
416
604
|
context: (_runConfig_commit4 = runConfig.commit) === null || _runConfig_commit4 === void 0 ? void 0 : _runConfig_commit4.context,
|
|
417
605
|
directories: runConfig.contextDirectories
|
|
418
606
|
};
|
|
419
|
-
|
|
420
|
-
//
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
607
|
+
let rawSummary;
|
|
608
|
+
// Check if agentic mode is enabled
|
|
609
|
+
if ((_runConfig_commit5 = runConfig.commit) === null || _runConfig_commit5 === void 0 ? void 0 : _runConfig_commit5.agentic) {
|
|
610
|
+
var _runConfig_commit14, _aiConfig_commands_commit, _aiConfig_commands, _runConfig_commit15, _aiConfig_commands_commit1, _aiConfig_commands1, _runConfig_commit16, _runConfig_commit17;
|
|
611
|
+
logger.info('🤖 Using agentic mode for commit message generation');
|
|
612
|
+
// Announce self-reflection if enabled
|
|
613
|
+
if ((_runConfig_commit14 = runConfig.commit) === null || _runConfig_commit14 === void 0 ? void 0 : _runConfig_commit14.selfReflection) {
|
|
614
|
+
logger.info('📊 Self-reflection enabled - detailed analysis will be generated');
|
|
615
|
+
}
|
|
616
|
+
// Get list of changed files
|
|
617
|
+
const changedFilesResult = await run(`git diff --name-only ${cached ? '--cached' : ''}`);
|
|
618
|
+
const changedFilesOutput = typeof changedFilesResult === 'string' ? changedFilesResult : changedFilesResult.stdout;
|
|
619
|
+
const changedFiles = changedFilesOutput.split('\n').filter((f)=>f.trim().length > 0);
|
|
620
|
+
logger.debug('Changed files for agentic analysis: %d files', changedFiles.length);
|
|
621
|
+
// Run agentic commit generation
|
|
622
|
+
const agenticResult = await runAgenticCommit({
|
|
623
|
+
changedFiles,
|
|
624
|
+
diffContent,
|
|
625
|
+
userDirection,
|
|
626
|
+
logContext,
|
|
627
|
+
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,
|
|
628
|
+
maxIterations: ((_runConfig_commit15 = runConfig.commit) === null || _runConfig_commit15 === void 0 ? void 0 : _runConfig_commit15.maxAgenticIterations) || 10,
|
|
629
|
+
debug: runConfig.debug,
|
|
630
|
+
debugRequestFile: getOutputPath(outputDirectory, getTimestampedRequestFilename('commit-agentic')),
|
|
631
|
+
debugResponseFile: getOutputPath(outputDirectory, getTimestampedResponseFilename('commit-agentic')),
|
|
632
|
+
storage: aiStorageAdapter,
|
|
633
|
+
logger: aiLogger,
|
|
634
|
+
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
|
|
635
|
+
});
|
|
636
|
+
logger.info('🔍 Agentic analysis complete: %d iterations, %d tool calls', agenticResult.iterations, agenticResult.toolCallsExecuted);
|
|
637
|
+
// Generate self-reflection output if enabled
|
|
638
|
+
if ((_runConfig_commit16 = runConfig.commit) === null || _runConfig_commit16 === void 0 ? void 0 : _runConfig_commit16.selfReflection) {
|
|
639
|
+
await generateSelfReflection(agenticResult, outputDirectory, storage, logger);
|
|
640
|
+
}
|
|
641
|
+
// Check for suggested splits
|
|
642
|
+
if (agenticResult.suggestedSplits.length > 1 && ((_runConfig_commit17 = runConfig.commit) === null || _runConfig_commit17 === void 0 ? void 0 : _runConfig_commit17.allowCommitSplitting)) {
|
|
643
|
+
logger.info('\n📋 Agent suggests splitting this into %d commits:', agenticResult.suggestedSplits.length);
|
|
644
|
+
for(let i = 0; i < agenticResult.suggestedSplits.length; i++){
|
|
645
|
+
const split = agenticResult.suggestedSplits[i];
|
|
646
|
+
logger.info('\nCommit %d (%d files):', i + 1, split.files.length);
|
|
647
|
+
logger.info(' Files: %s', split.files.join(', '));
|
|
648
|
+
logger.info(' Rationale: %s', split.rationale);
|
|
649
|
+
logger.info(' Message: %s', split.message);
|
|
650
|
+
}
|
|
651
|
+
logger.info('\n⚠️ Commit splitting is not yet automated. Please stage and commit files separately.');
|
|
652
|
+
logger.info('Using combined message for now...\n');
|
|
653
|
+
} else if (agenticResult.suggestedSplits.length > 1) {
|
|
654
|
+
logger.debug('Agent suggested %d splits but commit splitting is not enabled', agenticResult.suggestedSplits.length);
|
|
655
|
+
}
|
|
656
|
+
rawSummary = agenticResult.commitMessage;
|
|
657
|
+
} else {
|
|
658
|
+
var _aiConfig_commands_commit2, _aiConfig_commands2, _aiConfig_commands_commit3, _aiConfig_commands3;
|
|
659
|
+
// Traditional single-shot approach
|
|
660
|
+
const prompt = await createCommitPrompt(promptConfig, promptContent, promptContext);
|
|
661
|
+
// Get the appropriate model for the commit command
|
|
662
|
+
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';
|
|
663
|
+
// Use consistent model for debug (fix hardcoded model)
|
|
664
|
+
if (runConfig.debug) {
|
|
665
|
+
const formattedPrompt = Formatter.create({
|
|
666
|
+
logger
|
|
667
|
+
}).formatPrompt(modelToUse, prompt);
|
|
668
|
+
logger.silly('Formatted Prompt: %s', stringifyJSON(formattedPrompt));
|
|
669
|
+
}
|
|
670
|
+
const request = Formatter.create({
|
|
425
671
|
logger
|
|
426
672
|
}).formatPrompt(modelToUse, prompt);
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
673
|
+
// Create retry callback that reduces diff size on token limit errors
|
|
674
|
+
const createRetryCallback = (originalDiffContent)=>async (attempt)=>{
|
|
675
|
+
var _runConfig_commit;
|
|
676
|
+
logger.info('COMMIT_RETRY: Retrying with reduced diff size | Attempt: %d | Strategy: Truncate diff | Reason: Previous attempt failed', attempt);
|
|
677
|
+
// Progressively reduce the diff size on retries
|
|
678
|
+
const reductionFactor = Math.pow(0.5, attempt - 1); // 50% reduction per retry
|
|
679
|
+
const reducedMaxDiffBytes = Math.max(512, Math.floor(maxDiffBytes * reductionFactor));
|
|
680
|
+
logger.debug('Reducing maxDiffBytes from %d to %d for retry', maxDiffBytes, reducedMaxDiffBytes);
|
|
681
|
+
// Re-truncate the diff with smaller limits
|
|
682
|
+
const reducedDiffContent = originalDiffContent.length > reducedMaxDiffBytes ? truncateDiffByFiles(originalDiffContent, reducedMaxDiffBytes) : originalDiffContent;
|
|
683
|
+
// Rebuild the prompt with the reduced diff
|
|
684
|
+
const reducedPromptContent = {
|
|
685
|
+
diffContent: reducedDiffContent,
|
|
686
|
+
userDirection
|
|
687
|
+
};
|
|
688
|
+
const reducedPromptContext = {
|
|
689
|
+
logContext,
|
|
690
|
+
context: (_runConfig_commit = runConfig.commit) === null || _runConfig_commit === void 0 ? void 0 : _runConfig_commit.context,
|
|
691
|
+
directories: runConfig.contextDirectories
|
|
692
|
+
};
|
|
693
|
+
const retryPrompt = await createCommitPrompt(promptConfig, reducedPromptContent, reducedPromptContext);
|
|
694
|
+
const retryRequest = Formatter.create({
|
|
695
|
+
logger
|
|
696
|
+
}).formatPrompt(modelToUse, retryPrompt);
|
|
697
|
+
return retryRequest.messages;
|
|
451
698
|
};
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
logger: aiLogger
|
|
466
|
-
}, createRetryCallback(diffContent));
|
|
699
|
+
rawSummary = await createCompletionWithRetry(request.messages, {
|
|
700
|
+
model: modelToUse,
|
|
701
|
+
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,
|
|
702
|
+
debug: runConfig.debug,
|
|
703
|
+
debugRequestFile: getOutputPath(runConfig.outputDirectory || DEFAULT_OUTPUT_DIRECTORY, getTimestampedRequestFilename('commit')),
|
|
704
|
+
debugResponseFile: getOutputPath(runConfig.outputDirectory || DEFAULT_OUTPUT_DIRECTORY, getTimestampedResponseFilename('commit')),
|
|
705
|
+
storage: aiStorageAdapter,
|
|
706
|
+
logger: aiLogger
|
|
707
|
+
}, createRetryCallback(diffContent));
|
|
708
|
+
}
|
|
709
|
+
// Apply stop-context filtering to commit message
|
|
710
|
+
const filterResult = filterContent(rawSummary, runConfig.stopContext);
|
|
711
|
+
const summary = filterResult.filtered;
|
|
467
712
|
// Save timestamped copy of commit message with better error handling
|
|
468
713
|
await saveCommitMessage(outputDirectory, summary, storage, logger);
|
|
469
714
|
// 🛡️ Universal Safety Check: Run before ANY commit operation
|
|
470
715
|
// This protects both direct commits (--sendit) and automated commits (publish, etc.)
|
|
471
|
-
const willCreateCommit = ((
|
|
472
|
-
if (willCreateCommit && !((
|
|
716
|
+
const willCreateCommit = ((_runConfig_commit6 = runConfig.commit) === null || _runConfig_commit6 === void 0 ? void 0 : _runConfig_commit6.sendit) && hasActualChanges && cached;
|
|
717
|
+
if (willCreateCommit && !((_runConfig_commit7 = runConfig.commit) === null || _runConfig_commit7 === void 0 ? void 0 : _runConfig_commit7.skipFileCheck) && !isDryRun) {
|
|
473
718
|
logger.debug('Checking for file: dependencies before commit operation...');
|
|
474
719
|
try {
|
|
475
720
|
const fileDependencyIssues = await checkForFileDependencies(storage, process.cwd());
|
|
476
721
|
if (fileDependencyIssues.length > 0) {
|
|
477
|
-
var
|
|
722
|
+
var _runConfig_commit18;
|
|
478
723
|
logger.error('🚫 COMMIT BLOCKED: Found file: dependencies that should not be committed!');
|
|
479
724
|
logger.error('');
|
|
480
725
|
logFileDependencyWarning(fileDependencyIssues, 'commit');
|
|
@@ -482,7 +727,7 @@ const executeInternal = async (runConfig)=>{
|
|
|
482
727
|
logger.error('Generated commit message was:');
|
|
483
728
|
logger.error('%s', summary);
|
|
484
729
|
logger.error('');
|
|
485
|
-
if ((
|
|
730
|
+
if ((_runConfig_commit18 = runConfig.commit) === null || _runConfig_commit18 === void 0 ? void 0 : _runConfig_commit18.sendit) {
|
|
486
731
|
logger.error('To bypass this check, use: kodrdriv commit --skip-file-check --sendit');
|
|
487
732
|
} else {
|
|
488
733
|
logger.error('To bypass this check, add skipFileCheck: true to your commit configuration');
|
|
@@ -494,12 +739,12 @@ const executeInternal = async (runConfig)=>{
|
|
|
494
739
|
logger.warn('Warning: Could not check for file: dependencies: %s', error.message);
|
|
495
740
|
logger.warn('Proceeding with commit...');
|
|
496
741
|
}
|
|
497
|
-
} else if (((
|
|
742
|
+
} else if (((_runConfig_commit8 = runConfig.commit) === null || _runConfig_commit8 === void 0 ? void 0 : _runConfig_commit8.skipFileCheck) && willCreateCommit) {
|
|
498
743
|
logger.warn('⚠️ Skipping file: dependency check as requested');
|
|
499
744
|
}
|
|
500
745
|
// Handle interactive mode
|
|
501
|
-
if (((
|
|
502
|
-
var
|
|
746
|
+
if (((_runConfig_commit9 = runConfig.commit) === null || _runConfig_commit9 === void 0 ? void 0 : _runConfig_commit9.interactive) && !isDryRun) {
|
|
747
|
+
var _runConfig_commit19;
|
|
503
748
|
requireTTY('Interactive mode requires a terminal. Use --sendit or --dry-run instead.');
|
|
504
749
|
const interactiveResult = await handleInteractiveCommitFeedback(summary, runConfig, promptConfig, promptContext, outputDirectory, storage, diffContent, hasActualChanges, cached);
|
|
505
750
|
if (interactiveResult.action === 'skip') {
|
|
@@ -509,23 +754,23 @@ const executeInternal = async (runConfig)=>{
|
|
|
509
754
|
return interactiveResult.finalMessage;
|
|
510
755
|
}
|
|
511
756
|
// User chose to commit - check if sendit is enabled to determine what action to take
|
|
512
|
-
const senditEnabled = (
|
|
757
|
+
const senditEnabled = (_runConfig_commit19 = runConfig.commit) === null || _runConfig_commit19 === void 0 ? void 0 : _runConfig_commit19.sendit;
|
|
513
758
|
const willActuallyCommit = senditEnabled && hasActualChanges && cached;
|
|
514
759
|
if (willActuallyCommit) {
|
|
515
|
-
var
|
|
516
|
-
const commitAction = ((
|
|
760
|
+
var _runConfig_commit20;
|
|
761
|
+
const commitAction = ((_runConfig_commit20 = runConfig.commit) === null || _runConfig_commit20 === void 0 ? void 0 : _runConfig_commit20.amend) ? 'amending last commit' : 'committing';
|
|
517
762
|
logger.info('SENDIT_EXECUTING: SendIt enabled, executing commit action | Action: %s | Message Length: %d | Final Message: \n\n%s\n\n', commitAction.charAt(0).toUpperCase() + commitAction.slice(1), interactiveResult.finalMessage.length, interactiveResult.finalMessage);
|
|
518
763
|
try {
|
|
519
|
-
var
|
|
764
|
+
var _runConfig_commit21, _runConfig_commit22;
|
|
520
765
|
const validatedSummary = validateString(interactiveResult.finalMessage, 'commit summary');
|
|
521
766
|
const escapedSummary = shellescape([
|
|
522
767
|
validatedSummary
|
|
523
768
|
]);
|
|
524
|
-
const commitCommand = ((
|
|
769
|
+
const commitCommand = ((_runConfig_commit21 = runConfig.commit) === null || _runConfig_commit21 === void 0 ? void 0 : _runConfig_commit21.amend) ? `git commit --amend -m ${escapedSummary}` : `git commit -m ${escapedSummary}`;
|
|
525
770
|
await run(commitCommand);
|
|
526
771
|
logger.info('COMMIT_SUCCESS: Commit operation completed successfully | Status: committed | Action: Changes saved to repository');
|
|
527
772
|
// Push if requested
|
|
528
|
-
await pushCommit((
|
|
773
|
+
await pushCommit((_runConfig_commit22 = runConfig.commit) === null || _runConfig_commit22 === void 0 ? void 0 : _runConfig_commit22.push, logger, isDryRun);
|
|
529
774
|
} catch (error) {
|
|
530
775
|
logger.error('Failed to commit:', error);
|
|
531
776
|
throw new ExternalDependencyError('Failed to create commit', 'git', error);
|
|
@@ -548,32 +793,32 @@ const executeInternal = async (runConfig)=>{
|
|
|
548
793
|
logger.debug('Skipping sendit logic because user chose to skip in interactive mode');
|
|
549
794
|
return summary;
|
|
550
795
|
}
|
|
551
|
-
if ((
|
|
796
|
+
if ((_runConfig_commit10 = runConfig.commit) === null || _runConfig_commit10 === void 0 ? void 0 : _runConfig_commit10.sendit) {
|
|
552
797
|
if (isDryRun) {
|
|
553
|
-
var
|
|
798
|
+
var _runConfig_commit23, _runConfig_commit24;
|
|
554
799
|
logger.info('Would commit with message: \n\n%s\n\n', summary);
|
|
555
|
-
const commitAction = ((
|
|
800
|
+
const commitAction = ((_runConfig_commit23 = runConfig.commit) === null || _runConfig_commit23 === void 0 ? void 0 : _runConfig_commit23.amend) ? 'git commit --amend -m <generated-message>' : 'git commit -m <generated-message>';
|
|
556
801
|
logger.info('Would execute: %s', commitAction);
|
|
557
802
|
// Show push command in dry run if requested
|
|
558
|
-
if ((
|
|
803
|
+
if ((_runConfig_commit24 = runConfig.commit) === null || _runConfig_commit24 === void 0 ? void 0 : _runConfig_commit24.push) {
|
|
559
804
|
const remote = typeof runConfig.commit.push === 'string' ? runConfig.commit.push : 'origin';
|
|
560
805
|
logger.info('Would push to %s with: git push %s', remote, remote);
|
|
561
806
|
}
|
|
562
807
|
} else if (hasActualChanges && cached) {
|
|
563
|
-
var
|
|
564
|
-
const commitAction = ((
|
|
808
|
+
var _runConfig_commit25;
|
|
809
|
+
const commitAction = ((_runConfig_commit25 = runConfig.commit) === null || _runConfig_commit25 === void 0 ? void 0 : _runConfig_commit25.amend) ? 'amending commit' : 'committing';
|
|
565
810
|
logger.info('SendIt mode enabled. %s with message: \n\n%s\n\n', commitAction.charAt(0).toUpperCase() + commitAction.slice(1), summary);
|
|
566
811
|
try {
|
|
567
|
-
var
|
|
812
|
+
var _runConfig_commit26, _runConfig_commit27;
|
|
568
813
|
const validatedSummary = validateString(summary, 'commit summary');
|
|
569
814
|
const escapedSummary = shellescape([
|
|
570
815
|
validatedSummary
|
|
571
816
|
]);
|
|
572
|
-
const commitCommand = ((
|
|
817
|
+
const commitCommand = ((_runConfig_commit26 = runConfig.commit) === null || _runConfig_commit26 === void 0 ? void 0 : _runConfig_commit26.amend) ? `git commit --amend -m ${escapedSummary}` : `git commit -m ${escapedSummary}`;
|
|
573
818
|
await run(commitCommand);
|
|
574
819
|
logger.info('Commit successful!');
|
|
575
820
|
// Push if requested
|
|
576
|
-
await pushCommit((
|
|
821
|
+
await pushCommit((_runConfig_commit27 = runConfig.commit) === null || _runConfig_commit27 === void 0 ? void 0 : _runConfig_commit27.push, logger, isDryRun);
|
|
577
822
|
} catch (error) {
|
|
578
823
|
logger.error('Failed to commit:', error);
|
|
579
824
|
throw new ExternalDependencyError('Failed to create commit', 'git', error);
|