git-coco 0.22.2 β†’ 0.22.3

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.
@@ -47,7 +47,7 @@ import { pathToFileURL } from 'url';
47
47
  /**
48
48
  * Current build version from package.json
49
49
  */
50
- const BUILD_VERSION = "0.22.2";
50
+ const BUILD_VERSION = "0.22.3";
51
51
 
52
52
  const isInteractive = (config) => {
53
53
  return config?.mode === 'interactive' || !!config?.interactive;
@@ -6219,7 +6219,7 @@ function getLlm(provider, model, config) {
6219
6219
  });
6220
6220
  case 'openai':
6221
6221
  return new ChatOpenAI({
6222
- openAIApiKey: apiKey,
6222
+ apiKey: apiKey,
6223
6223
  model,
6224
6224
  temperature: config.service.temperature || 0.2,
6225
6225
  });
@@ -11476,9 +11476,34 @@ ${schema.description}
11476
11476
  // Load commitlint rules context if available
11477
11477
  const hasCommitLintConfig = await hasCommitlintConfig();
11478
11478
  let commitlint_rules_context = '';
11479
+ let shouldSkipCommitlintValidation = false;
11479
11480
  if (USE_CONVENTIONAL_COMMITS || hasCommitLintConfig) {
11480
- const { getCommitlintRulesContext } = await Promise.resolve().then(function () { return commitlintValidator; });
11481
- commitlint_rules_context = await getCommitlintRulesContext();
11481
+ const { getCommitlintRulesContext, checkCommitlintAvailability } = await Promise.resolve().then(function () { return commitlintValidator; });
11482
+ // Check if commitlint packages are available
11483
+ const availability = checkCommitlintAvailability();
11484
+ if (!availability.available) {
11485
+ const { handleMissingCommitlintDeps } = await Promise.resolve().then(function () { return handleMissingCommitlintDeps$1; });
11486
+ const result = await handleMissingCommitlintDeps({
11487
+ logger,
11488
+ interactive: INTERACTIVE,
11489
+ missingPackages: availability.missingPackages,
11490
+ });
11491
+ switch (result.action) {
11492
+ case 'continue':
11493
+ shouldSkipCommitlintValidation = true;
11494
+ logger.log('Continuing without commitlint validation...', { color: 'yellow' });
11495
+ break;
11496
+ case 'setup':
11497
+ logger.log('\nPlease run `coco init` to set up commitlint, then try again.', { color: 'blue' });
11498
+ process.exit(0);
11499
+ case 'abort':
11500
+ logger.log('\nAborting commit operation.', { color: 'red' });
11501
+ process.exit(1);
11502
+ }
11503
+ }
11504
+ else {
11505
+ commitlint_rules_context = await getCommitlintRulesContext();
11506
+ }
11482
11507
  }
11483
11508
  // Get variables for the prompt
11484
11509
  const variables = {
@@ -11525,13 +11550,33 @@ ${schema.description}
11525
11550
  const ticketId = extractTicketIdFromBranchName(branchName);
11526
11551
  const ticketFooter = argv.appendTicket && ticketId ? `\n\nPart of **${ticketId}**` : '';
11527
11552
  const fullMessage = `${commitMsg.title}\n\n${commitMsg.body}${appendedText}${ticketFooter}`;
11528
- // If commitlint validation is needed, validate the message
11529
- if (USE_CONVENTIONAL_COMMITS || hasCommitLintConfig) {
11553
+ // If commitlint validation is needed and not skipped, validate the message
11554
+ if ((USE_CONVENTIONAL_COMMITS || hasCommitLintConfig) && !shouldSkipCommitlintValidation) {
11530
11555
  const { validateCommitMessage, CommitlintValidationError } = await Promise.resolve().then(function () { return commitlintValidator; });
11531
11556
  const validationResult = await validateCommitMessage(fullMessage);
11532
11557
  logger.verbose(`Validation result: ${JSON.stringify(validationResult)}`, {
11533
11558
  color: 'yellow',
11534
11559
  });
11560
+ // Handle missing dependencies gracefully
11561
+ if (validationResult.missingDependencies && validationResult.missingDependencies.length > 0) {
11562
+ const { handleMissingCommitlintDeps } = await Promise.resolve().then(function () { return handleMissingCommitlintDeps$1; });
11563
+ const result = await handleMissingCommitlintDeps({
11564
+ logger,
11565
+ interactive: INTERACTIVE,
11566
+ missingPackages: validationResult.missingDependencies,
11567
+ });
11568
+ switch (result.action) {
11569
+ case 'continue':
11570
+ logger.log('Skipping commitlint validation...', { color: 'yellow' });
11571
+ return fullMessage;
11572
+ case 'setup':
11573
+ logger.log('\nPlease run `coco init` to set up commitlint, then try again.', { color: 'blue' });
11574
+ process.exit(0);
11575
+ case 'abort':
11576
+ logger.log('\nAborting commit due to missing dependencies.', { color: 'red' });
11577
+ process.exit(1);
11578
+ }
11579
+ }
11535
11580
  if (!validationResult.valid) {
11536
11581
  retryCount++;
11537
11582
  // Format validation errors for next attempt
@@ -11969,14 +12014,21 @@ const questions = {
11969
12014
  },
11970
12015
  ],
11971
12016
  }),
12017
+ setupCommitlint: async () => await confirm({
12018
+ message: 'set up commitlint for conventional commits support?',
12019
+ default: true,
12020
+ }),
11972
12021
  };
11973
12022
 
11974
12023
  const handler$2 = async (argv, logger) => {
11975
12024
  const options = loadConfig(argv);
11976
12025
  logger.log(LOGO);
11977
12026
  let scope = options?.scope;
12027
+ let shouldSetupCommitlint = false;
11978
12028
  if (!scope) {
11979
12029
  scope = await questions.whatScope();
12030
+ // Ask about commitlint setup after scope selection
12031
+ shouldSetupCommitlint = await questions.setupCommitlint();
11980
12032
  const llmProvider = await questions.selectLLMProvider();
11981
12033
  const llmModel = await questions.selectLLMModel(llmProvider);
11982
12034
  const service = getDefaultServiceConfigFromAlias(llmProvider, llmModel);
@@ -12093,6 +12145,10 @@ const handler$2 = async (argv, logger) => {
12093
12145
  }
12094
12146
  // After config is written, check for package installation
12095
12147
  await checkAndHandlePackageInstallation({ global: scope === 'global', logger });
12148
+ // Install commitlint packages if user requested
12149
+ if (shouldSetupCommitlint) {
12150
+ await installCommitlintPackages(scope, logger);
12151
+ }
12096
12152
  logger.log(`\ninit successful! πŸ¦ΎπŸ€–πŸŽ‰`, { color: 'green' });
12097
12153
  }
12098
12154
  else {
@@ -12100,6 +12156,39 @@ const handler$2 = async (argv, logger) => {
12100
12156
  }
12101
12157
  }
12102
12158
  };
12159
+ /**
12160
+ * Install commitlint packages based on scope (global or project)
12161
+ */
12162
+ async function installCommitlintPackages(scope, logger) {
12163
+ const packages = ['@commitlint/config-conventional', '@commitlint/cli'];
12164
+ try {
12165
+ if (scope === 'global') {
12166
+ logger.startSpinner('Installing commitlint packages globally...', { color: 'blue' });
12167
+ for (const pkg of packages) {
12168
+ await installNpmPackage({ name: pkg, flags: ['-g'] });
12169
+ }
12170
+ logger.stopSpinner('Installed commitlint packages globally');
12171
+ }
12172
+ else {
12173
+ logger.startSpinner('Installing commitlint packages in project...', { color: 'blue' });
12174
+ for (const pkg of packages) {
12175
+ await installNpmPackage({ name: pkg, flags: ['--save-dev'] });
12176
+ }
12177
+ logger.stopSpinner('Installed commitlint packages in project');
12178
+ }
12179
+ }
12180
+ catch (error) {
12181
+ logger.stopSpinner('Failed to install commitlint packages');
12182
+ logger.log(`Error installing commitlint packages: ${error.message}`, { color: 'red' });
12183
+ logger.log('You can install them manually later:', { color: 'yellow' });
12184
+ if (scope === 'global') {
12185
+ logger.log('npm install -g @commitlint/config-conventional @commitlint/cli', { color: 'gray' });
12186
+ }
12187
+ else {
12188
+ logger.log('npm install --save-dev @commitlint/config-conventional @commitlint/cli', { color: 'gray' });
12189
+ }
12190
+ }
12191
+ }
12103
12192
 
12104
12193
  var init = {
12105
12194
  command: command$2,
@@ -12786,6 +12875,31 @@ class CommitlintValidationError extends Error {
12786
12875
  this.commitMessage = commitMessage;
12787
12876
  }
12788
12877
  }
12878
+ /**
12879
+ * Check if commitlint config packages are available
12880
+ * We only check for config-conventional since @commitlint/core is bundled with git-coco
12881
+ */
12882
+ function checkCommitlintAvailability() {
12883
+ const requiredPackages = ['@commitlint/config-conventional'];
12884
+ const missingPackages = [];
12885
+ for (const pkg of requiredPackages) {
12886
+ try {
12887
+ // Try to resolve the package from the current working directory
12888
+ require.resolve(pkg, { paths: [process.cwd(), ...module.paths] });
12889
+ }
12890
+ catch (error) {
12891
+ missingPackages.push(pkg);
12892
+ }
12893
+ }
12894
+ // If config-conventional is missing, also suggest installing CLI
12895
+ if (missingPackages.length > 0) {
12896
+ missingPackages.push('@commitlint/cli');
12897
+ }
12898
+ return {
12899
+ available: missingPackages.length === 0,
12900
+ missingPackages,
12901
+ };
12902
+ }
12789
12903
  /**
12790
12904
  * Load commitlint configuration
12791
12905
  */
@@ -12825,10 +12939,35 @@ async function loadCommitlintConfig() {
12825
12939
  catch (error) {
12826
12940
  // Could be an error parsing, or just not found. Fall through to default.
12827
12941
  }
12828
- // If nothing worked, fallback to conventional config
12829
- return load({
12830
- extends: ['@commitlint/config-conventional'],
12831
- });
12942
+ // Try to fallback to conventional config, but handle missing dependencies gracefully
12943
+ try {
12944
+ return await load({
12945
+ extends: ['@commitlint/config-conventional'],
12946
+ });
12947
+ }
12948
+ catch (error) {
12949
+ // If @commitlint/config-conventional is not available, return a basic conventional config
12950
+ if (error instanceof Error && error.message.includes('Cannot find module "@commitlint/config-conventional"')) {
12951
+ return await load({
12952
+ rules: {
12953
+ 'header-max-length': [2, 'always', 72],
12954
+ 'header-min-length': [2, 'always', 8],
12955
+ 'subject-empty': [2, 'never'],
12956
+ 'subject-full-stop': [2, 'never', '.'],
12957
+ 'subject-case': [2, 'always', ['sentence-case', 'start-case', 'pascal-case', 'upper-case', 'lower-case']],
12958
+ 'type-empty': [2, 'never'],
12959
+ 'type-case': [2, 'always', 'lower-case'],
12960
+ 'type-enum': [2, 'always', [
12961
+ 'build', 'chore', 'ci', 'docs', 'feat', 'fix',
12962
+ 'perf', 'refactor', 'revert', 'style', 'test'
12963
+ ]],
12964
+ 'body-max-line-length': [2, 'always', 100],
12965
+ 'scope-case': [2, 'always', 'lower-case'],
12966
+ },
12967
+ });
12968
+ }
12969
+ throw error;
12970
+ }
12832
12971
  }
12833
12972
  /**
12834
12973
  * Format commitlint rules into a human-readable string for AI prompts
@@ -12937,9 +13076,19 @@ async function validateCommitMessage(message, options = {}) {
12937
13076
  };
12938
13077
  }
12939
13078
  catch (error) {
13079
+ const errorMessage = error.message;
13080
+ // Check if this is a missing dependency error
13081
+ if (errorMessage.includes('Cannot find module "@commitlint/config-conventional"')) {
13082
+ return {
13083
+ valid: false,
13084
+ errors: ['Commitlint configuration requires @commitlint/config-conventional to be installed'],
13085
+ warnings: [],
13086
+ missingDependencies: ['@commitlint/config-conventional', '@commitlint/cli'],
13087
+ };
13088
+ }
12940
13089
  return {
12941
13090
  valid: false,
12942
- errors: [error.message],
13091
+ errors: [errorMessage],
12943
13092
  warnings: [],
12944
13093
  };
12945
13094
  }
@@ -12948,12 +13097,61 @@ async function validateCommitMessage(message, options = {}) {
12948
13097
  var commitlintValidator = /*#__PURE__*/Object.freeze({
12949
13098
  __proto__: null,
12950
13099
  CommitlintValidationError: CommitlintValidationError,
13100
+ checkCommitlintAvailability: checkCommitlintAvailability,
12951
13101
  formatCommitlintRulesForPrompt: formatCommitlintRulesForPrompt,
12952
13102
  getCommitlintRulesContext: getCommitlintRulesContext,
12953
13103
  loadCommitlintConfig: loadCommitlintConfig,
12954
13104
  validateCommitMessage: validateCommitMessage
12955
13105
  });
12956
13106
 
13107
+ /**
13108
+ * Handle missing commitlint dependencies with user-friendly options
13109
+ */
13110
+ async function handleMissingCommitlintDeps(options) {
13111
+ const { logger, interactive, missingPackages } = options;
13112
+ if (!interactive) {
13113
+ logger.log('\nCommitlint packages not found. Skipping commit message validation.', {
13114
+ color: 'yellow',
13115
+ });
13116
+ logger.log('Run `coco init` to set up commitlint for conventional commits.', {
13117
+ color: 'gray',
13118
+ });
13119
+ return { action: 'continue' };
13120
+ }
13121
+ logger.log('\nCommitlint configuration requires additional packages:', { color: 'yellow' });
13122
+ missingPackages.forEach((pkg) => {
13123
+ logger.log(` β€’ ${pkg}`, { color: 'gray' });
13124
+ });
13125
+ logger.log('');
13126
+ const choice = await select({
13127
+ message: 'How would you like to proceed?',
13128
+ choices: [
13129
+ {
13130
+ name: 'Continue without commitlint validation',
13131
+ value: 'continue',
13132
+ description: 'Generate commit message without validation rules',
13133
+ },
13134
+ {
13135
+ name: 'Set up commitlint (run coco init)',
13136
+ value: 'setup',
13137
+ description: 'Exit and run the init command to install required packages',
13138
+ },
13139
+ {
13140
+ name: 'Abort',
13141
+ value: 'abort',
13142
+ description: 'Cancel the commit operation',
13143
+ },
13144
+ ],
13145
+ default: 'continue',
13146
+ });
13147
+ return { action: choice };
13148
+ }
13149
+
13150
+ var handleMissingCommitlintDeps$1 = /*#__PURE__*/Object.freeze({
13151
+ __proto__: null,
13152
+ handleMissingCommitlintDeps: handleMissingCommitlintDeps
13153
+ });
13154
+
12957
13155
  /**
12958
13156
  * Handle commit message validation results with user interaction
12959
13157
  */
package/dist/index.js CHANGED
@@ -69,7 +69,7 @@ var readline__namespace = /*#__PURE__*/_interopNamespaceDefault(readline);
69
69
  /**
70
70
  * Current build version from package.json
71
71
  */
72
- const BUILD_VERSION = "0.22.2";
72
+ const BUILD_VERSION = "0.22.3";
73
73
 
74
74
  const isInteractive = (config) => {
75
75
  return config?.mode === 'interactive' || !!config?.interactive;
@@ -6241,7 +6241,7 @@ function getLlm(provider, model, config) {
6241
6241
  });
6242
6242
  case 'openai':
6243
6243
  return new openai.ChatOpenAI({
6244
- openAIApiKey: apiKey,
6244
+ apiKey: apiKey,
6245
6245
  model,
6246
6246
  temperature: config.service.temperature || 0.2,
6247
6247
  });
@@ -11498,9 +11498,34 @@ ${schema.description}
11498
11498
  // Load commitlint rules context if available
11499
11499
  const hasCommitLintConfig = await hasCommitlintConfig();
11500
11500
  let commitlint_rules_context = '';
11501
+ let shouldSkipCommitlintValidation = false;
11501
11502
  if (USE_CONVENTIONAL_COMMITS || hasCommitLintConfig) {
11502
- const { getCommitlintRulesContext } = await Promise.resolve().then(function () { return commitlintValidator; });
11503
- commitlint_rules_context = await getCommitlintRulesContext();
11503
+ const { getCommitlintRulesContext, checkCommitlintAvailability } = await Promise.resolve().then(function () { return commitlintValidator; });
11504
+ // Check if commitlint packages are available
11505
+ const availability = checkCommitlintAvailability();
11506
+ if (!availability.available) {
11507
+ const { handleMissingCommitlintDeps } = await Promise.resolve().then(function () { return handleMissingCommitlintDeps$1; });
11508
+ const result = await handleMissingCommitlintDeps({
11509
+ logger,
11510
+ interactive: INTERACTIVE,
11511
+ missingPackages: availability.missingPackages,
11512
+ });
11513
+ switch (result.action) {
11514
+ case 'continue':
11515
+ shouldSkipCommitlintValidation = true;
11516
+ logger.log('Continuing without commitlint validation...', { color: 'yellow' });
11517
+ break;
11518
+ case 'setup':
11519
+ logger.log('\nPlease run `coco init` to set up commitlint, then try again.', { color: 'blue' });
11520
+ process.exit(0);
11521
+ case 'abort':
11522
+ logger.log('\nAborting commit operation.', { color: 'red' });
11523
+ process.exit(1);
11524
+ }
11525
+ }
11526
+ else {
11527
+ commitlint_rules_context = await getCommitlintRulesContext();
11528
+ }
11504
11529
  }
11505
11530
  // Get variables for the prompt
11506
11531
  const variables = {
@@ -11547,13 +11572,33 @@ ${schema.description}
11547
11572
  const ticketId = extractTicketIdFromBranchName(branchName);
11548
11573
  const ticketFooter = argv.appendTicket && ticketId ? `\n\nPart of **${ticketId}**` : '';
11549
11574
  const fullMessage = `${commitMsg.title}\n\n${commitMsg.body}${appendedText}${ticketFooter}`;
11550
- // If commitlint validation is needed, validate the message
11551
- if (USE_CONVENTIONAL_COMMITS || hasCommitLintConfig) {
11575
+ // If commitlint validation is needed and not skipped, validate the message
11576
+ if ((USE_CONVENTIONAL_COMMITS || hasCommitLintConfig) && !shouldSkipCommitlintValidation) {
11552
11577
  const { validateCommitMessage, CommitlintValidationError } = await Promise.resolve().then(function () { return commitlintValidator; });
11553
11578
  const validationResult = await validateCommitMessage(fullMessage);
11554
11579
  logger.verbose(`Validation result: ${JSON.stringify(validationResult)}`, {
11555
11580
  color: 'yellow',
11556
11581
  });
11582
+ // Handle missing dependencies gracefully
11583
+ if (validationResult.missingDependencies && validationResult.missingDependencies.length > 0) {
11584
+ const { handleMissingCommitlintDeps } = await Promise.resolve().then(function () { return handleMissingCommitlintDeps$1; });
11585
+ const result = await handleMissingCommitlintDeps({
11586
+ logger,
11587
+ interactive: INTERACTIVE,
11588
+ missingPackages: validationResult.missingDependencies,
11589
+ });
11590
+ switch (result.action) {
11591
+ case 'continue':
11592
+ logger.log('Skipping commitlint validation...', { color: 'yellow' });
11593
+ return fullMessage;
11594
+ case 'setup':
11595
+ logger.log('\nPlease run `coco init` to set up commitlint, then try again.', { color: 'blue' });
11596
+ process.exit(0);
11597
+ case 'abort':
11598
+ logger.log('\nAborting commit due to missing dependencies.', { color: 'red' });
11599
+ process.exit(1);
11600
+ }
11601
+ }
11557
11602
  if (!validationResult.valid) {
11558
11603
  retryCount++;
11559
11604
  // Format validation errors for next attempt
@@ -11991,14 +12036,21 @@ const questions = {
11991
12036
  },
11992
12037
  ],
11993
12038
  }),
12039
+ setupCommitlint: async () => await prompts.confirm({
12040
+ message: 'set up commitlint for conventional commits support?',
12041
+ default: true,
12042
+ }),
11994
12043
  };
11995
12044
 
11996
12045
  const handler$2 = async (argv, logger) => {
11997
12046
  const options = loadConfig(argv);
11998
12047
  logger.log(LOGO);
11999
12048
  let scope = options?.scope;
12049
+ let shouldSetupCommitlint = false;
12000
12050
  if (!scope) {
12001
12051
  scope = await questions.whatScope();
12052
+ // Ask about commitlint setup after scope selection
12053
+ shouldSetupCommitlint = await questions.setupCommitlint();
12002
12054
  const llmProvider = await questions.selectLLMProvider();
12003
12055
  const llmModel = await questions.selectLLMModel(llmProvider);
12004
12056
  const service = getDefaultServiceConfigFromAlias(llmProvider, llmModel);
@@ -12115,6 +12167,10 @@ const handler$2 = async (argv, logger) => {
12115
12167
  }
12116
12168
  // After config is written, check for package installation
12117
12169
  await checkAndHandlePackageInstallation({ global: scope === 'global', logger });
12170
+ // Install commitlint packages if user requested
12171
+ if (shouldSetupCommitlint) {
12172
+ await installCommitlintPackages(scope, logger);
12173
+ }
12118
12174
  logger.log(`\ninit successful! πŸ¦ΎπŸ€–πŸŽ‰`, { color: 'green' });
12119
12175
  }
12120
12176
  else {
@@ -12122,6 +12178,39 @@ const handler$2 = async (argv, logger) => {
12122
12178
  }
12123
12179
  }
12124
12180
  };
12181
+ /**
12182
+ * Install commitlint packages based on scope (global or project)
12183
+ */
12184
+ async function installCommitlintPackages(scope, logger) {
12185
+ const packages = ['@commitlint/config-conventional', '@commitlint/cli'];
12186
+ try {
12187
+ if (scope === 'global') {
12188
+ logger.startSpinner('Installing commitlint packages globally...', { color: 'blue' });
12189
+ for (const pkg of packages) {
12190
+ await installNpmPackage({ name: pkg, flags: ['-g'] });
12191
+ }
12192
+ logger.stopSpinner('Installed commitlint packages globally');
12193
+ }
12194
+ else {
12195
+ logger.startSpinner('Installing commitlint packages in project...', { color: 'blue' });
12196
+ for (const pkg of packages) {
12197
+ await installNpmPackage({ name: pkg, flags: ['--save-dev'] });
12198
+ }
12199
+ logger.stopSpinner('Installed commitlint packages in project');
12200
+ }
12201
+ }
12202
+ catch (error) {
12203
+ logger.stopSpinner('Failed to install commitlint packages');
12204
+ logger.log(`Error installing commitlint packages: ${error.message}`, { color: 'red' });
12205
+ logger.log('You can install them manually later:', { color: 'yellow' });
12206
+ if (scope === 'global') {
12207
+ logger.log('npm install -g @commitlint/config-conventional @commitlint/cli', { color: 'gray' });
12208
+ }
12209
+ else {
12210
+ logger.log('npm install --save-dev @commitlint/config-conventional @commitlint/cli', { color: 'gray' });
12211
+ }
12212
+ }
12213
+ }
12125
12214
 
12126
12215
  var init = {
12127
12216
  command: command$2,
@@ -12808,6 +12897,31 @@ class CommitlintValidationError extends Error {
12808
12897
  this.commitMessage = commitMessage;
12809
12898
  }
12810
12899
  }
12900
+ /**
12901
+ * Check if commitlint config packages are available
12902
+ * We only check for config-conventional since @commitlint/core is bundled with git-coco
12903
+ */
12904
+ function checkCommitlintAvailability() {
12905
+ const requiredPackages = ['@commitlint/config-conventional'];
12906
+ const missingPackages = [];
12907
+ for (const pkg of requiredPackages) {
12908
+ try {
12909
+ // Try to resolve the package from the current working directory
12910
+ require.resolve(pkg, { paths: [process.cwd(), ...module.paths] });
12911
+ }
12912
+ catch (error) {
12913
+ missingPackages.push(pkg);
12914
+ }
12915
+ }
12916
+ // If config-conventional is missing, also suggest installing CLI
12917
+ if (missingPackages.length > 0) {
12918
+ missingPackages.push('@commitlint/cli');
12919
+ }
12920
+ return {
12921
+ available: missingPackages.length === 0,
12922
+ missingPackages,
12923
+ };
12924
+ }
12811
12925
  /**
12812
12926
  * Load commitlint configuration
12813
12927
  */
@@ -12847,10 +12961,35 @@ async function loadCommitlintConfig() {
12847
12961
  catch (error) {
12848
12962
  // Could be an error parsing, or just not found. Fall through to default.
12849
12963
  }
12850
- // If nothing worked, fallback to conventional config
12851
- return load({
12852
- extends: ['@commitlint/config-conventional'],
12853
- });
12964
+ // Try to fallback to conventional config, but handle missing dependencies gracefully
12965
+ try {
12966
+ return await load({
12967
+ extends: ['@commitlint/config-conventional'],
12968
+ });
12969
+ }
12970
+ catch (error) {
12971
+ // If @commitlint/config-conventional is not available, return a basic conventional config
12972
+ if (error instanceof Error && error.message.includes('Cannot find module "@commitlint/config-conventional"')) {
12973
+ return await load({
12974
+ rules: {
12975
+ 'header-max-length': [2, 'always', 72],
12976
+ 'header-min-length': [2, 'always', 8],
12977
+ 'subject-empty': [2, 'never'],
12978
+ 'subject-full-stop': [2, 'never', '.'],
12979
+ 'subject-case': [2, 'always', ['sentence-case', 'start-case', 'pascal-case', 'upper-case', 'lower-case']],
12980
+ 'type-empty': [2, 'never'],
12981
+ 'type-case': [2, 'always', 'lower-case'],
12982
+ 'type-enum': [2, 'always', [
12983
+ 'build', 'chore', 'ci', 'docs', 'feat', 'fix',
12984
+ 'perf', 'refactor', 'revert', 'style', 'test'
12985
+ ]],
12986
+ 'body-max-line-length': [2, 'always', 100],
12987
+ 'scope-case': [2, 'always', 'lower-case'],
12988
+ },
12989
+ });
12990
+ }
12991
+ throw error;
12992
+ }
12854
12993
  }
12855
12994
  /**
12856
12995
  * Format commitlint rules into a human-readable string for AI prompts
@@ -12959,9 +13098,19 @@ async function validateCommitMessage(message, options = {}) {
12959
13098
  };
12960
13099
  }
12961
13100
  catch (error) {
13101
+ const errorMessage = error.message;
13102
+ // Check if this is a missing dependency error
13103
+ if (errorMessage.includes('Cannot find module "@commitlint/config-conventional"')) {
13104
+ return {
13105
+ valid: false,
13106
+ errors: ['Commitlint configuration requires @commitlint/config-conventional to be installed'],
13107
+ warnings: [],
13108
+ missingDependencies: ['@commitlint/config-conventional', '@commitlint/cli'],
13109
+ };
13110
+ }
12962
13111
  return {
12963
13112
  valid: false,
12964
- errors: [error.message],
13113
+ errors: [errorMessage],
12965
13114
  warnings: [],
12966
13115
  };
12967
13116
  }
@@ -12970,12 +13119,61 @@ async function validateCommitMessage(message, options = {}) {
12970
13119
  var commitlintValidator = /*#__PURE__*/Object.freeze({
12971
13120
  __proto__: null,
12972
13121
  CommitlintValidationError: CommitlintValidationError,
13122
+ checkCommitlintAvailability: checkCommitlintAvailability,
12973
13123
  formatCommitlintRulesForPrompt: formatCommitlintRulesForPrompt,
12974
13124
  getCommitlintRulesContext: getCommitlintRulesContext,
12975
13125
  loadCommitlintConfig: loadCommitlintConfig,
12976
13126
  validateCommitMessage: validateCommitMessage
12977
13127
  });
12978
13128
 
13129
+ /**
13130
+ * Handle missing commitlint dependencies with user-friendly options
13131
+ */
13132
+ async function handleMissingCommitlintDeps(options) {
13133
+ const { logger, interactive, missingPackages } = options;
13134
+ if (!interactive) {
13135
+ logger.log('\nCommitlint packages not found. Skipping commit message validation.', {
13136
+ color: 'yellow',
13137
+ });
13138
+ logger.log('Run `coco init` to set up commitlint for conventional commits.', {
13139
+ color: 'gray',
13140
+ });
13141
+ return { action: 'continue' };
13142
+ }
13143
+ logger.log('\nCommitlint configuration requires additional packages:', { color: 'yellow' });
13144
+ missingPackages.forEach((pkg) => {
13145
+ logger.log(` β€’ ${pkg}`, { color: 'gray' });
13146
+ });
13147
+ logger.log('');
13148
+ const choice = await prompts.select({
13149
+ message: 'How would you like to proceed?',
13150
+ choices: [
13151
+ {
13152
+ name: 'Continue without commitlint validation',
13153
+ value: 'continue',
13154
+ description: 'Generate commit message without validation rules',
13155
+ },
13156
+ {
13157
+ name: 'Set up commitlint (run coco init)',
13158
+ value: 'setup',
13159
+ description: 'Exit and run the init command to install required packages',
13160
+ },
13161
+ {
13162
+ name: 'Abort',
13163
+ value: 'abort',
13164
+ description: 'Cancel the commit operation',
13165
+ },
13166
+ ],
13167
+ default: 'continue',
13168
+ });
13169
+ return { action: choice };
13170
+ }
13171
+
13172
+ var handleMissingCommitlintDeps$1 = /*#__PURE__*/Object.freeze({
13173
+ __proto__: null,
13174
+ handleMissingCommitlintDeps: handleMissingCommitlintDeps
13175
+ });
13176
+
12979
13177
  /**
12980
13178
  * Handle commit message validation results with user interaction
12981
13179
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-coco",
3
- "version": "0.22.2",
3
+ "version": "0.22.3",
4
4
  "description": "zero-effort git commits with coco.",
5
5
  "author": "gfargo <ghfargo@gmail.com>",
6
6
  "license": "MIT",
@@ -45,6 +45,7 @@
45
45
  "coco:esm": "node dist/index.esm.mjs"
46
46
  },
47
47
  "devDependencies": {
48
+ "@commitlint/types": "^19.8.0",
48
49
  "@rollup/plugin-commonjs": "^28.0.0",
49
50
  "@rollup/plugin-eslint": "^9.0.5",
50
51
  "@rollup/plugin-json": "^6.0.0",
@@ -73,9 +74,7 @@
73
74
  "typescript": "^5.4.5"
74
75
  },
75
76
  "dependencies": {
76
- "@commitlint/config-conventional": "^19.8.0",
77
77
  "@commitlint/core": "^19.8.0",
78
- "@commitlint/types": "^19.8.0",
79
78
  "@inquirer/prompts": "3.3.0",
80
79
  "@langchain/anthropic": "^0.3.14",
81
80
  "@langchain/community": "^0.3.32",