git-coco 0.22.8 → 0.22.10

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.8";
50
+ const BUILD_VERSION = "0.22.10";
51
51
 
52
52
  const isInteractive = (config) => {
53
53
  return config?.mode === 'interactive' || !!config?.interactive;
@@ -7212,6 +7212,8 @@ const CONVENTIONAL_TEMPLATE = `Generate a commit message that strictly adheres t
7212
7212
  - Scope should be a noun in parentheses (e.g., (parser), (ui), (config))
7213
7213
  - Omit scope if the change is broad or affects multiple areas
7214
7214
 
7215
+ CRITICAL: You must respond with ONLY valid JSON. All string values must be properly quoted.
7216
+
7215
7217
  Based on the following diff summary, generate a conventional commit message that follows these rules exactly:
7216
7218
 
7217
7219
  """"""
@@ -7838,7 +7840,7 @@ var changelog = {
7838
7840
  options: options$4,
7839
7841
  };
7840
7842
 
7841
- const conventionalTypeRegex = /^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?:/;
7843
+ const conventionalTypeRegex = /^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?!?:/;
7842
7844
  // Regular commit message schema with basic validation
7843
7845
  const CommitMessageResponseSchema = objectType({
7844
7846
  title: stringType().describe("Title of the commit message"),
@@ -7955,6 +7957,55 @@ async function executeChainWithSchema(schema, llm, prompt, variables, options =
7955
7957
  }
7956
7958
  }
7957
7959
 
7960
+ /**
7961
+ * Utility to repair common JSON formatting issues that LLMs make
7962
+ * Specifically handles cases where string values are not properly quoted
7963
+ */
7964
+ function repairJson(jsonString) {
7965
+ // Remove any markdown code block wrapping
7966
+ let cleaned = jsonString.replace(/```(?:json)?\s*([\s\S]*?)\s*```/g, '$1').trim();
7967
+ // Remove inline code block wrapping
7968
+ cleaned = cleaned.replace(/^`(.*)`$/, '$1').trim();
7969
+ // If it doesn't look like JSON, return as-is
7970
+ if (!cleaned.startsWith('{') || !cleaned.endsWith('}')) {
7971
+ return jsonString;
7972
+ }
7973
+ try {
7974
+ // First try parsing as-is
7975
+ JSON.parse(cleaned);
7976
+ return cleaned;
7977
+ }
7978
+ catch {
7979
+ // Try to repair common issues
7980
+ let repaired = cleaned;
7981
+ // Fix unquoted string values in title and body fields
7982
+ // Pattern: "title": unquoted_value, -> "title": "unquoted_value",
7983
+ repaired = repaired.replace(/"(title|body)":\s*([^",\{\}\[\]]+?)(?=\s*[,\}])/g, (match, field, value) => {
7984
+ // Clean up the value (remove leading/trailing whitespace)
7985
+ const cleanValue = value.trim();
7986
+ // If it's already quoted or looks like a number/boolean, leave it
7987
+ if (cleanValue.startsWith('"') || /^(true|false|\d+)$/.test(cleanValue)) {
7988
+ return match;
7989
+ }
7990
+ // Quote the value
7991
+ return `"${field}": "${cleanValue}"`;
7992
+ });
7993
+ // Fix missing quotes around field names (though this should be rare)
7994
+ repaired = repaired.replace(/([{,]\s*)([a-zA-Z_][a-zA-Z0-9_]*)\s*:/g, '$1"$2":');
7995
+ // Remove trailing commas before closing braces
7996
+ repaired = repaired.replace(/,(\s*[}\]])/g, '$1');
7997
+ try {
7998
+ // Test if the repair worked
7999
+ JSON.parse(repaired);
8000
+ return repaired;
8001
+ }
8002
+ catch {
8003
+ // If repair failed, return original
8004
+ return jsonString;
8005
+ }
8006
+ }
8007
+ }
8008
+
7958
8009
  /**
7959
8010
  * Utility function to ensure commit messages are properly formatted as strings
7960
8011
  * rather than JSON objects, whether they come as parsed objects or stringified JSON
@@ -8004,7 +8055,23 @@ function formatCommitMessage(result, options = {}) {
8004
8055
  }
8005
8056
  }
8006
8057
  catch {
8007
- // Not valid JSON, continue to fallback
8058
+ // Try to repair the JSON and parse again
8059
+ try {
8060
+ const repairedJson = repairJson(jsonString);
8061
+ const parsed = JSON.parse(repairedJson);
8062
+ if (parsed &&
8063
+ typeof parsed === 'object' &&
8064
+ typeof parsed.title === 'string' &&
8065
+ typeof parsed.body === 'string' &&
8066
+ parsed.title.length > 0 &&
8067
+ parsed.body.length > 0) {
8068
+ // Successfully repaired and parsed JSON
8069
+ return constructMessage(parsed.title, parsed.body);
8070
+ }
8071
+ }
8072
+ catch {
8073
+ // Repair failed, continue to fallback
8074
+ }
8008
8075
  }
8009
8076
  }
8010
8077
  // If no JSON found and it's already formatted, return as-is
@@ -11495,12 +11562,23 @@ const handler$3 = async (argv, logger) => {
11495
11562
  const schema = USE_CONVENTIONAL_COMMITS
11496
11563
  ? ConventionalCommitMessageResponseSchema
11497
11564
  : CommitMessageResponseSchema;
11498
- const formatInstructions = `You must always return a valid JSON object. Do not return any additional text. The JSON object you return should match the following schema:
11565
+ const formatInstructions = `CRITICAL: You must return ONLY a valid JSON object with no additional text, explanations, or markdown formatting.
11566
+
11567
+ REQUIRED JSON FORMAT:
11499
11568
  ${schema.description}
11569
+
11570
+ EXAMPLE (follow this exact structure):
11500
11571
  {
11501
- "title": "The commit title",
11502
- "body": "The commit body"
11503
- }`;
11572
+ "title": "feat(auth): add user authentication system",
11573
+ "body": "Implement JWT-based authentication with login and logout functionality. Includes password hashing and session management."
11574
+ }
11575
+
11576
+ IMPORTANT RULES:
11577
+ - ALL string values MUST be enclosed in double quotes
11578
+ - NO trailing commas
11579
+ - NO comments or additional text outside the JSON
11580
+ - The "title" and "body" values must be properly quoted strings
11581
+ - Return ONLY the JSON object, nothing else`;
11504
11582
  // Use conventional commit prompt if enabled
11505
11583
  const promptTemplate = USE_CONVENTIONAL_COMMITS ? CONVENTIONAL_COMMIT_PROMPT : COMMIT_PROMPT;
11506
11584
  const prompt = getPrompt({
@@ -12947,6 +13025,18 @@ function checkCommitlintAvailability() {
12947
13025
  try {
12948
13026
  // Try to resolve the package from the current working directory
12949
13027
  require.resolve(pkg, { paths: [process.cwd(), ...module.paths] });
13028
+ // Additional check: try to actually load the config to catch ES module issues
13029
+ try {
13030
+ require(pkg);
13031
+ }
13032
+ catch (loadError) {
13033
+ const loadErrorMessage = loadError instanceof Error ? loadError.message : String(loadError);
13034
+ // If we can resolve but can't load due to ES module issues, treat as missing
13035
+ if (loadErrorMessage.includes('Directory import') ||
13036
+ loadErrorMessage.includes('is not supported resolving ES modules')) {
13037
+ missingPackages.push(pkg);
13038
+ }
13039
+ }
12950
13040
  }
12951
13041
  catch (error) {
12952
13042
  missingPackages.push(pkg);
@@ -12961,6 +13051,15 @@ function checkCommitlintAvailability() {
12961
13051
  missingPackages,
12962
13052
  };
12963
13053
  }
13054
+ /**
13055
+ * Check if we're in a pnpm environment with ES module issues
13056
+ */
13057
+ function isPnpmEsModuleIssue(error) {
13058
+ const message = error.message;
13059
+ return (message.includes('Directory import') &&
13060
+ message.includes('is not supported resolving ES modules') &&
13061
+ message.includes('@commitlint/config-conventional'));
13062
+ }
12964
13063
  /**
12965
13064
  * Load commitlint configuration
12966
13065
  */
@@ -13007,8 +13106,14 @@ async function loadCommitlintConfig() {
13007
13106
  });
13008
13107
  }
13009
13108
  catch (error) {
13010
- // If @commitlint/config-conventional is not available, return a basic conventional config
13011
- if (error instanceof Error && error.message.includes('Cannot find module "@commitlint/config-conventional"')) {
13109
+ if (!(error instanceof Error)) {
13110
+ throw error;
13111
+ }
13112
+ // Handle various types of config-conventional loading errors
13113
+ const isConfigConventionalError = error.message.includes('Cannot find module "@commitlint/config-conventional"') ||
13114
+ isPnpmEsModuleIssue(error);
13115
+ if (isConfigConventionalError) {
13116
+ // Return a basic conventional config that matches @commitlint/config-conventional rules
13012
13117
  return await load({
13013
13118
  rules: {
13014
13119
  'header-max-length': [2, 'always', 72],
@@ -13137,9 +13242,26 @@ async function validateCommitMessage(message, options = {}) {
13137
13242
  };
13138
13243
  }
13139
13244
  catch (error) {
13140
- const errorMessage = error.message;
13141
- // Check if this is a missing dependency error
13142
- if (errorMessage.includes('Cannot find module "@commitlint/config-conventional"')) {
13245
+ if (!(error instanceof Error)) {
13246
+ return {
13247
+ valid: false,
13248
+ errors: [String(error)],
13249
+ warnings: [],
13250
+ };
13251
+ }
13252
+ // Check if this is a config-conventional related error (including pnpm ES module issues)
13253
+ const isConfigConventionalError = error.message.includes('Cannot find module "@commitlint/config-conventional"') ||
13254
+ isPnpmEsModuleIssue(error);
13255
+ if (isConfigConventionalError) {
13256
+ // For pnpm ES module issues, we should have already fallen back to built-in rules
13257
+ // during config loading, so this shouldn't happen. But if it does, provide helpful info.
13258
+ if (isPnpmEsModuleIssue(error)) {
13259
+ return {
13260
+ valid: false,
13261
+ errors: ['pnpm ES module compatibility issue with @commitlint/config-conventional'],
13262
+ warnings: ['Try: pnpm add -D @commitlint/config-conventional@latest @commitlint/cli@latest'],
13263
+ };
13264
+ }
13143
13265
  return {
13144
13266
  valid: false,
13145
13267
  errors: ['Commitlint configuration requires @commitlint/config-conventional to be installed'],
@@ -13149,7 +13271,7 @@ async function validateCommitMessage(message, options = {}) {
13149
13271
  }
13150
13272
  return {
13151
13273
  valid: false,
13152
- errors: [errorMessage],
13274
+ errors: [error.message],
13153
13275
  warnings: [],
13154
13276
  };
13155
13277
  }
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.8";
72
+ const BUILD_VERSION = "0.22.10";
73
73
 
74
74
  const isInteractive = (config) => {
75
75
  return config?.mode === 'interactive' || !!config?.interactive;
@@ -7234,6 +7234,8 @@ const CONVENTIONAL_TEMPLATE = `Generate a commit message that strictly adheres t
7234
7234
  - Scope should be a noun in parentheses (e.g., (parser), (ui), (config))
7235
7235
  - Omit scope if the change is broad or affects multiple areas
7236
7236
 
7237
+ CRITICAL: You must respond with ONLY valid JSON. All string values must be properly quoted.
7238
+
7237
7239
  Based on the following diff summary, generate a conventional commit message that follows these rules exactly:
7238
7240
 
7239
7241
  """"""
@@ -7860,7 +7862,7 @@ var changelog = {
7860
7862
  options: options$4,
7861
7863
  };
7862
7864
 
7863
- const conventionalTypeRegex = /^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?:/;
7865
+ const conventionalTypeRegex = /^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?!?:/;
7864
7866
  // Regular commit message schema with basic validation
7865
7867
  const CommitMessageResponseSchema = objectType({
7866
7868
  title: stringType().describe("Title of the commit message"),
@@ -7977,6 +7979,55 @@ async function executeChainWithSchema(schema, llm, prompt, variables, options =
7977
7979
  }
7978
7980
  }
7979
7981
 
7982
+ /**
7983
+ * Utility to repair common JSON formatting issues that LLMs make
7984
+ * Specifically handles cases where string values are not properly quoted
7985
+ */
7986
+ function repairJson(jsonString) {
7987
+ // Remove any markdown code block wrapping
7988
+ let cleaned = jsonString.replace(/```(?:json)?\s*([\s\S]*?)\s*```/g, '$1').trim();
7989
+ // Remove inline code block wrapping
7990
+ cleaned = cleaned.replace(/^`(.*)`$/, '$1').trim();
7991
+ // If it doesn't look like JSON, return as-is
7992
+ if (!cleaned.startsWith('{') || !cleaned.endsWith('}')) {
7993
+ return jsonString;
7994
+ }
7995
+ try {
7996
+ // First try parsing as-is
7997
+ JSON.parse(cleaned);
7998
+ return cleaned;
7999
+ }
8000
+ catch {
8001
+ // Try to repair common issues
8002
+ let repaired = cleaned;
8003
+ // Fix unquoted string values in title and body fields
8004
+ // Pattern: "title": unquoted_value, -> "title": "unquoted_value",
8005
+ repaired = repaired.replace(/"(title|body)":\s*([^",\{\}\[\]]+?)(?=\s*[,\}])/g, (match, field, value) => {
8006
+ // Clean up the value (remove leading/trailing whitespace)
8007
+ const cleanValue = value.trim();
8008
+ // If it's already quoted or looks like a number/boolean, leave it
8009
+ if (cleanValue.startsWith('"') || /^(true|false|\d+)$/.test(cleanValue)) {
8010
+ return match;
8011
+ }
8012
+ // Quote the value
8013
+ return `"${field}": "${cleanValue}"`;
8014
+ });
8015
+ // Fix missing quotes around field names (though this should be rare)
8016
+ repaired = repaired.replace(/([{,]\s*)([a-zA-Z_][a-zA-Z0-9_]*)\s*:/g, '$1"$2":');
8017
+ // Remove trailing commas before closing braces
8018
+ repaired = repaired.replace(/,(\s*[}\]])/g, '$1');
8019
+ try {
8020
+ // Test if the repair worked
8021
+ JSON.parse(repaired);
8022
+ return repaired;
8023
+ }
8024
+ catch {
8025
+ // If repair failed, return original
8026
+ return jsonString;
8027
+ }
8028
+ }
8029
+ }
8030
+
7980
8031
  /**
7981
8032
  * Utility function to ensure commit messages are properly formatted as strings
7982
8033
  * rather than JSON objects, whether they come as parsed objects or stringified JSON
@@ -8026,7 +8077,23 @@ function formatCommitMessage(result, options = {}) {
8026
8077
  }
8027
8078
  }
8028
8079
  catch {
8029
- // Not valid JSON, continue to fallback
8080
+ // Try to repair the JSON and parse again
8081
+ try {
8082
+ const repairedJson = repairJson(jsonString);
8083
+ const parsed = JSON.parse(repairedJson);
8084
+ if (parsed &&
8085
+ typeof parsed === 'object' &&
8086
+ typeof parsed.title === 'string' &&
8087
+ typeof parsed.body === 'string' &&
8088
+ parsed.title.length > 0 &&
8089
+ parsed.body.length > 0) {
8090
+ // Successfully repaired and parsed JSON
8091
+ return constructMessage(parsed.title, parsed.body);
8092
+ }
8093
+ }
8094
+ catch {
8095
+ // Repair failed, continue to fallback
8096
+ }
8030
8097
  }
8031
8098
  }
8032
8099
  // If no JSON found and it's already formatted, return as-is
@@ -11517,12 +11584,23 @@ const handler$3 = async (argv, logger) => {
11517
11584
  const schema = USE_CONVENTIONAL_COMMITS
11518
11585
  ? ConventionalCommitMessageResponseSchema
11519
11586
  : CommitMessageResponseSchema;
11520
- const formatInstructions = `You must always return a valid JSON object. Do not return any additional text. The JSON object you return should match the following schema:
11587
+ const formatInstructions = `CRITICAL: You must return ONLY a valid JSON object with no additional text, explanations, or markdown formatting.
11588
+
11589
+ REQUIRED JSON FORMAT:
11521
11590
  ${schema.description}
11591
+
11592
+ EXAMPLE (follow this exact structure):
11522
11593
  {
11523
- "title": "The commit title",
11524
- "body": "The commit body"
11525
- }`;
11594
+ "title": "feat(auth): add user authentication system",
11595
+ "body": "Implement JWT-based authentication with login and logout functionality. Includes password hashing and session management."
11596
+ }
11597
+
11598
+ IMPORTANT RULES:
11599
+ - ALL string values MUST be enclosed in double quotes
11600
+ - NO trailing commas
11601
+ - NO comments or additional text outside the JSON
11602
+ - The "title" and "body" values must be properly quoted strings
11603
+ - Return ONLY the JSON object, nothing else`;
11526
11604
  // Use conventional commit prompt if enabled
11527
11605
  const promptTemplate = USE_CONVENTIONAL_COMMITS ? CONVENTIONAL_COMMIT_PROMPT : COMMIT_PROMPT;
11528
11606
  const prompt = getPrompt({
@@ -12969,6 +13047,18 @@ function checkCommitlintAvailability() {
12969
13047
  try {
12970
13048
  // Try to resolve the package from the current working directory
12971
13049
  require.resolve(pkg, { paths: [process.cwd(), ...module.paths] });
13050
+ // Additional check: try to actually load the config to catch ES module issues
13051
+ try {
13052
+ require(pkg);
13053
+ }
13054
+ catch (loadError) {
13055
+ const loadErrorMessage = loadError instanceof Error ? loadError.message : String(loadError);
13056
+ // If we can resolve but can't load due to ES module issues, treat as missing
13057
+ if (loadErrorMessage.includes('Directory import') ||
13058
+ loadErrorMessage.includes('is not supported resolving ES modules')) {
13059
+ missingPackages.push(pkg);
13060
+ }
13061
+ }
12972
13062
  }
12973
13063
  catch (error) {
12974
13064
  missingPackages.push(pkg);
@@ -12983,6 +13073,15 @@ function checkCommitlintAvailability() {
12983
13073
  missingPackages,
12984
13074
  };
12985
13075
  }
13076
+ /**
13077
+ * Check if we're in a pnpm environment with ES module issues
13078
+ */
13079
+ function isPnpmEsModuleIssue(error) {
13080
+ const message = error.message;
13081
+ return (message.includes('Directory import') &&
13082
+ message.includes('is not supported resolving ES modules') &&
13083
+ message.includes('@commitlint/config-conventional'));
13084
+ }
12986
13085
  /**
12987
13086
  * Load commitlint configuration
12988
13087
  */
@@ -13029,8 +13128,14 @@ async function loadCommitlintConfig() {
13029
13128
  });
13030
13129
  }
13031
13130
  catch (error) {
13032
- // If @commitlint/config-conventional is not available, return a basic conventional config
13033
- if (error instanceof Error && error.message.includes('Cannot find module "@commitlint/config-conventional"')) {
13131
+ if (!(error instanceof Error)) {
13132
+ throw error;
13133
+ }
13134
+ // Handle various types of config-conventional loading errors
13135
+ const isConfigConventionalError = error.message.includes('Cannot find module "@commitlint/config-conventional"') ||
13136
+ isPnpmEsModuleIssue(error);
13137
+ if (isConfigConventionalError) {
13138
+ // Return a basic conventional config that matches @commitlint/config-conventional rules
13034
13139
  return await load({
13035
13140
  rules: {
13036
13141
  'header-max-length': [2, 'always', 72],
@@ -13159,9 +13264,26 @@ async function validateCommitMessage(message, options = {}) {
13159
13264
  };
13160
13265
  }
13161
13266
  catch (error) {
13162
- const errorMessage = error.message;
13163
- // Check if this is a missing dependency error
13164
- if (errorMessage.includes('Cannot find module "@commitlint/config-conventional"')) {
13267
+ if (!(error instanceof Error)) {
13268
+ return {
13269
+ valid: false,
13270
+ errors: [String(error)],
13271
+ warnings: [],
13272
+ };
13273
+ }
13274
+ // Check if this is a config-conventional related error (including pnpm ES module issues)
13275
+ const isConfigConventionalError = error.message.includes('Cannot find module "@commitlint/config-conventional"') ||
13276
+ isPnpmEsModuleIssue(error);
13277
+ if (isConfigConventionalError) {
13278
+ // For pnpm ES module issues, we should have already fallen back to built-in rules
13279
+ // during config loading, so this shouldn't happen. But if it does, provide helpful info.
13280
+ if (isPnpmEsModuleIssue(error)) {
13281
+ return {
13282
+ valid: false,
13283
+ errors: ['pnpm ES module compatibility issue with @commitlint/config-conventional'],
13284
+ warnings: ['Try: pnpm add -D @commitlint/config-conventional@latest @commitlint/cli@latest'],
13285
+ };
13286
+ }
13165
13287
  return {
13166
13288
  valid: false,
13167
13289
  errors: ['Commitlint configuration requires @commitlint/config-conventional to be installed'],
@@ -13171,7 +13293,7 @@ async function validateCommitMessage(message, options = {}) {
13171
13293
  }
13172
13294
  return {
13173
13295
  valid: false,
13174
- errors: [errorMessage],
13296
+ errors: [error.message],
13175
13297
  warnings: [],
13176
13298
  };
13177
13299
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-coco",
3
- "version": "0.22.8",
3
+ "version": "0.22.10",
4
4
  "description": "zero-effort git commits with coco.",
5
5
  "author": "gfargo <ghfargo@gmail.com>",
6
6
  "license": "MIT",