@grunnverk/commands-git 1.5.12 → 1.5.13-dev.20260315113156.5cc09b3

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/dist/index.js CHANGED
@@ -86,6 +86,51 @@ async function getCurrentVersion(storage) {
86
86
  return undefined;
87
87
  }
88
88
  }
89
+ function isTokenLimitFailure(error) {
90
+ if (!error) {
91
+ return false;
92
+ }
93
+ if (error.isTokenLimitError) {
94
+ return true;
95
+ }
96
+ const message = String(error.message || error).toLowerCase();
97
+ return message.includes('input tokens exceed') || message.includes('maximum context length') || message.includes('context_length_exceeded') || message.includes('too many tokens') || message.includes('token limit');
98
+ }
99
+ async function buildFallbackCommitMessage(changedFiles, storage) {
100
+ const fileNames = changedFiles.map((file)=>file.split('/').pop() || file);
101
+ const uniqueNames = Array.from(new Set(fileNames));
102
+ const packageMetadataFiles = new Set([
103
+ 'package.json',
104
+ 'package-lock.json',
105
+ 'npm-shrinkwrap.json'
106
+ ]);
107
+ const isPackageMetadataOnly = uniqueNames.length > 0 && uniqueNames.every((name)=>packageMetadataFiles.has(name));
108
+ if (isPackageMetadataOnly && uniqueNames.includes('package.json')) {
109
+ const currentVersion = await getCurrentVersion(storage);
110
+ if (currentVersion) {
111
+ return `chore: bump version to ${currentVersion}`;
112
+ }
113
+ return 'chore: update package metadata';
114
+ }
115
+ const isDocsOnly = changedFiles.length > 0 && changedFiles.every((file)=>{
116
+ const fileName = file.split('/').pop() || file;
117
+ return file.endsWith('.md') || fileName.toLowerCase().startsWith('readme');
118
+ });
119
+ if (isDocsOnly) {
120
+ return 'docs: update documentation';
121
+ }
122
+ const isTestsOnly = changedFiles.length > 0 && changedFiles.every((file)=>/\.test\.[^.]+$|\.spec\.[^.]+$/.test(file) || file.includes('/test/') || file.includes('/tests/'));
123
+ if (isTestsOnly) {
124
+ return 'test: update test coverage';
125
+ }
126
+ if (uniqueNames.length === 1) {
127
+ return `chore: update ${uniqueNames[0]}`;
128
+ }
129
+ if (uniqueNames.length > 1 && uniqueNames.length <= 3) {
130
+ return `chore: update ${uniqueNames.join(', ')}`;
131
+ }
132
+ return 'chore: update project files';
133
+ }
89
134
  // Helper function to edit commit message using editor
90
135
  async function editCommitMessageInteractively(commitMessage) {
91
136
  const templateLines = [
@@ -553,7 +598,7 @@ const saveCommitMessage = async (outputDirectory, summary, storage, logger)=>{
553
598
  }
554
599
  const executeInternal$3 = async (runConfig)=>{
555
600
  var _ref, _ref1, _runConfig_excludedPatterns;
556
- var _runConfig_commit, _runConfig_commit1, _runConfig_commit2, _runConfig_commit3, _runConfig_commit4, _runConfig_commit5, _runConfig_commit6, _runConfig_commit7, _aiConfig_commands_commit, _aiConfig_commands, _aiConfig_commands_commit1, _aiConfig_commands1, _aiConfig_commands_commit2, _aiConfig_commands2, _runConfig_commit8, _aiConfig_commands_commit3, _aiConfig_commands3, _runConfig_commit9, _runConfig_commit10, _runConfig_commit11, _runConfig_commit12, _runConfig_commit13, _runConfig_commit14, _runConfig_commit15;
601
+ var _runConfig_commit, _runConfig_commit1, _runConfig_commit2, _runConfig_commit3, _runConfig_commit4, _runConfig_commit5, _runConfig_commit6, _runConfig_commit7, _aiConfig_commands_commit, _aiConfig_commands, _aiConfig_commands_commit1, _aiConfig_commands1, _runConfig_commit8, _runConfig_commit9, _runConfig_commit10, _runConfig_commit11, _runConfig_commit12, _runConfig_commit13, _runConfig_commit14, _runConfig_commit15;
557
602
  const isDryRun = runConfig.dryRun || false;
558
603
  const logger = getDryRunLogger(isDryRun);
559
604
  logger.info('COMMIT_START: Starting commit message generation | Mode: %s', isDryRun ? 'dry-run' : 'live');
@@ -726,26 +771,50 @@ const executeInternal$3 = async (runConfig)=>{
726
771
  logger.debug('Changed files for analysis: %d files', changedFiles.length);
727
772
  // Run agentic commit generation
728
773
  logger.info('COMMIT_AI_GENERATION: Starting AI-powered commit message generation | Model: %s | Reasoning: %s | Files: %d', ((_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', ((_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 || 'low', changedFiles.length);
729
- const agenticResult = await runAgenticCommit({
730
- changedFiles,
731
- diffContent,
732
- userDirection,
733
- logContext,
734
- model: ((_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,
735
- maxIterations: ((_runConfig_commit8 = runConfig.commit) === null || _runConfig_commit8 === void 0 ? void 0 : _runConfig_commit8.maxAgenticIterations) || 10,
736
- debug: runConfig.debug,
737
- debugRequestFile: getOutputPath(outputDirectory, getTimestampedRequestFilename('commit')),
738
- debugResponseFile: getOutputPath(outputDirectory, getTimestampedResponseFilename('commit')),
739
- storage: aiStorageAdapter,
740
- logger: aiLogger,
741
- 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
742
- });
774
+ let usedFallbackCommitMessage = false;
775
+ const agenticResult = await (async ()=>{
776
+ try {
777
+ var _aiConfig_commands_commit, _aiConfig_commands, _runConfig_commit, _aiConfig_commands_commit1, _aiConfig_commands1;
778
+ return await runAgenticCommit({
779
+ changedFiles,
780
+ diffContent,
781
+ userDirection,
782
+ logContext,
783
+ 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,
784
+ maxIterations: ((_runConfig_commit = runConfig.commit) === null || _runConfig_commit === void 0 ? void 0 : _runConfig_commit.maxAgenticIterations) || 10,
785
+ debug: runConfig.debug,
786
+ debugRequestFile: getOutputPath(outputDirectory, getTimestampedRequestFilename('commit')),
787
+ debugResponseFile: getOutputPath(outputDirectory, getTimestampedResponseFilename('commit')),
788
+ storage: aiStorageAdapter,
789
+ logger: aiLogger,
790
+ 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
791
+ });
792
+ } catch (error) {
793
+ if (!isTokenLimitFailure(error)) {
794
+ throw error;
795
+ }
796
+ usedFallbackCommitMessage = true;
797
+ const fallbackMessage = await buildFallbackCommitMessage(changedFiles, storage);
798
+ logger.warn('COMMIT_AI_TOKEN_LIMIT: AI commit generation exceeded model token limits | Action: Falling back to heuristic commit message | Files: %d', changedFiles.length);
799
+ logger.warn('COMMIT_AI_FALLBACK_MESSAGE: Using fallback commit message | Message: %s', fallbackMessage);
800
+ return {
801
+ commitMessage: fallbackMessage,
802
+ iterations: 0,
803
+ toolCallsExecuted: 0,
804
+ suggestedSplits: [],
805
+ conversationHistory: [],
806
+ toolMetrics: []
807
+ };
808
+ }
809
+ })();
743
810
  const iterations = agenticResult.iterations || 0;
744
811
  const toolCalls = agenticResult.toolCallsExecuted || 0;
745
812
  logger.info(`🔍 Analysis complete: ${iterations} iterations, ${toolCalls} tool calls`);
746
813
  // Generate self-reflection output if enabled
747
- if ((_runConfig_commit9 = runConfig.commit) === null || _runConfig_commit9 === void 0 ? void 0 : _runConfig_commit9.selfReflection) {
814
+ if (((_runConfig_commit8 = runConfig.commit) === null || _runConfig_commit8 === void 0 ? void 0 : _runConfig_commit8.selfReflection) && !usedFallbackCommitMessage) {
748
815
  await generateSelfReflection(agenticResult, outputDirectory, storage, logger);
816
+ } else if (((_runConfig_commit9 = runConfig.commit) === null || _runConfig_commit9 === void 0 ? void 0 : _runConfig_commit9.selfReflection) && usedFallbackCommitMessage) {
817
+ logger.warn('Skipping self-reflection because commit generation used a fallback message after a token-limit failure');
749
818
  }
750
819
  // Check for suggested splits
751
820
  if (agenticResult.suggestedSplits.length > 1 && ((_runConfig_commit10 = runConfig.commit) === null || _runConfig_commit10 === void 0 ? void 0 : _runConfig_commit10.allowCommitSplitting)) {