git-coco 0.22.4 → 0.22.6

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.4";
50
+ const BUILD_VERSION = "0.22.6";
51
51
 
52
52
  const isInteractive = (config) => {
53
53
  return config?.mode === 'interactive' || !!config?.interactive;
@@ -7960,6 +7960,73 @@ async function executeChainWithSchema(schema, llm, prompt, variables, options =
7960
7960
  }
7961
7961
  }
7962
7962
 
7963
+ /**
7964
+ * Utility function to ensure commit messages are properly formatted as strings
7965
+ * rather than JSON objects, whether they come as parsed objects or stringified JSON
7966
+ */
7967
+ function formatCommitMessage(result, options = {}) {
7968
+ const { append, ticketId, appendTicket } = options;
7969
+ // Helper function to construct the final message with appends
7970
+ const constructMessage = (title, body) => {
7971
+ const appendedText = append ? `\n\n${append}` : '';
7972
+ const ticketFooter = appendTicket && ticketId ? `\n\nPart of **${ticketId}**` : '';
7973
+ return `${title}\n\n${body}${appendedText}${ticketFooter}`;
7974
+ };
7975
+ // If it's a string, check if it contains a JSON object (including markdown code blocks)
7976
+ if (typeof result === 'string') {
7977
+ // Early return if string clearly doesn't contain JSON-like content
7978
+ if (!result.includes('{') && !result.includes('"title"')) {
7979
+ return result;
7980
+ }
7981
+ // Handle multiple markdown code block formats
7982
+ const codeBlockPatterns = [
7983
+ /```(?:json)?\s*(\{[\s\S]*?\})\s*```/, // Standard markdown blocks
7984
+ /`(\{[\s\S]*?\})`/, // Inline code blocks
7985
+ /^\s*(\{[\s\S]*\})\s*$/ // Raw JSON without blocks
7986
+ ];
7987
+ let jsonString = result;
7988
+ // Try each pattern to extract JSON
7989
+ for (const pattern of codeBlockPatterns) {
7990
+ const match = result.match(pattern);
7991
+ if (match && match[1]) {
7992
+ jsonString = match[1].trim();
7993
+ break;
7994
+ }
7995
+ }
7996
+ // Only attempt JSON parsing if we found potential JSON content
7997
+ if (jsonString !== result || jsonString.startsWith('{')) {
7998
+ try {
7999
+ // Try to parse as JSON to see if it's a stringified object
8000
+ const parsed = JSON.parse(jsonString);
8001
+ if (parsed &&
8002
+ typeof parsed === 'object' &&
8003
+ typeof parsed.title === 'string' &&
8004
+ typeof parsed.body === 'string' &&
8005
+ parsed.title.length > 0 &&
8006
+ parsed.body.length > 0) {
8007
+ // It's a valid stringified JSON object, format it properly
8008
+ return constructMessage(parsed.title, parsed.body);
8009
+ }
8010
+ }
8011
+ catch {
8012
+ // Not valid JSON, continue to fallback
8013
+ }
8014
+ }
8015
+ // If no JSON found and it's already formatted, return as-is
8016
+ return result;
8017
+ }
8018
+ // If it's already an object with title and body, format it
8019
+ if (typeof result === 'object' && result !== null &&
8020
+ 'title' in result && 'body' in result) {
8021
+ const commitMsgObj = result;
8022
+ if (typeof commitMsgObj.title === 'string' && typeof commitMsgObj.body === 'string') {
8023
+ return constructMessage(commitMsgObj.title, commitMsgObj.body);
8024
+ }
8025
+ }
8026
+ // Fallback - convert to string and return as-is
8027
+ return String(result);
8028
+ }
8029
+
7963
8030
  /**
7964
8031
  * Extract the path from a file path string.
7965
8032
  * @param {string} filePath - The full file path.
@@ -11545,11 +11612,13 @@ ${schema.description}
11545
11612
  });
11546
11613
  },
11547
11614
  });
11548
- // Construct the full commit message
11549
- const appendedText = argv.append ? `\n\n${argv.append}` : '';
11615
+ // Construct the full commit message using the utility function
11550
11616
  const ticketId = extractTicketIdFromBranchName(branchName);
11551
- const ticketFooter = argv.appendTicket && ticketId ? `\n\nPart of **${ticketId}**` : '';
11552
- const fullMessage = `${commitMsg.title}\n\n${commitMsg.body}${appendedText}${ticketFooter}`;
11617
+ const fullMessage = formatCommitMessage(commitMsg, {
11618
+ append: argv.append,
11619
+ ticketId: ticketId || undefined,
11620
+ appendTicket: argv.appendTicket,
11621
+ });
11553
11622
  // If commitlint validation is needed and not skipped, validate the message
11554
11623
  if ((USE_CONVENTIONAL_COMMITS || hasCommitLintConfig) && !shouldSkipCommitlintValidation) {
11555
11624
  const { validateCommitMessage, CommitlintValidationError } = await Promise.resolve().then(function () { return commitlintValidator; });
@@ -11632,14 +11701,7 @@ ${schema.description}
11632
11701
  logger.verbose(`Retrying commit message generation (attempt ${attempt}): ${error.message}`, { color: 'yellow' });
11633
11702
  },
11634
11703
  });
11635
- // Ensure we always return a formatted string, not a JSON object
11636
- if (typeof result === 'object' && result !== null && 'title' in result && 'body' in result) {
11637
- const commitMsgObj = result;
11638
- const appendedText = argv.append ? `\n\n${argv.append}` : '';
11639
- const ticketId = extractTicketIdFromBranchName(branchName);
11640
- const ticketFooter = argv.appendTicket && ticketId ? `\n\nPart of **${ticketId}**` : '';
11641
- return `${commitMsgObj.title}\n\n${commitMsgObj.body}${appendedText}${ticketFooter}`;
11642
- }
11704
+ // Return the result which is already a properly formatted commit message string
11643
11705
  return result;
11644
11706
  },
11645
11707
  noResult: async () => {
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.4";
72
+ const BUILD_VERSION = "0.22.6";
73
73
 
74
74
  const isInteractive = (config) => {
75
75
  return config?.mode === 'interactive' || !!config?.interactive;
@@ -7982,6 +7982,73 @@ async function executeChainWithSchema(schema, llm, prompt, variables, options =
7982
7982
  }
7983
7983
  }
7984
7984
 
7985
+ /**
7986
+ * Utility function to ensure commit messages are properly formatted as strings
7987
+ * rather than JSON objects, whether they come as parsed objects or stringified JSON
7988
+ */
7989
+ function formatCommitMessage(result, options = {}) {
7990
+ const { append, ticketId, appendTicket } = options;
7991
+ // Helper function to construct the final message with appends
7992
+ const constructMessage = (title, body) => {
7993
+ const appendedText = append ? `\n\n${append}` : '';
7994
+ const ticketFooter = appendTicket && ticketId ? `\n\nPart of **${ticketId}**` : '';
7995
+ return `${title}\n\n${body}${appendedText}${ticketFooter}`;
7996
+ };
7997
+ // If it's a string, check if it contains a JSON object (including markdown code blocks)
7998
+ if (typeof result === 'string') {
7999
+ // Early return if string clearly doesn't contain JSON-like content
8000
+ if (!result.includes('{') && !result.includes('"title"')) {
8001
+ return result;
8002
+ }
8003
+ // Handle multiple markdown code block formats
8004
+ const codeBlockPatterns = [
8005
+ /```(?:json)?\s*(\{[\s\S]*?\})\s*```/, // Standard markdown blocks
8006
+ /`(\{[\s\S]*?\})`/, // Inline code blocks
8007
+ /^\s*(\{[\s\S]*\})\s*$/ // Raw JSON without blocks
8008
+ ];
8009
+ let jsonString = result;
8010
+ // Try each pattern to extract JSON
8011
+ for (const pattern of codeBlockPatterns) {
8012
+ const match = result.match(pattern);
8013
+ if (match && match[1]) {
8014
+ jsonString = match[1].trim();
8015
+ break;
8016
+ }
8017
+ }
8018
+ // Only attempt JSON parsing if we found potential JSON content
8019
+ if (jsonString !== result || jsonString.startsWith('{')) {
8020
+ try {
8021
+ // Try to parse as JSON to see if it's a stringified object
8022
+ const parsed = JSON.parse(jsonString);
8023
+ if (parsed &&
8024
+ typeof parsed === 'object' &&
8025
+ typeof parsed.title === 'string' &&
8026
+ typeof parsed.body === 'string' &&
8027
+ parsed.title.length > 0 &&
8028
+ parsed.body.length > 0) {
8029
+ // It's a valid stringified JSON object, format it properly
8030
+ return constructMessage(parsed.title, parsed.body);
8031
+ }
8032
+ }
8033
+ catch {
8034
+ // Not valid JSON, continue to fallback
8035
+ }
8036
+ }
8037
+ // If no JSON found and it's already formatted, return as-is
8038
+ return result;
8039
+ }
8040
+ // If it's already an object with title and body, format it
8041
+ if (typeof result === 'object' && result !== null &&
8042
+ 'title' in result && 'body' in result) {
8043
+ const commitMsgObj = result;
8044
+ if (typeof commitMsgObj.title === 'string' && typeof commitMsgObj.body === 'string') {
8045
+ return constructMessage(commitMsgObj.title, commitMsgObj.body);
8046
+ }
8047
+ }
8048
+ // Fallback - convert to string and return as-is
8049
+ return String(result);
8050
+ }
8051
+
7985
8052
  /**
7986
8053
  * Extract the path from a file path string.
7987
8054
  * @param {string} filePath - The full file path.
@@ -11567,11 +11634,13 @@ ${schema.description}
11567
11634
  });
11568
11635
  },
11569
11636
  });
11570
- // Construct the full commit message
11571
- const appendedText = argv.append ? `\n\n${argv.append}` : '';
11637
+ // Construct the full commit message using the utility function
11572
11638
  const ticketId = extractTicketIdFromBranchName(branchName);
11573
- const ticketFooter = argv.appendTicket && ticketId ? `\n\nPart of **${ticketId}**` : '';
11574
- const fullMessage = `${commitMsg.title}\n\n${commitMsg.body}${appendedText}${ticketFooter}`;
11639
+ const fullMessage = formatCommitMessage(commitMsg, {
11640
+ append: argv.append,
11641
+ ticketId: ticketId || undefined,
11642
+ appendTicket: argv.appendTicket,
11643
+ });
11575
11644
  // If commitlint validation is needed and not skipped, validate the message
11576
11645
  if ((USE_CONVENTIONAL_COMMITS || hasCommitLintConfig) && !shouldSkipCommitlintValidation) {
11577
11646
  const { validateCommitMessage, CommitlintValidationError } = await Promise.resolve().then(function () { return commitlintValidator; });
@@ -11654,14 +11723,7 @@ ${schema.description}
11654
11723
  logger.verbose(`Retrying commit message generation (attempt ${attempt}): ${error.message}`, { color: 'yellow' });
11655
11724
  },
11656
11725
  });
11657
- // Ensure we always return a formatted string, not a JSON object
11658
- if (typeof result === 'object' && result !== null && 'title' in result && 'body' in result) {
11659
- const commitMsgObj = result;
11660
- const appendedText = argv.append ? `\n\n${argv.append}` : '';
11661
- const ticketId = extractTicketIdFromBranchName(branchName);
11662
- const ticketFooter = argv.appendTicket && ticketId ? `\n\nPart of **${ticketId}**` : '';
11663
- return `${commitMsgObj.title}\n\n${commitMsgObj.body}${appendedText}${ticketFooter}`;
11664
- }
11726
+ // Return the result which is already a properly formatted commit message string
11665
11727
  return result;
11666
11728
  },
11667
11729
  noResult: async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-coco",
3
- "version": "0.22.4",
3
+ "version": "0.22.6",
4
4
  "description": "zero-effort git commits with coco.",
5
5
  "author": "gfargo <ghfargo@gmail.com>",
6
6
  "license": "MIT",