@eldrforge/kodrdriv 1.2.134 → 1.2.137
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/.cursor/rules/no-local-dependencies.md +6 -0
- package/README.md +1 -0
- package/dist/application.js +32 -42
- package/dist/application.js.map +1 -1
- package/dist/arguments.js +3 -3
- package/dist/arguments.js.map +1 -1
- package/dist/constants.js +5 -7
- package/dist/constants.js.map +1 -1
- package/dist/logging.js +4 -32
- package/dist/logging.js.map +1 -1
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -1
- package/package.json +13 -8
- package/dist/commands/audio-commit.js +0 -152
- package/dist/commands/audio-commit.js.map +0 -1
- package/dist/commands/audio-review.js +0 -274
- package/dist/commands/audio-review.js.map +0 -1
- package/dist/commands/clean.js +0 -49
- package/dist/commands/clean.js.map +0 -1
- package/dist/commands/commit.js +0 -680
- package/dist/commands/commit.js.map +0 -1
- package/dist/commands/development.js +0 -467
- package/dist/commands/development.js.map +0 -1
- package/dist/commands/link.js +0 -646
- package/dist/commands/link.js.map +0 -1
- package/dist/commands/precommit.js +0 -99
- package/dist/commands/precommit.js.map +0 -1
- package/dist/commands/publish.js +0 -1432
- package/dist/commands/publish.js.map +0 -1
- package/dist/commands/release.js +0 -376
- package/dist/commands/release.js.map +0 -1
- package/dist/commands/review.js +0 -733
- package/dist/commands/review.js.map +0 -1
- package/dist/commands/select-audio.js +0 -46
- package/dist/commands/select-audio.js.map +0 -1
- package/dist/commands/tree.js +0 -2363
- package/dist/commands/tree.js.map +0 -1
- package/dist/commands/unlink.js +0 -537
- package/dist/commands/unlink.js.map +0 -1
- package/dist/commands/updates.js +0 -211
- package/dist/commands/updates.js.map +0 -1
- package/dist/commands/versions.js +0 -221
- package/dist/commands/versions.js.map +0 -1
- package/dist/content/diff.js +0 -346
- package/dist/content/diff.js.map +0 -1
- package/dist/content/files.js +0 -190
- package/dist/content/files.js.map +0 -1
- package/dist/content/log.js +0 -72
- package/dist/content/log.js.map +0 -1
- package/dist/util/aiAdapter.js +0 -28
- package/dist/util/aiAdapter.js.map +0 -1
- package/dist/util/fileLock.js +0 -241
- package/dist/util/fileLock.js.map +0 -1
- package/dist/util/general.js +0 -379
- package/dist/util/general.js.map +0 -1
- package/dist/util/gitMutex.js +0 -161
- package/dist/util/gitMutex.js.map +0 -1
- package/dist/util/interactive.js +0 -32
- package/dist/util/interactive.js.map +0 -1
- package/dist/util/loggerAdapter.js +0 -41
- package/dist/util/loggerAdapter.js.map +0 -1
- package/dist/util/performance.js +0 -134
- package/dist/util/performance.js.map +0 -1
- package/dist/util/precommitOptimizations.js +0 -310
- package/dist/util/precommitOptimizations.js.map +0 -1
- package/dist/util/stopContext.js +0 -146
- package/dist/util/stopContext.js.map +0 -1
- package/dist/util/storageAdapter.js +0 -31
- package/dist/util/storageAdapter.js.map +0 -1
- package/dist/util/validation.js +0 -45
- package/dist/util/validation.js.map +0 -1
- package/dist/utils/branchState.js +0 -700
- package/dist/utils/branchState.js.map +0 -1
package/dist/commands/commit.js
DELETED
|
@@ -1,680 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { Formatter } from '@riotprompt/riotprompt';
|
|
3
|
-
import 'dotenv/config';
|
|
4
|
-
import shellescape from 'shell-escape';
|
|
5
|
-
import { DEFAULT_MAX_DIFF_BYTES, DEFAULT_EXCLUDED_PATTERNS, DEFAULT_OUTPUT_DIRECTORY } from '../constants.js';
|
|
6
|
-
import { create, hasCriticalExcludedChanges, getMinimalExcludedPatterns, hasStagedChanges } from '../content/diff.js';
|
|
7
|
-
import { create as create$2 } from '../content/log.js';
|
|
8
|
-
import { create as create$1 } from '../content/files.js';
|
|
9
|
-
import { ValidationError, ExternalDependencyError, CommandError, createStorage, checkForFileDependencies, logFileDependencyWarning, logFileDependencySuggestions } from '@eldrforge/shared';
|
|
10
|
-
import { getDryRunLogger } from '../logging.js';
|
|
11
|
-
import { run, validateString, safeJsonParse, validatePackageJson } from '@eldrforge/git-tools';
|
|
12
|
-
import { sanitizeDirection } from '../util/validation.js';
|
|
13
|
-
import { filterContent } from '../util/stopContext.js';
|
|
14
|
-
import { getOutputPath, getTimestampedResponseFilename, getTimestampedRequestFilename, getTimestampedCommitFilename } from '../util/general.js';
|
|
15
|
-
import { getRecentClosedIssuesForCommit } from '@eldrforge/github-tools';
|
|
16
|
-
import { runAgenticCommit, requireTTY, generateReflectionReport, getUserChoice, STANDARD_CHOICES, getLLMFeedbackInEditor, editContentInEditor, createCompletionWithRetry, createCommitPrompt } from '@eldrforge/ai-service';
|
|
17
|
-
import { improveContentWithLLM } from '../util/interactive.js';
|
|
18
|
-
import { toAIConfig } from '../util/aiAdapter.js';
|
|
19
|
-
import { createStorageAdapter } from '../util/storageAdapter.js';
|
|
20
|
-
import { createLoggerAdapter } from '../util/loggerAdapter.js';
|
|
21
|
-
|
|
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
|
|
41
|
-
async function generateSelfReflection(agenticResult, outputDirectory, storage, logger) {
|
|
42
|
-
try {
|
|
43
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('.')[0];
|
|
44
|
-
const reflectionPath = getOutputPath(outputDirectory, `agentic-reflection-commit-${timestamp}.md`);
|
|
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');
|
|
58
|
-
logger.info('');
|
|
59
|
-
logger.info('═'.repeat(80));
|
|
60
|
-
logger.info('📊 SELF-REFLECTION REPORT GENERATED');
|
|
61
|
-
logger.info('═'.repeat(80));
|
|
62
|
-
logger.info('');
|
|
63
|
-
logger.info('📁 Location: %s', reflectionPath);
|
|
64
|
-
logger.info('');
|
|
65
|
-
logger.info('📈 Report Summary:');
|
|
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`);
|
|
72
|
-
logger.info('');
|
|
73
|
-
logger.info('💡 Use this report to:');
|
|
74
|
-
logger.info(' • Understand which tools were most effective');
|
|
75
|
-
logger.info(' • Identify performance bottlenecks');
|
|
76
|
-
logger.info(' • Review the complete agentic conversation');
|
|
77
|
-
logger.info(' • Improve tool implementation based on metrics');
|
|
78
|
-
logger.info('');
|
|
79
|
-
logger.info('═'.repeat(80));
|
|
80
|
-
} catch (error) {
|
|
81
|
-
logger.warn('Failed to generate self-reflection output: %s', error.message);
|
|
82
|
-
logger.debug('Self-reflection error details:', error);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
// Helper function to get current version from package.json
|
|
86
|
-
async function getCurrentVersion(storage) {
|
|
87
|
-
try {
|
|
88
|
-
const packageJsonContents = await storage.readFile('package.json', 'utf-8');
|
|
89
|
-
const packageJson = safeJsonParse(packageJsonContents, 'package.json');
|
|
90
|
-
const validated = validatePackageJson(packageJson, 'package.json');
|
|
91
|
-
return validated.version;
|
|
92
|
-
} catch {
|
|
93
|
-
// Return undefined if we can't read the version (not a critical failure)
|
|
94
|
-
return undefined;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
// Helper function to edit commit message using editor
|
|
98
|
-
async function editCommitMessageInteractively(commitMessage) {
|
|
99
|
-
const templateLines = [
|
|
100
|
-
'# Edit your commit message below. Lines starting with "#" will be ignored.',
|
|
101
|
-
'# Save and close the editor when you are done.'
|
|
102
|
-
];
|
|
103
|
-
const result = await editContentInEditor(commitMessage, templateLines, '.txt');
|
|
104
|
-
return result.content;
|
|
105
|
-
}
|
|
106
|
-
// Helper function to improve commit message using LLM
|
|
107
|
-
async function improveCommitMessageWithLLM(commitMessage, runConfig, promptConfig, promptContext, outputDirectory, diffContent) {
|
|
108
|
-
// Get user feedback on what to improve using the editor
|
|
109
|
-
const userFeedback = await getLLMFeedbackInEditor('commit message', commitMessage);
|
|
110
|
-
// Create AI config from kodrdriv config
|
|
111
|
-
const aiConfig = toAIConfig(runConfig);
|
|
112
|
-
const aiStorageAdapter = createStorageAdapter(outputDirectory);
|
|
113
|
-
const aiLogger = createLoggerAdapter(false);
|
|
114
|
-
const improvementConfig = {
|
|
115
|
-
contentType: 'commit message',
|
|
116
|
-
createImprovedPrompt: async (promptConfig, currentMessage, promptContext)=>{
|
|
117
|
-
var _aiConfig_commands_commit, _aiConfig_commands;
|
|
118
|
-
const improvementPromptContent = {
|
|
119
|
-
diffContent: diffContent,
|
|
120
|
-
userDirection: `Please improve this commit message based on the user's feedback: "${userFeedback}".
|
|
121
|
-
|
|
122
|
-
Current commit message: "${currentMessage}"
|
|
123
|
-
|
|
124
|
-
Please revise the commit message according to the user's feedback while maintaining accuracy and following conventional commit standards if appropriate.`
|
|
125
|
-
};
|
|
126
|
-
const prompt = await createCommitPrompt(promptConfig, improvementPromptContent, promptContext);
|
|
127
|
-
// Format the prompt into a proper request with messages
|
|
128
|
-
const modelToUse = ((_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 || 'gpt-4o-mini';
|
|
129
|
-
return Formatter.create({
|
|
130
|
-
logger: getDryRunLogger(false)
|
|
131
|
-
}).formatPrompt(modelToUse, prompt);
|
|
132
|
-
},
|
|
133
|
-
callLLM: async (request, runConfig, outputDirectory)=>{
|
|
134
|
-
var _aiConfig_commands_commit, _aiConfig_commands, _aiConfig_commands_commit1, _aiConfig_commands1;
|
|
135
|
-
return await createCompletionWithRetry(request.messages, {
|
|
136
|
-
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,
|
|
137
|
-
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,
|
|
138
|
-
debug: runConfig.debug,
|
|
139
|
-
debugRequestFile: getOutputPath(outputDirectory, getTimestampedRequestFilename('commit-improve')),
|
|
140
|
-
debugResponseFile: getOutputPath(outputDirectory, getTimestampedResponseFilename('commit-improve')),
|
|
141
|
-
storage: aiStorageAdapter,
|
|
142
|
-
logger: aiLogger
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
return await improveContentWithLLM(commitMessage, runConfig, promptConfig, promptContext, outputDirectory, improvementConfig);
|
|
147
|
-
}
|
|
148
|
-
// Interactive feedback loop for commit message
|
|
149
|
-
async function handleInteractiveCommitFeedback(commitMessage, runConfig, promptConfig, promptContext, outputDirectory, storage, diffContent, hasActualChanges, cached) {
|
|
150
|
-
var _runConfig_commit, _runConfig_commit1;
|
|
151
|
-
const logger = getDryRunLogger(false);
|
|
152
|
-
let currentMessage = commitMessage;
|
|
153
|
-
// Determine what the confirm action will do based on configuration
|
|
154
|
-
const senditEnabled = (_runConfig_commit = runConfig.commit) === null || _runConfig_commit === void 0 ? void 0 : _runConfig_commit.sendit;
|
|
155
|
-
const willActuallyCommit = senditEnabled && hasActualChanges && cached;
|
|
156
|
-
// Create dynamic confirm choice based on configuration
|
|
157
|
-
const isAmendMode = (_runConfig_commit1 = runConfig.commit) === null || _runConfig_commit1 === void 0 ? void 0 : _runConfig_commit1.amend;
|
|
158
|
-
const confirmChoice = willActuallyCommit ? {
|
|
159
|
-
key: 'c',
|
|
160
|
-
label: isAmendMode ? 'Amend last commit with this message (sendit enabled)' : 'Commit changes with this message (sendit enabled)'
|
|
161
|
-
} : {
|
|
162
|
-
key: 'c',
|
|
163
|
-
label: 'Accept message (you will need to commit manually)'
|
|
164
|
-
};
|
|
165
|
-
while(true){
|
|
166
|
-
// Display the current commit message
|
|
167
|
-
logger.info('\n📝 Generated Commit Message:');
|
|
168
|
-
logger.info('─'.repeat(50));
|
|
169
|
-
logger.info(currentMessage);
|
|
170
|
-
logger.info('─'.repeat(50));
|
|
171
|
-
// Show configuration status
|
|
172
|
-
if (senditEnabled) {
|
|
173
|
-
if (willActuallyCommit) {
|
|
174
|
-
logger.info('\nSENDIT_MODE_ACTIVE: SendIt mode enabled | Action: Commit choice will execute git commit automatically | Staged Changes: Available');
|
|
175
|
-
} else {
|
|
176
|
-
logger.info('\nSENDIT_MODE_NO_CHANGES: SendIt mode configured but no staged changes | Action: Only message save available | Staged Changes: None');
|
|
177
|
-
}
|
|
178
|
-
} else {
|
|
179
|
-
logger.info('\nSENDIT_MODE_INACTIVE: SendIt mode not active | Action: Accept choice will only save message | Commit: Manual');
|
|
180
|
-
}
|
|
181
|
-
// Get user choice
|
|
182
|
-
const userChoice = await getUserChoice('\nWhat would you like to do with this commit message?', [
|
|
183
|
-
confirmChoice,
|
|
184
|
-
STANDARD_CHOICES.EDIT,
|
|
185
|
-
STANDARD_CHOICES.SKIP,
|
|
186
|
-
STANDARD_CHOICES.IMPROVE
|
|
187
|
-
], {
|
|
188
|
-
nonTtyErrorSuggestions: [
|
|
189
|
-
'Use --sendit flag to auto-commit without review'
|
|
190
|
-
]
|
|
191
|
-
});
|
|
192
|
-
switch(userChoice){
|
|
193
|
-
case 'c':
|
|
194
|
-
return {
|
|
195
|
-
action: 'commit',
|
|
196
|
-
finalMessage: currentMessage
|
|
197
|
-
};
|
|
198
|
-
case 'e':
|
|
199
|
-
try {
|
|
200
|
-
currentMessage = await editCommitMessageInteractively(currentMessage);
|
|
201
|
-
} catch (error) {
|
|
202
|
-
logger.error(`Failed to edit commit message: ${error.message}`);
|
|
203
|
-
// Continue the loop to show options again
|
|
204
|
-
}
|
|
205
|
-
break;
|
|
206
|
-
case 's':
|
|
207
|
-
return {
|
|
208
|
-
action: 'skip',
|
|
209
|
-
finalMessage: currentMessage
|
|
210
|
-
};
|
|
211
|
-
case 'i':
|
|
212
|
-
try {
|
|
213
|
-
currentMessage = await improveCommitMessageWithLLM(currentMessage, runConfig, promptConfig, promptContext, outputDirectory, diffContent);
|
|
214
|
-
} catch (error) {
|
|
215
|
-
logger.error(`Failed to improve commit message: ${error.message}`);
|
|
216
|
-
// Continue the loop to show options again
|
|
217
|
-
}
|
|
218
|
-
break;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
// Helper function to check if there are any commits in the repository
|
|
223
|
-
const hasCommits = async ()=>{
|
|
224
|
-
try {
|
|
225
|
-
await run('git rev-parse HEAD');
|
|
226
|
-
return true;
|
|
227
|
-
} catch {
|
|
228
|
-
// No commits found or not a git repository
|
|
229
|
-
return false;
|
|
230
|
-
}
|
|
231
|
-
};
|
|
232
|
-
// Helper function to push the commit
|
|
233
|
-
const pushCommit = async (pushConfig, logger, isDryRun)=>{
|
|
234
|
-
if (!pushConfig) {
|
|
235
|
-
return; // No push requested
|
|
236
|
-
}
|
|
237
|
-
// Determine the remote to push to
|
|
238
|
-
let remote = 'origin';
|
|
239
|
-
if (typeof pushConfig === 'string') {
|
|
240
|
-
remote = pushConfig;
|
|
241
|
-
}
|
|
242
|
-
const pushCommand = `git push ${remote}`;
|
|
243
|
-
if (isDryRun) {
|
|
244
|
-
logger.info('Would push to %s with: %s', remote, pushCommand);
|
|
245
|
-
} else {
|
|
246
|
-
logger.info('🚀 Pushing to %s...', remote);
|
|
247
|
-
try {
|
|
248
|
-
await run(pushCommand);
|
|
249
|
-
logger.info('✅ Push successful!');
|
|
250
|
-
} catch (error) {
|
|
251
|
-
logger.error('Failed to push to %s: %s', remote, error.message);
|
|
252
|
-
throw new ExternalDependencyError(`Failed to push to ${remote}`, 'git', error);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
};
|
|
256
|
-
// Simplified cached determination with single check
|
|
257
|
-
const determineCachedState = async (config)=>{
|
|
258
|
-
var _config_commit, _config_commit1, _config_commit2;
|
|
259
|
-
// If amend is used, we use staged changes (since we're amending the last commit)
|
|
260
|
-
if ((_config_commit = config.commit) === null || _config_commit === void 0 ? void 0 : _config_commit.amend) {
|
|
261
|
-
// For amend mode, check that there's a previous commit to amend
|
|
262
|
-
const hasAnyCommits = await hasCommits();
|
|
263
|
-
if (!hasAnyCommits) {
|
|
264
|
-
throw new ValidationError('Cannot use --amend: no commits found in repository. Create an initial commit first.');
|
|
265
|
-
}
|
|
266
|
-
return true;
|
|
267
|
-
}
|
|
268
|
-
// If add is used, we always look at staged changes after add
|
|
269
|
-
if ((_config_commit1 = config.commit) === null || _config_commit1 === void 0 ? void 0 : _config_commit1.add) {
|
|
270
|
-
return true;
|
|
271
|
-
}
|
|
272
|
-
// If explicitly set, use that value
|
|
273
|
-
if (((_config_commit2 = config.commit) === null || _config_commit2 === void 0 ? void 0 : _config_commit2.cached) !== undefined) {
|
|
274
|
-
return config.commit.cached;
|
|
275
|
-
}
|
|
276
|
-
// Otherwise, check if there are staged changes
|
|
277
|
-
return await hasStagedChanges();
|
|
278
|
-
};
|
|
279
|
-
// Single validation of sendit + cached state
|
|
280
|
-
const validateSenditState = (config, cached, isDryRun, logger)=>{
|
|
281
|
-
var _config_commit;
|
|
282
|
-
if (((_config_commit = config.commit) === null || _config_commit === void 0 ? void 0 : _config_commit.sendit) && !cached && !isDryRun) {
|
|
283
|
-
const message = 'SendIt mode enabled, but no changes to commit.';
|
|
284
|
-
logger.warn(message);
|
|
285
|
-
return false; // Return false to indicate no changes to commit
|
|
286
|
-
}
|
|
287
|
-
return true; // Return true to indicate we can proceed
|
|
288
|
-
};
|
|
289
|
-
// Better file save handling with fallbacks
|
|
290
|
-
const saveCommitMessage = async (outputDirectory, summary, storage, logger)=>{
|
|
291
|
-
const timestampedFilename = getTimestampedCommitFilename();
|
|
292
|
-
const primaryPath = getOutputPath(outputDirectory, timestampedFilename);
|
|
293
|
-
try {
|
|
294
|
-
await storage.writeFile(primaryPath, summary, 'utf-8');
|
|
295
|
-
logger.debug('Saved timestamped commit message: %s', primaryPath);
|
|
296
|
-
return; // Success, no fallback needed
|
|
297
|
-
} catch (error) {
|
|
298
|
-
logger.warn('Failed to save commit message to primary location (%s): %s', primaryPath, error.message);
|
|
299
|
-
logger.debug('Primary save error details:', error);
|
|
300
|
-
// First fallback: try output directory root (in case subdirectory has issues)
|
|
301
|
-
try {
|
|
302
|
-
const outputRootPath = getOutputPath('output', timestampedFilename);
|
|
303
|
-
await storage.writeFile(outputRootPath, summary, 'utf-8');
|
|
304
|
-
logger.info('COMMIT_MESSAGE_SAVED_FALLBACK: Saved commit message to fallback location | Path: %s | Purpose: Preserve message for later use', outputRootPath);
|
|
305
|
-
return;
|
|
306
|
-
} catch (outputError) {
|
|
307
|
-
logger.warn('Failed to save to output directory fallback: %s', outputError.message);
|
|
308
|
-
}
|
|
309
|
-
// Last resort fallback: save to current directory (this creates the clutter!)
|
|
310
|
-
try {
|
|
311
|
-
const fallbackPath = `commit-message-${Date.now()}.txt`;
|
|
312
|
-
await storage.writeFile(fallbackPath, summary, 'utf-8');
|
|
313
|
-
logger.warn('⚠️ Saved commit message to current directory as last resort: %s', fallbackPath);
|
|
314
|
-
logger.warn('⚠️ This file should be moved to the output directory and may clutter your workspace');
|
|
315
|
-
} catch (fallbackError) {
|
|
316
|
-
logger.error('Failed to save commit message anywhere: %s', fallbackError.message);
|
|
317
|
-
logger.error('Commit message will only be available in console output');
|
|
318
|
-
// Continue execution - commit message is still returned
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
};
|
|
322
|
-
const executeInternal = async (runConfig)=>{
|
|
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;
|
|
324
|
-
const isDryRun = runConfig.dryRun || false;
|
|
325
|
-
const logger = getDryRunLogger(isDryRun);
|
|
326
|
-
// Track if user explicitly chose to skip in interactive mode
|
|
327
|
-
let userSkippedCommit = false;
|
|
328
|
-
if ((_runConfig_commit = runConfig.commit) === null || _runConfig_commit === void 0 ? void 0 : _runConfig_commit.add) {
|
|
329
|
-
if (isDryRun) {
|
|
330
|
-
logger.info('GIT_ADD_DRY_RUN: Would stage all changes | Mode: dry-run | Command: git add -A');
|
|
331
|
-
} else {
|
|
332
|
-
logger.info('GIT_ADD_STAGING: Adding all changes to index | Command: git add -A | Scope: all files | Purpose: Stage for commit');
|
|
333
|
-
await run('git add -A');
|
|
334
|
-
logger.info('GIT_ADD_SUCCESS: Successfully staged all changes | Command: git add -A | Status: completed');
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
// Determine cached state with single, clear logic
|
|
338
|
-
const cached = await determineCachedState(runConfig);
|
|
339
|
-
// Validate sendit state early - now returns boolean instead of throwing
|
|
340
|
-
validateSenditState(runConfig, cached, isDryRun, logger);
|
|
341
|
-
let diffContent = '';
|
|
342
|
-
var _runConfig_commit_maxDiffBytes;
|
|
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;
|
|
344
|
-
var _runConfig_excludedPatterns;
|
|
345
|
-
const options = {
|
|
346
|
-
cached,
|
|
347
|
-
excludedPatterns: (_runConfig_excludedPatterns = runConfig.excludedPatterns) !== null && _runConfig_excludedPatterns !== void 0 ? _runConfig_excludedPatterns : DEFAULT_EXCLUDED_PATTERNS,
|
|
348
|
-
maxDiffBytes
|
|
349
|
-
};
|
|
350
|
-
const diff = await create(options);
|
|
351
|
-
diffContent = await diff.get();
|
|
352
|
-
// Check if there are actually any changes in the diff
|
|
353
|
-
let hasActualChanges = diffContent.trim().length > 0;
|
|
354
|
-
// If no changes found with current patterns, check for critical excluded files
|
|
355
|
-
if (!hasActualChanges) {
|
|
356
|
-
const criticalChanges = await hasCriticalExcludedChanges();
|
|
357
|
-
if (criticalChanges.hasChanges) {
|
|
358
|
-
var _runConfig_commit15;
|
|
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(', '));
|
|
360
|
-
if (((_runConfig_commit15 = runConfig.commit) === null || _runConfig_commit15 === void 0 ? void 0 : _runConfig_commit15.sendit) && !isDryRun) {
|
|
361
|
-
// In sendit mode, automatically include critical files
|
|
362
|
-
logger.info('SENDIT_INCLUDING_CRITICAL: SendIt mode including critical files in diff | Purpose: Ensure all important changes are captured');
|
|
363
|
-
var _runConfig_excludedPatterns1;
|
|
364
|
-
const minimalPatterns = getMinimalExcludedPatterns((_runConfig_excludedPatterns1 = runConfig.excludedPatterns) !== null && _runConfig_excludedPatterns1 !== void 0 ? _runConfig_excludedPatterns1 : DEFAULT_EXCLUDED_PATTERNS);
|
|
365
|
-
const updatedOptions = {
|
|
366
|
-
...options,
|
|
367
|
-
excludedPatterns: minimalPatterns
|
|
368
|
-
};
|
|
369
|
-
const updatedDiff = await create(updatedOptions);
|
|
370
|
-
diffContent = await updatedDiff.get();
|
|
371
|
-
if (diffContent.trim().length > 0) {
|
|
372
|
-
logger.info('CRITICAL_FILES_INCLUDED: Successfully added critical files to diff | Status: ready for commit message generation');
|
|
373
|
-
// Update hasActualChanges since we now have content after including critical files
|
|
374
|
-
hasActualChanges = true;
|
|
375
|
-
} else {
|
|
376
|
-
logger.warn('No changes detected even after including critical files.');
|
|
377
|
-
return 'No changes to commit.';
|
|
378
|
-
}
|
|
379
|
-
} else {
|
|
380
|
-
// In non-sendit mode, suggest including the files
|
|
381
|
-
logger.warn('Consider including these files by using:');
|
|
382
|
-
var _runConfig_excludedPatterns2;
|
|
383
|
-
logger.warn(' kodrdriv commit --excluded-paths %s', ((_runConfig_excludedPatterns2 = runConfig.excludedPatterns) !== null && _runConfig_excludedPatterns2 !== void 0 ? _runConfig_excludedPatterns2 : DEFAULT_EXCLUDED_PATTERNS).filter((p)=>!criticalChanges.files.some((f)=>p.includes(f.split('/').pop() || ''))).map((p)=>`"${p}"`).join(' '));
|
|
384
|
-
logger.warn('Or run with --sendit to automatically include critical files.');
|
|
385
|
-
if (!isDryRun) {
|
|
386
|
-
return 'No changes to commit. Use suggestions above to include critical files.';
|
|
387
|
-
} else {
|
|
388
|
-
logger.info('Generating commit message template for future use...');
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
} else {
|
|
392
|
-
var _runConfig_commit16;
|
|
393
|
-
// No changes at all - try fallback to file content for new repositories
|
|
394
|
-
logger.info('NO_CHANGES_DETECTED: No changes found in working directory | Status: clean | Action: Nothing to commit');
|
|
395
|
-
if (((_runConfig_commit16 = runConfig.commit) === null || _runConfig_commit16 === void 0 ? void 0 : _runConfig_commit16.sendit) && !isDryRun) {
|
|
396
|
-
logger.warn('No changes detected to commit. Skipping commit operation.');
|
|
397
|
-
return 'No changes to commit.';
|
|
398
|
-
} else {
|
|
399
|
-
logger.info('NO_DIFF_FALLBACK: No diff content available | Action: Attempting to generate commit message from file content | Strategy: fallback');
|
|
400
|
-
var _runConfig_excludedPatterns3;
|
|
401
|
-
// Create file content collector as fallback
|
|
402
|
-
const fileOptions = {
|
|
403
|
-
excludedPatterns: (_runConfig_excludedPatterns3 = runConfig.excludedPatterns) !== null && _runConfig_excludedPatterns3 !== void 0 ? _runConfig_excludedPatterns3 : DEFAULT_EXCLUDED_PATTERNS,
|
|
404
|
-
maxTotalBytes: maxDiffBytes * 5,
|
|
405
|
-
workingDirectory: process.cwd()
|
|
406
|
-
};
|
|
407
|
-
const files = await create$1(fileOptions);
|
|
408
|
-
const fileContent = await files.get();
|
|
409
|
-
if (fileContent && fileContent.trim().length > 0) {
|
|
410
|
-
logger.info('FILE_CONTENT_USING: Using file content for commit message generation | Content Length: %d characters | Source: file content', fileContent.length);
|
|
411
|
-
diffContent = fileContent;
|
|
412
|
-
hasActualChanges = true; // We have content to work with
|
|
413
|
-
} else {
|
|
414
|
-
var _runConfig_commit17;
|
|
415
|
-
if ((_runConfig_commit17 = runConfig.commit) === null || _runConfig_commit17 === void 0 ? void 0 : _runConfig_commit17.sendit) {
|
|
416
|
-
logger.info('COMMIT_SKIPPED: Skipping commit operation | Reason: No changes detected | Action: None');
|
|
417
|
-
return 'No changes to commit.';
|
|
418
|
-
} else {
|
|
419
|
-
logger.info('COMMIT_TEMPLATE_GENERATING: Creating commit message template for future use | Reason: No changes | Purpose: Provide template');
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
const logOptions = {
|
|
426
|
-
limit: (_runConfig_commit2 = runConfig.commit) === null || _runConfig_commit2 === void 0 ? void 0 : _runConfig_commit2.messageLimit
|
|
427
|
-
};
|
|
428
|
-
const log = await create$2(logOptions);
|
|
429
|
-
const logContext = await log.get();
|
|
430
|
-
// Always ensure output directory exists for request/response files and GitHub issues lookup
|
|
431
|
-
const outputDirectory = runConfig.outputDirectory || DEFAULT_OUTPUT_DIRECTORY;
|
|
432
|
-
const storage = createStorage();
|
|
433
|
-
await storage.ensureDirectory(outputDirectory);
|
|
434
|
-
// Get GitHub issues context for large commits [[memory:5887795]]
|
|
435
|
-
let githubIssuesContext = '';
|
|
436
|
-
try {
|
|
437
|
-
const currentVersion = await getCurrentVersion(storage);
|
|
438
|
-
if (currentVersion) {
|
|
439
|
-
logger.debug(`Found current version: ${currentVersion}, fetching related GitHub issues...`);
|
|
440
|
-
githubIssuesContext = await getRecentClosedIssuesForCommit(currentVersion, 10);
|
|
441
|
-
if (githubIssuesContext) {
|
|
442
|
-
logger.debug(`Fetched GitHub issues context (${githubIssuesContext.length} characters)`);
|
|
443
|
-
} else {
|
|
444
|
-
logger.debug('No relevant GitHub issues found for commit context');
|
|
445
|
-
}
|
|
446
|
-
} else {
|
|
447
|
-
logger.debug('Could not determine current version, fetching recent issues without milestone filtering...');
|
|
448
|
-
githubIssuesContext = await getRecentClosedIssuesForCommit(undefined, 10);
|
|
449
|
-
if (githubIssuesContext) {
|
|
450
|
-
logger.debug(`Fetched general GitHub issues context (${githubIssuesContext.length} characters)`);
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
} catch (error) {
|
|
454
|
-
logger.debug(`Failed to fetch GitHub issues for commit context: ${error.message}`);
|
|
455
|
-
// Continue without GitHub context - this shouldn't block commit generation
|
|
456
|
-
}
|
|
457
|
-
const promptConfig = {
|
|
458
|
-
overridePaths: runConfig.discoveredConfigDirs || [],
|
|
459
|
-
overrides: runConfig.overrides || false
|
|
460
|
-
};
|
|
461
|
-
const userDirection = sanitizeDirection((_runConfig_commit3 = runConfig.commit) === null || _runConfig_commit3 === void 0 ? void 0 : _runConfig_commit3.direction);
|
|
462
|
-
if (userDirection) {
|
|
463
|
-
logger.debug('Using user direction: %s', userDirection);
|
|
464
|
-
}
|
|
465
|
-
// Create adapters for ai-service
|
|
466
|
-
const aiConfig = toAIConfig(runConfig);
|
|
467
|
-
const aiStorageAdapter = createStorageAdapter(outputDirectory);
|
|
468
|
-
const aiLogger = createLoggerAdapter(isDryRun);
|
|
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
|
|
477
|
-
const promptContext = {
|
|
478
|
-
logContext,
|
|
479
|
-
context: combinedContext || undefined,
|
|
480
|
-
directories: runConfig.contextDirectories
|
|
481
|
-
};
|
|
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);
|
|
522
|
-
}
|
|
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);
|
|
527
|
-
}
|
|
528
|
-
const rawSummary = agenticResult.commitMessage;
|
|
529
|
-
// Apply stop-context filtering to commit message
|
|
530
|
-
const filterResult = filterContent(rawSummary, runConfig.stopContext);
|
|
531
|
-
const summary = filterResult.filtered;
|
|
532
|
-
// Save timestamped copy of commit message with better error handling
|
|
533
|
-
await saveCommitMessage(outputDirectory, summary, storage, logger);
|
|
534
|
-
// 🛡️ Universal Safety Check: Run before ANY commit operation
|
|
535
|
-
// This protects both direct commits (--sendit) and automated commits (publish, etc.)
|
|
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) {
|
|
538
|
-
logger.debug('Checking for file: dependencies before commit operation...');
|
|
539
|
-
try {
|
|
540
|
-
const fileDependencyIssues = await checkForFileDependencies(storage, process.cwd());
|
|
541
|
-
if (fileDependencyIssues.length > 0) {
|
|
542
|
-
var _runConfig_commit18;
|
|
543
|
-
logger.error('🚫 COMMIT BLOCKED: Found file: dependencies that should not be committed!');
|
|
544
|
-
logger.error('');
|
|
545
|
-
logFileDependencyWarning(fileDependencyIssues, 'commit');
|
|
546
|
-
logFileDependencySuggestions(true);
|
|
547
|
-
logger.error('Generated commit message was:');
|
|
548
|
-
logger.error('%s', summary);
|
|
549
|
-
logger.error('');
|
|
550
|
-
if ((_runConfig_commit18 = runConfig.commit) === null || _runConfig_commit18 === void 0 ? void 0 : _runConfig_commit18.sendit) {
|
|
551
|
-
logger.error('To bypass this check, use: kodrdriv commit --skip-file-check --sendit');
|
|
552
|
-
} else {
|
|
553
|
-
logger.error('To bypass this check, add skipFileCheck: true to your commit configuration');
|
|
554
|
-
}
|
|
555
|
-
throw new ValidationError('Found file: dependencies that should not be committed. Use --skip-file-check to bypass.');
|
|
556
|
-
}
|
|
557
|
-
logger.debug('✅ No file: dependencies found, proceeding with commit');
|
|
558
|
-
} catch (error) {
|
|
559
|
-
logger.warn('Warning: Could not check for file: dependencies: %s', error.message);
|
|
560
|
-
logger.warn('Proceeding with commit...');
|
|
561
|
-
}
|
|
562
|
-
} else if (((_runConfig_commit12 = runConfig.commit) === null || _runConfig_commit12 === void 0 ? void 0 : _runConfig_commit12.skipFileCheck) && willCreateCommit) {
|
|
563
|
-
logger.warn('⚠️ Skipping file: dependency check as requested');
|
|
564
|
-
}
|
|
565
|
-
// Handle interactive mode
|
|
566
|
-
if (((_runConfig_commit13 = runConfig.commit) === null || _runConfig_commit13 === void 0 ? void 0 : _runConfig_commit13.interactive) && !isDryRun) {
|
|
567
|
-
var _runConfig_commit19;
|
|
568
|
-
requireTTY('Interactive mode requires a terminal. Use --sendit or --dry-run instead.');
|
|
569
|
-
const interactiveResult = await handleInteractiveCommitFeedback(summary, runConfig, promptConfig, promptContext, outputDirectory, storage, diffContent, hasActualChanges, cached);
|
|
570
|
-
if (interactiveResult.action === 'skip') {
|
|
571
|
-
logger.info('COMMIT_ABORTED: User aborted commit operation | Reason: User choice | Action: No commit performed');
|
|
572
|
-
logger.info('COMMIT_NO_ACTION: No commit will be performed | Status: aborted | Next: User can retry or modify changes');
|
|
573
|
-
userSkippedCommit = true;
|
|
574
|
-
return interactiveResult.finalMessage;
|
|
575
|
-
}
|
|
576
|
-
// User chose to commit - check if sendit is enabled to determine what action to take
|
|
577
|
-
const senditEnabled = (_runConfig_commit19 = runConfig.commit) === null || _runConfig_commit19 === void 0 ? void 0 : _runConfig_commit19.sendit;
|
|
578
|
-
const willActuallyCommit = senditEnabled && hasActualChanges && cached;
|
|
579
|
-
if (willActuallyCommit) {
|
|
580
|
-
var _runConfig_commit20;
|
|
581
|
-
const commitAction = ((_runConfig_commit20 = runConfig.commit) === null || _runConfig_commit20 === void 0 ? void 0 : _runConfig_commit20.amend) ? 'amending last commit' : 'committing';
|
|
582
|
-
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);
|
|
583
|
-
try {
|
|
584
|
-
var _runConfig_commit21, _runConfig_commit22;
|
|
585
|
-
const validatedSummary = validateString(interactiveResult.finalMessage, 'commit summary');
|
|
586
|
-
const escapedSummary = shellescape([
|
|
587
|
-
validatedSummary
|
|
588
|
-
]);
|
|
589
|
-
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}`;
|
|
590
|
-
await run(commitCommand);
|
|
591
|
-
logger.info('COMMIT_SUCCESS: Commit operation completed successfully | Status: committed | Action: Changes saved to repository');
|
|
592
|
-
// Push if requested
|
|
593
|
-
await pushCommit((_runConfig_commit22 = runConfig.commit) === null || _runConfig_commit22 === void 0 ? void 0 : _runConfig_commit22.push, logger, isDryRun);
|
|
594
|
-
} catch (error) {
|
|
595
|
-
logger.error('Failed to commit:', error);
|
|
596
|
-
throw new ExternalDependencyError('Failed to create commit', 'git', error);
|
|
597
|
-
}
|
|
598
|
-
} else if (senditEnabled && (!hasActualChanges || !cached)) {
|
|
599
|
-
logger.info('📝 SendIt enabled but no staged changes available. Final message saved: \n\n%s\n\n', interactiveResult.finalMessage);
|
|
600
|
-
if (!hasActualChanges) {
|
|
601
|
-
logger.info('💡 No changes detected to commit');
|
|
602
|
-
} else if (!cached) {
|
|
603
|
-
logger.info('💡 No staged changes found. Use "git add" to stage changes or configure add: true in commit settings');
|
|
604
|
-
}
|
|
605
|
-
} else {
|
|
606
|
-
logger.info('📝 Message accepted (SendIt not enabled). Use this commit message manually: \n\n%s\n\n', interactiveResult.finalMessage);
|
|
607
|
-
logger.info('💡 To automatically commit, add sendit: true to your commit configuration');
|
|
608
|
-
}
|
|
609
|
-
return interactiveResult.finalMessage;
|
|
610
|
-
}
|
|
611
|
-
// Safety check: Never commit if user explicitly skipped in interactive mode
|
|
612
|
-
if (userSkippedCommit) {
|
|
613
|
-
logger.debug('Skipping sendit logic because user chose to skip in interactive mode');
|
|
614
|
-
return summary;
|
|
615
|
-
}
|
|
616
|
-
if ((_runConfig_commit14 = runConfig.commit) === null || _runConfig_commit14 === void 0 ? void 0 : _runConfig_commit14.sendit) {
|
|
617
|
-
if (isDryRun) {
|
|
618
|
-
var _runConfig_commit23, _runConfig_commit24;
|
|
619
|
-
logger.info('Would commit with message: \n\n%s\n\n', summary);
|
|
620
|
-
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>';
|
|
621
|
-
logger.info('Would execute: %s', commitAction);
|
|
622
|
-
// Show push command in dry run if requested
|
|
623
|
-
if ((_runConfig_commit24 = runConfig.commit) === null || _runConfig_commit24 === void 0 ? void 0 : _runConfig_commit24.push) {
|
|
624
|
-
const remote = typeof runConfig.commit.push === 'string' ? runConfig.commit.push : 'origin';
|
|
625
|
-
logger.info('Would push to %s with: git push %s', remote, remote);
|
|
626
|
-
}
|
|
627
|
-
} else if (hasActualChanges && cached) {
|
|
628
|
-
var _runConfig_commit25;
|
|
629
|
-
const commitAction = ((_runConfig_commit25 = runConfig.commit) === null || _runConfig_commit25 === void 0 ? void 0 : _runConfig_commit25.amend) ? 'amending commit' : 'committing';
|
|
630
|
-
logger.info('SendIt mode enabled. %s with message: \n\n%s\n\n', commitAction.charAt(0).toUpperCase() + commitAction.slice(1), summary);
|
|
631
|
-
try {
|
|
632
|
-
var _runConfig_commit26, _runConfig_commit27;
|
|
633
|
-
const validatedSummary = validateString(summary, 'commit summary');
|
|
634
|
-
const escapedSummary = shellescape([
|
|
635
|
-
validatedSummary
|
|
636
|
-
]);
|
|
637
|
-
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}`;
|
|
638
|
-
await run(commitCommand);
|
|
639
|
-
logger.info('Commit successful!');
|
|
640
|
-
// Push if requested
|
|
641
|
-
await pushCommit((_runConfig_commit27 = runConfig.commit) === null || _runConfig_commit27 === void 0 ? void 0 : _runConfig_commit27.push, logger, isDryRun);
|
|
642
|
-
} catch (error) {
|
|
643
|
-
logger.error('Failed to commit:', error);
|
|
644
|
-
throw new ExternalDependencyError('Failed to create commit', 'git', error);
|
|
645
|
-
}
|
|
646
|
-
} else {
|
|
647
|
-
logger.info('SendIt mode enabled, but no changes to commit. Generated message: \n\n%s\n\n', summary);
|
|
648
|
-
}
|
|
649
|
-
} else if (isDryRun) {
|
|
650
|
-
logger.info('Generated commit message: \n\n%s\n\n', summary);
|
|
651
|
-
} else {
|
|
652
|
-
// Default behavior when neither --interactive nor --sendit is specified
|
|
653
|
-
logger.info('Generated commit message: \n\n%s\n\n', summary);
|
|
654
|
-
}
|
|
655
|
-
return summary;
|
|
656
|
-
};
|
|
657
|
-
const execute = async (runConfig)=>{
|
|
658
|
-
try {
|
|
659
|
-
return await executeInternal(runConfig);
|
|
660
|
-
} catch (error) {
|
|
661
|
-
// Import getLogger for error handling
|
|
662
|
-
const { getLogger } = await import('../logging.js');
|
|
663
|
-
const standardLogger = getLogger();
|
|
664
|
-
if (error instanceof ValidationError || error instanceof ExternalDependencyError || error instanceof CommandError) {
|
|
665
|
-
standardLogger.error(`commit failed: ${error.message}`);
|
|
666
|
-
if (error.cause && typeof error.cause === 'object' && 'message' in error.cause) {
|
|
667
|
-
standardLogger.debug(`Caused by: ${error.cause.message}`);
|
|
668
|
-
} else if (error.cause) {
|
|
669
|
-
standardLogger.debug(`Caused by: ${error.cause}`);
|
|
670
|
-
}
|
|
671
|
-
throw error;
|
|
672
|
-
}
|
|
673
|
-
// Unexpected errors
|
|
674
|
-
standardLogger.error(`commit encountered unexpected error: ${error.message}`);
|
|
675
|
-
throw error;
|
|
676
|
-
}
|
|
677
|
-
};
|
|
678
|
-
|
|
679
|
-
export { execute };
|
|
680
|
-
//# sourceMappingURL=commit.js.map
|