git-coco 0.11.0 → 0.11.1

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.d.ts CHANGED
@@ -75,7 +75,7 @@ declare const _default$1: {
75
75
  };
76
76
 
77
77
  type LLMProvider = 'openai' | 'ollama';
78
- type OllamaModel = 'neural-chat' | 'aya:8b' | 'aya:35b' | 'mistral' | 'llama2' | 'codellama' | 'codellama:7b' | 'codellama:13b' | 'codellama:34b' | 'codellama:70b' | 'llama2-uncensored' | 'llama2:13b' | 'llama2:70b' | 'llama3' | 'llama3:latest' | 'llama3:text' | 'llama3:70b' | 'llama3:70b-text' | 'orca2' | 'orca2:13b' | 'orca-mini' | 'orca-mini:latest' | 'orca-mini:13b' | 'orca-mini:70b' | 'phi3' | 'phi3:mini' | 'phi3:medium' | 'phi3:medium-128k' | 'qwen2' | 'qwen2:72b' | 'qwen2:72b-text' | 'qwen2:1.5b' | 'qwen2:0.5b' | 'gemma' | 'gemma:7b`' | 'gemma:2b' | 'codegemma' | 'codegemma:7b-code' | 'codegemma:2b';
78
+ type OllamaModel = 'codegemma:2b' | 'codegemma:7b-code' | 'codegemma' | 'codellama:13b' | 'codellama:34b' | 'codellama:70b' | 'codellama:7b' | 'codellama:instruct' | 'codellama:latest' | 'codellama' | 'gemma:2b' | 'gemma:7b' | 'gemma:latest' | 'gemma' | 'llama2:13b' | 'llama2:70b' | 'llama2:chat' | 'llama2:latest' | 'llama2:text' | 'llama2' | 'llama3:70b-text' | 'llama3:70b' | 'llama3:latest' | 'llama3:text' | 'llama3.1:70b' | 'llama3.1:8b' | 'llama3.1:latest' | 'llama3.2' | 'llama3.2:latest' | 'llama3.2:1b' | 'llama3.2:3b' | 'llama3.2:1b-instruct-fp16' | 'llama3.2:1b-instruct-q3_K_M' | 'llama3' | 'mistral:7b' | 'mistral:latest' | 'mistral:text' | 'mistral' | 'phi3:14b' | 'phi3:3.8b' | 'phi3:instruct' | 'phi3:medium-128k' | 'phi3:medium-4k' | 'phi3:medium' | 'phi3' | 'qwen2:0.5b' | 'qwen2:1.5b' | 'qwen2:72b-text' | 'qwen2:72b' | 'qwen2';
79
79
  type LLMModel = TiktokenModel | OllamaModel;
80
80
  type BaseLLMService = {
81
81
  provider: LLMProvider;
@@ -15,23 +15,23 @@ import Ajv from 'ajv';
15
15
  import ora from 'ora';
16
16
  import now from 'performance-now';
17
17
  import prettyMilliseconds from 'pretty-ms';
18
+ import { BaseOutputParser, JsonOutputParser } from '@langchain/core/output_parsers';
19
+ import { ChatOllama } from '@langchain/ollama';
20
+ import { ChatOpenAI } from '@langchain/openai';
18
21
  import pQueue from 'p-queue';
19
22
  import { Document, BaseDocumentTransformer } from '@langchain/core/documents';
20
23
  import { RUN_KEY } from '@langchain/core/outputs';
21
24
  import { CallbackManager, parseCallbackConfigArg } from '@langchain/core/callbacks/manager';
22
25
  import { ensureConfig, Runnable } from '@langchain/core/runnables';
23
26
  import { BaseLangChain, BaseLanguageModel } from '@langchain/core/language_models/base';
24
- import { BaseOutputParser, JsonOutputParser } from '@langchain/core/output_parsers';
25
27
  import '@langchain/core/messages';
26
28
  import '@langchain/core/memory';
27
29
  import '@langchain/core/chat_history';
28
30
  import '@langchain/core/utils/tiktoken';
29
- import { ChatOpenAI } from '@langchain/openai';
30
31
  import '@langchain/core/utils/async_caller';
31
32
  import '@langchain/core/utils/env';
32
33
  import '@langchain/core/utils/json_patch';
33
34
  import { createTwoFilesPatch } from 'diff';
34
- import { ChatOllama } from '@langchain/ollama';
35
35
  import { minimatch } from 'minimatch';
36
36
  import { simpleGit } from 'simple-git';
37
37
  import { encoding_for_model } from 'tiktoken';
@@ -107,9 +107,9 @@ function getDefaultServiceApiKey(config) {
107
107
  }
108
108
  const DEFAULT_OPENAI_LLM_SERVICE = {
109
109
  provider: 'openai',
110
- model: 'gpt-4-turbo',
110
+ model: 'gpt-4',
111
111
  tokenLimit: 2024,
112
- temperature: 0.4,
112
+ temperature: 0.32,
113
113
  authentication: {
114
114
  type: 'APIKey',
115
115
  credentials: {
@@ -1915,6 +1915,66 @@ function commandExecutor(handler) {
1915
1915
  };
1916
1916
  }
1917
1917
 
1918
+ const executeChain = async ({ llm, prompt, variables, parser, }) => {
1919
+ if (!llm || !prompt || !variables) {
1920
+ throw new Error('The input parameters "llm", "prompt", and "variables" are all required.');
1921
+ }
1922
+ const chain = prompt.pipe(llm).pipe(parser);
1923
+ let res;
1924
+ try {
1925
+ res = await chain.invoke(variables);
1926
+ }
1927
+ catch (error) {
1928
+ if (error instanceof Error) {
1929
+ throw new Error(`LLMChain call error: ${error.message}`);
1930
+ }
1931
+ }
1932
+ if (!res) {
1933
+ throw new Error('Empty response from LLMChain call');
1934
+ }
1935
+ return res;
1936
+ };
1937
+
1938
+ /**
1939
+ * Get LLM Model Based on Configuration
1940
+ *
1941
+ * @param fields
1942
+ * @param configuration
1943
+ * @returns LLM Model
1944
+ */
1945
+ function getLlm(provider, model, config) {
1946
+ if (!model) {
1947
+ throw new Error(`Invalid LLM Service: ${provider}/${model}`);
1948
+ }
1949
+ switch (provider) {
1950
+ case 'ollama':
1951
+ return new ChatOllama({
1952
+ baseUrl: DEFAULT_OLLAMA_LLM_SERVICE.endpoint,
1953
+ maxConcurrency: config.service.maxConcurrent,
1954
+ model,
1955
+ });
1956
+ case 'openai':
1957
+ default:
1958
+ const openAiModel = new ChatOpenAI({
1959
+ openAIApiKey: getApiKeyForModel(config),
1960
+ model,
1961
+ temperature: config.service.temperature || 0.2,
1962
+ });
1963
+ return openAiModel;
1964
+ }
1965
+ }
1966
+
1967
+ function getPrompt({ template, variables, fallback }) {
1968
+ if (!template && !fallback)
1969
+ throw new Error('Must provide either a template or a fallback');
1970
+ return (template
1971
+ ? new PromptTemplate({
1972
+ template,
1973
+ inputVariables: variables,
1974
+ })
1975
+ : fallback);
1976
+ }
1977
+
1918
1978
  /**
1919
1979
  * Extract the path from a file path string.
1920
1980
  * @param {string} filePath - The full file path.
@@ -5498,62 +5558,15 @@ async function fileChangeParser({ changes, commit, options: { tokenizer, git, ll
5498
5558
  return summary;
5499
5559
  }
5500
5560
 
5501
- const template$1 = `Write informative git commit message, in the imperative, based on the diffs & file changes provided in the "Diff Summary" section.
5502
- Commit Messages must have a short description that is less than 50 characters and a longer detailed summary no more than 300 characters, the shorter and more concise the better. Please follow the guidelines below when writing your commit message:
5503
-
5504
- - Write concisely using an informal tone
5505
- - DO NOT use phrases like "this commit", "this change", "this function", etc. Instead refer to the function, variable, or class by name
5506
- - DO NOT use specific names or files from the code
5507
- - DO NOT include any diffs or file changes in the commit message
5508
- - Wrap variable, class, function, components, and dependency names in back ticks e.g. \`variable\`
5509
-
5510
- {format_instructions}
5511
-
5512
- """{summary}"""`;
5513
- const inputVariables$1 = ['summary', 'format_instructions'];
5514
- const COMMIT_PROMPT = new PromptTemplate({
5515
- template: template$1,
5516
- inputVariables: inputVariables$1,
5517
- });
5518
-
5519
5561
  /**
5520
- * Get LLM Model Based on Configuration
5562
+ * Creates a commit with the specified commit message.
5521
5563
  *
5522
- * @param fields
5523
- * @param configuration
5524
- * @returns LLM Model
5564
+ * @param message The commit message.
5565
+ * @param git The SimpleGit instance.
5566
+ * @returns A Promise that resolves to the CommitResult.
5525
5567
  */
5526
- function getLlm(provider, model, config) {
5527
- if (!model) {
5528
- throw new Error(`Invalid LLM Service: ${provider}/${model}`);
5529
- }
5530
- switch (provider) {
5531
- case 'ollama':
5532
- return new ChatOllama({
5533
- baseUrl: DEFAULT_OLLAMA_LLM_SERVICE.endpoint,
5534
- maxConcurrency: config.service.maxConcurrent,
5535
- model,
5536
- });
5537
- case 'openai':
5538
- default:
5539
- const openAiModel = new ChatOpenAI({
5540
- openAIApiKey: getApiKeyForModel(config),
5541
- model,
5542
- temperature: config.service.temperature || 0.2,
5543
- });
5544
- return openAiModel;
5545
- }
5546
- }
5547
-
5548
- function getPrompt({ template, variables, fallback }) {
5549
- if (!template && !fallback)
5550
- throw new Error('Must provide either a template or a fallback');
5551
- return (template
5552
- ? new PromptTemplate({
5553
- template,
5554
- inputVariables: variables,
5555
- })
5556
- : fallback);
5568
+ async function createCommit(message, git) {
5569
+ return await git.commit(message);
5557
5570
  }
5558
5571
 
5559
5572
  /**
@@ -5685,34 +5698,39 @@ async function getChanges({ git, options }) {
5685
5698
  };
5686
5699
  }
5687
5700
 
5688
- async function noResult({ git, logger }) {
5689
- const { staged, unstaged, untracked } = await getChanges({ git });
5690
- const hasStaged = staged && staged.length > 0;
5691
- const hasUnstaged = unstaged && unstaged.length > 0;
5692
- const hasUntracked = untracked && untracked.length > 0;
5693
- if (hasStaged) {
5694
- logger.log(`Staged files detected, but no summary generated...`, { color: 'red' });
5695
- logger.log(`Files are likely either:\n • changed files are ignored\n • file diff is too large.`, { color: 'yellow' });
5696
- }
5697
- else if (hasUnstaged || hasUntracked) {
5698
- logger.log('Forget something? No staged changes found... 👻', { color: 'red' });
5699
- if (hasUnstaged) {
5700
- logger.log('\nChanges not staged for commit:', { color: 'yellow' });
5701
- logger.verbose(`\t${unstaged.map(({ summary }) => summary).join('\n\t')}`, {
5702
- color: 'red',
5703
- });
5704
- }
5705
- if (hasUntracked) {
5706
- logger.log('\nUntracked changes:', { color: 'yellow' });
5707
- logger.verbose(`\t${untracked.map(({ summary }) => summary).join('\n\t')}`, {
5708
- color: 'red',
5709
- });
5710
- }
5701
+ /**
5702
+ * Retrieves the SimpleGit instance for the repository.
5703
+ * @returns {SimpleGit} The SimpleGit instance.
5704
+ */
5705
+ const getRepo = () => {
5706
+ let git;
5707
+ try {
5708
+ git = simpleGit();
5711
5709
  }
5712
- else {
5713
- logger.log('No repo changes detected. 👀', { color: 'blue' });
5710
+ catch (e) {
5711
+ console.log('Error initializing git repo', e);
5712
+ process.exit(1);
5714
5713
  }
5715
- }
5714
+ return git;
5715
+ };
5716
+
5717
+ const template$1 = `Write informative git commit message, in the imperative, based on the diffs & file changes provided in the "Diff Summary" section.
5718
+ Commit Messages must have a short description that is less than 50 characters and a longer detailed summary no more than 300 characters, the shorter and more concise the better. Please follow the guidelines below when writing your commit message:
5719
+
5720
+ - Write concisely using an informal tone
5721
+ - DO NOT use phrases like "this commit", "this change", "this function", etc. Instead refer to the function, variable, or class by name
5722
+ - DO NOT use specific names or files from the code
5723
+ - DO NOT include any diffs or file changes in the commit message
5724
+ - Wrap variable, class, function, components, and dependency names in back ticks e.g. \`variable\`
5725
+
5726
+ {format_instructions}
5727
+
5728
+ """{summary}"""`;
5729
+ const inputVariables$1 = ['summary', 'format_instructions'];
5730
+ const COMMIT_PROMPT = new PromptTemplate({
5731
+ template: template$1,
5732
+ inputVariables: inputVariables$1,
5733
+ });
5716
5734
 
5717
5735
  /**
5718
5736
  * Verify template string contains all required input variables
@@ -5880,26 +5898,6 @@ async function generateAndReviewLoop({ label, factory, parser, noResult, agent,
5880
5898
  return result;
5881
5899
  }
5882
5900
 
5883
- const executeChain = async ({ llm, prompt, variables, parser, }) => {
5884
- if (!llm || !prompt || !variables) {
5885
- throw new Error('The input parameters "llm", "prompt", and "variables" are all required.');
5886
- }
5887
- const chain = prompt.pipe(llm).pipe(parser);
5888
- let res;
5889
- try {
5890
- res = await chain.invoke(variables);
5891
- }
5892
- catch (error) {
5893
- if (error instanceof Error) {
5894
- throw new Error(`LLMChain call error: ${error.message}`);
5895
- }
5896
- }
5897
- if (!res) {
5898
- throw new Error('Empty response from LLMChain call');
5899
- }
5900
- return res;
5901
- };
5902
-
5903
5901
  const logSuccess = () => {
5904
5902
  console.log(chalk.green(chalk.bold('\nAll set! 🦾🤖')));
5905
5903
  };
@@ -5923,22 +5921,6 @@ async function handleResult({ result, mode, interactiveHandler }) {
5923
5921
  process.exit(0);
5924
5922
  }
5925
5923
 
5926
- /**
5927
- * Retrieves the SimpleGit instance for the repository.
5928
- * @returns {SimpleGit} The SimpleGit instance.
5929
- */
5930
- const getRepo = () => {
5931
- let git;
5932
- try {
5933
- git = simpleGit();
5934
- }
5935
- catch (e) {
5936
- console.log('Error initializing git repo', e);
5937
- process.exit(1);
5938
- }
5939
- return git;
5940
- };
5941
-
5942
5924
  /**
5943
5925
  * Retrieves a TikToken for the specified model.
5944
5926
  *
@@ -5961,15 +5943,33 @@ const getTokenCounter = async (modelName) => {
5961
5943
  });
5962
5944
  };
5963
5945
 
5964
- /**
5965
- * Creates a commit with the specified commit message.
5966
- *
5967
- * @param message The commit message.
5968
- * @param git The SimpleGit instance.
5969
- * @returns A Promise that resolves to the CommitResult.
5970
- */
5971
- async function createCommit(message, git) {
5972
- return await git.commit(message);
5946
+ async function noResult({ git, logger }) {
5947
+ const { staged, unstaged, untracked } = await getChanges({ git });
5948
+ const hasStaged = staged && staged.length > 0;
5949
+ const hasUnstaged = unstaged && unstaged.length > 0;
5950
+ const hasUntracked = untracked && untracked.length > 0;
5951
+ if (hasStaged) {
5952
+ logger.log(`Staged files detected, but no summary generated...`, { color: 'red' });
5953
+ logger.log(`Files are likely either:\n • changed files are ignored\n • file diff is too large.`, { color: 'yellow' });
5954
+ }
5955
+ else if (hasUnstaged || hasUntracked) {
5956
+ logger.log('Forget something? No staged changes found... 👻', { color: 'red' });
5957
+ if (hasUnstaged) {
5958
+ logger.log('\nChanges not staged for commit:', { color: 'yellow' });
5959
+ logger.verbose(`\t${unstaged.map(({ summary }) => summary).join('\n\t')}`, {
5960
+ color: 'red',
5961
+ });
5962
+ }
5963
+ if (hasUntracked) {
5964
+ logger.log('\nUntracked changes:', { color: 'yellow' });
5965
+ logger.verbose(`\t${untracked.map(({ summary }) => summary).join('\n\t')}`, {
5966
+ color: 'red',
5967
+ });
5968
+ }
5969
+ }
5970
+ else {
5971
+ logger.log('No repo changes detected. 👀', { color: 'blue' });
5972
+ }
5973
5973
  }
5974
5974
 
5975
5975
  const handler$2 = async (argv, logger) => {
@@ -6117,7 +6117,7 @@ async function getCommitLogRange(from, to, { noMerges, git }) {
6117
6117
  try {
6118
6118
  const logOptions = { from: `${from}^1`, to, '--no-merges': noMerges };
6119
6119
  const commitLog = await git.log(logOptions);
6120
- return commitLog.all.map(({ message, date, body, author_name, hash, author_email }) => `[${date}] ${message}\n${body}\n - ${author_name}<${author_email}> (${hash})`);
6120
+ return commitLog.all.map(({ message, date, body, author_name, hash, author_email }) => `[${date}] ${message}\n${body}\n(${hash}) - ${author_name}<${author_email}>`);
6121
6121
  }
6122
6122
  catch (error) {
6123
6123
  // If there's an error, handle it appropriately
@@ -6190,8 +6190,8 @@ async function getCommitLogCurrentBranch({ git, logger, comparisonBranch = 'main
6190
6190
 
6191
6191
  const template = `Write informative git changelog, in the imperative, based on a series of individual messages.
6192
6192
 
6193
- - Typically a hyphen or asterisk is used for the bullet
6194
- - Summarize dependency updates
6193
+ - Include the git commit hash as reference for each change, including just the first 7 characters
6194
+ - Logically group changes, and if necessary, summarize dependency updates
6195
6195
 
6196
6196
  {format_instructions}
6197
6197
 
@@ -6236,8 +6236,8 @@ const handler$1 = async (argv, logger) => {
6236
6236
  };
6237
6237
  }
6238
6238
  async function parser({ branch, commits }) {
6239
- console.log({ branch, commits });
6240
- const result = `## ${branch}\n\n${commits.map((commit) => `- ${commit}`).join('\n')}`;
6239
+ const result = `## ${branch}\n\n${commits.map((commit) => `${commit}`).join('\n\n\n')}`;
6240
+ console.log({ result });
6241
6241
  return result;
6242
6242
  }
6243
6243
  const changelogMsg = await generateAndReviewLoop({
@@ -6251,7 +6251,7 @@ const handler$1 = async (argv, logger) => {
6251
6251
  variables: CHANGELOG_PROMPT.inputVariables,
6252
6252
  fallback: CHANGELOG_PROMPT,
6253
6253
  });
6254
- const formatInstructions = "Respond with a valid JSON object, containing two fields: 'header' and 'content'.";
6254
+ const formatInstructions = "Respond with a valid JSON object, containing two fields: 'header' and 'content', both strings.";
6255
6255
  const changelog = await executeChain({
6256
6256
  llm,
6257
6257
  prompt,
@@ -6261,7 +6261,6 @@ const handler$1 = async (argv, logger) => {
6261
6261
  },
6262
6262
  parser,
6263
6263
  });
6264
- console.log({ changelog });
6265
6264
  return `${changelog.header}\n\n${changelog.content}`;
6266
6265
  },
6267
6266
  noResult: async () => {
package/dist/index.js CHANGED
@@ -14,23 +14,23 @@ var Ajv = require('ajv');
14
14
  var ora = require('ora');
15
15
  var now = require('performance-now');
16
16
  var prettyMilliseconds = require('pretty-ms');
17
+ var output_parsers = require('@langchain/core/output_parsers');
18
+ var ollama = require('@langchain/ollama');
19
+ var openai = require('@langchain/openai');
17
20
  var pQueue = require('p-queue');
18
21
  var documents = require('@langchain/core/documents');
19
22
  var outputs = require('@langchain/core/outputs');
20
23
  var manager = require('@langchain/core/callbacks/manager');
21
24
  var runnables = require('@langchain/core/runnables');
22
25
  var base = require('@langchain/core/language_models/base');
23
- var output_parsers = require('@langchain/core/output_parsers');
24
26
  require('@langchain/core/messages');
25
27
  require('@langchain/core/memory');
26
28
  require('@langchain/core/chat_history');
27
29
  require('@langchain/core/utils/tiktoken');
28
- var openai = require('@langchain/openai');
29
30
  require('@langchain/core/utils/async_caller');
30
31
  require('@langchain/core/utils/env');
31
32
  require('@langchain/core/utils/json_patch');
32
33
  var diff = require('diff');
33
- var ollama = require('@langchain/ollama');
34
34
  var minimatch = require('minimatch');
35
35
  var simpleGit = require('simple-git');
36
36
  var tiktoken = require('tiktoken');
@@ -128,9 +128,9 @@ function getDefaultServiceApiKey(config) {
128
128
  }
129
129
  const DEFAULT_OPENAI_LLM_SERVICE = {
130
130
  provider: 'openai',
131
- model: 'gpt-4-turbo',
131
+ model: 'gpt-4',
132
132
  tokenLimit: 2024,
133
- temperature: 0.4,
133
+ temperature: 0.32,
134
134
  authentication: {
135
135
  type: 'APIKey',
136
136
  credentials: {
@@ -1936,6 +1936,66 @@ function commandExecutor(handler) {
1936
1936
  };
1937
1937
  }
1938
1938
 
1939
+ const executeChain = async ({ llm, prompt, variables, parser, }) => {
1940
+ if (!llm || !prompt || !variables) {
1941
+ throw new Error('The input parameters "llm", "prompt", and "variables" are all required.');
1942
+ }
1943
+ const chain = prompt.pipe(llm).pipe(parser);
1944
+ let res;
1945
+ try {
1946
+ res = await chain.invoke(variables);
1947
+ }
1948
+ catch (error) {
1949
+ if (error instanceof Error) {
1950
+ throw new Error(`LLMChain call error: ${error.message}`);
1951
+ }
1952
+ }
1953
+ if (!res) {
1954
+ throw new Error('Empty response from LLMChain call');
1955
+ }
1956
+ return res;
1957
+ };
1958
+
1959
+ /**
1960
+ * Get LLM Model Based on Configuration
1961
+ *
1962
+ * @param fields
1963
+ * @param configuration
1964
+ * @returns LLM Model
1965
+ */
1966
+ function getLlm(provider, model, config) {
1967
+ if (!model) {
1968
+ throw new Error(`Invalid LLM Service: ${provider}/${model}`);
1969
+ }
1970
+ switch (provider) {
1971
+ case 'ollama':
1972
+ return new ollama.ChatOllama({
1973
+ baseUrl: DEFAULT_OLLAMA_LLM_SERVICE.endpoint,
1974
+ maxConcurrency: config.service.maxConcurrent,
1975
+ model,
1976
+ });
1977
+ case 'openai':
1978
+ default:
1979
+ const openAiModel = new openai.ChatOpenAI({
1980
+ openAIApiKey: getApiKeyForModel(config),
1981
+ model,
1982
+ temperature: config.service.temperature || 0.2,
1983
+ });
1984
+ return openAiModel;
1985
+ }
1986
+ }
1987
+
1988
+ function getPrompt({ template, variables, fallback }) {
1989
+ if (!template && !fallback)
1990
+ throw new Error('Must provide either a template or a fallback');
1991
+ return (template
1992
+ ? new prompts.PromptTemplate({
1993
+ template,
1994
+ inputVariables: variables,
1995
+ })
1996
+ : fallback);
1997
+ }
1998
+
1939
1999
  /**
1940
2000
  * Extract the path from a file path string.
1941
2001
  * @param {string} filePath - The full file path.
@@ -5519,62 +5579,15 @@ async function fileChangeParser({ changes, commit, options: { tokenizer, git, ll
5519
5579
  return summary;
5520
5580
  }
5521
5581
 
5522
- const template$1 = `Write informative git commit message, in the imperative, based on the diffs & file changes provided in the "Diff Summary" section.
5523
- Commit Messages must have a short description that is less than 50 characters and a longer detailed summary no more than 300 characters, the shorter and more concise the better. Please follow the guidelines below when writing your commit message:
5524
-
5525
- - Write concisely using an informal tone
5526
- - DO NOT use phrases like "this commit", "this change", "this function", etc. Instead refer to the function, variable, or class by name
5527
- - DO NOT use specific names or files from the code
5528
- - DO NOT include any diffs or file changes in the commit message
5529
- - Wrap variable, class, function, components, and dependency names in back ticks e.g. \`variable\`
5530
-
5531
- {format_instructions}
5532
-
5533
- """{summary}"""`;
5534
- const inputVariables$1 = ['summary', 'format_instructions'];
5535
- const COMMIT_PROMPT = new prompts.PromptTemplate({
5536
- template: template$1,
5537
- inputVariables: inputVariables$1,
5538
- });
5539
-
5540
5582
  /**
5541
- * Get LLM Model Based on Configuration
5583
+ * Creates a commit with the specified commit message.
5542
5584
  *
5543
- * @param fields
5544
- * @param configuration
5545
- * @returns LLM Model
5585
+ * @param message The commit message.
5586
+ * @param git The SimpleGit instance.
5587
+ * @returns A Promise that resolves to the CommitResult.
5546
5588
  */
5547
- function getLlm(provider, model, config) {
5548
- if (!model) {
5549
- throw new Error(`Invalid LLM Service: ${provider}/${model}`);
5550
- }
5551
- switch (provider) {
5552
- case 'ollama':
5553
- return new ollama.ChatOllama({
5554
- baseUrl: DEFAULT_OLLAMA_LLM_SERVICE.endpoint,
5555
- maxConcurrency: config.service.maxConcurrent,
5556
- model,
5557
- });
5558
- case 'openai':
5559
- default:
5560
- const openAiModel = new openai.ChatOpenAI({
5561
- openAIApiKey: getApiKeyForModel(config),
5562
- model,
5563
- temperature: config.service.temperature || 0.2,
5564
- });
5565
- return openAiModel;
5566
- }
5567
- }
5568
-
5569
- function getPrompt({ template, variables, fallback }) {
5570
- if (!template && !fallback)
5571
- throw new Error('Must provide either a template or a fallback');
5572
- return (template
5573
- ? new prompts.PromptTemplate({
5574
- template,
5575
- inputVariables: variables,
5576
- })
5577
- : fallback);
5589
+ async function createCommit(message, git) {
5590
+ return await git.commit(message);
5578
5591
  }
5579
5592
 
5580
5593
  /**
@@ -5706,34 +5719,39 @@ async function getChanges({ git, options }) {
5706
5719
  };
5707
5720
  }
5708
5721
 
5709
- async function noResult({ git, logger }) {
5710
- const { staged, unstaged, untracked } = await getChanges({ git });
5711
- const hasStaged = staged && staged.length > 0;
5712
- const hasUnstaged = unstaged && unstaged.length > 0;
5713
- const hasUntracked = untracked && untracked.length > 0;
5714
- if (hasStaged) {
5715
- logger.log(`Staged files detected, but no summary generated...`, { color: 'red' });
5716
- logger.log(`Files are likely either:\n • changed files are ignored\n • file diff is too large.`, { color: 'yellow' });
5717
- }
5718
- else if (hasUnstaged || hasUntracked) {
5719
- logger.log('Forget something? No staged changes found... 👻', { color: 'red' });
5720
- if (hasUnstaged) {
5721
- logger.log('\nChanges not staged for commit:', { color: 'yellow' });
5722
- logger.verbose(`\t${unstaged.map(({ summary }) => summary).join('\n\t')}`, {
5723
- color: 'red',
5724
- });
5725
- }
5726
- if (hasUntracked) {
5727
- logger.log('\nUntracked changes:', { color: 'yellow' });
5728
- logger.verbose(`\t${untracked.map(({ summary }) => summary).join('\n\t')}`, {
5729
- color: 'red',
5730
- });
5731
- }
5722
+ /**
5723
+ * Retrieves the SimpleGit instance for the repository.
5724
+ * @returns {SimpleGit} The SimpleGit instance.
5725
+ */
5726
+ const getRepo = () => {
5727
+ let git;
5728
+ try {
5729
+ git = simpleGit.simpleGit();
5732
5730
  }
5733
- else {
5734
- logger.log('No repo changes detected. 👀', { color: 'blue' });
5731
+ catch (e) {
5732
+ console.log('Error initializing git repo', e);
5733
+ process.exit(1);
5735
5734
  }
5736
- }
5735
+ return git;
5736
+ };
5737
+
5738
+ const template$1 = `Write informative git commit message, in the imperative, based on the diffs & file changes provided in the "Diff Summary" section.
5739
+ Commit Messages must have a short description that is less than 50 characters and a longer detailed summary no more than 300 characters, the shorter and more concise the better. Please follow the guidelines below when writing your commit message:
5740
+
5741
+ - Write concisely using an informal tone
5742
+ - DO NOT use phrases like "this commit", "this change", "this function", etc. Instead refer to the function, variable, or class by name
5743
+ - DO NOT use specific names or files from the code
5744
+ - DO NOT include any diffs or file changes in the commit message
5745
+ - Wrap variable, class, function, components, and dependency names in back ticks e.g. \`variable\`
5746
+
5747
+ {format_instructions}
5748
+
5749
+ """{summary}"""`;
5750
+ const inputVariables$1 = ['summary', 'format_instructions'];
5751
+ const COMMIT_PROMPT = new prompts.PromptTemplate({
5752
+ template: template$1,
5753
+ inputVariables: inputVariables$1,
5754
+ });
5737
5755
 
5738
5756
  /**
5739
5757
  * Verify template string contains all required input variables
@@ -5901,26 +5919,6 @@ async function generateAndReviewLoop({ label, factory, parser, noResult, agent,
5901
5919
  return result;
5902
5920
  }
5903
5921
 
5904
- const executeChain = async ({ llm, prompt, variables, parser, }) => {
5905
- if (!llm || !prompt || !variables) {
5906
- throw new Error('The input parameters "llm", "prompt", and "variables" are all required.');
5907
- }
5908
- const chain = prompt.pipe(llm).pipe(parser);
5909
- let res;
5910
- try {
5911
- res = await chain.invoke(variables);
5912
- }
5913
- catch (error) {
5914
- if (error instanceof Error) {
5915
- throw new Error(`LLMChain call error: ${error.message}`);
5916
- }
5917
- }
5918
- if (!res) {
5919
- throw new Error('Empty response from LLMChain call');
5920
- }
5921
- return res;
5922
- };
5923
-
5924
5922
  const logSuccess = () => {
5925
5923
  console.log(chalk.green(chalk.bold('\nAll set! 🦾🤖')));
5926
5924
  };
@@ -5944,22 +5942,6 @@ async function handleResult({ result, mode, interactiveHandler }) {
5944
5942
  process.exit(0);
5945
5943
  }
5946
5944
 
5947
- /**
5948
- * Retrieves the SimpleGit instance for the repository.
5949
- * @returns {SimpleGit} The SimpleGit instance.
5950
- */
5951
- const getRepo = () => {
5952
- let git;
5953
- try {
5954
- git = simpleGit.simpleGit();
5955
- }
5956
- catch (e) {
5957
- console.log('Error initializing git repo', e);
5958
- process.exit(1);
5959
- }
5960
- return git;
5961
- };
5962
-
5963
5945
  /**
5964
5946
  * Retrieves a TikToken for the specified model.
5965
5947
  *
@@ -5982,15 +5964,33 @@ const getTokenCounter = async (modelName) => {
5982
5964
  });
5983
5965
  };
5984
5966
 
5985
- /**
5986
- * Creates a commit with the specified commit message.
5987
- *
5988
- * @param message The commit message.
5989
- * @param git The SimpleGit instance.
5990
- * @returns A Promise that resolves to the CommitResult.
5991
- */
5992
- async function createCommit(message, git) {
5993
- return await git.commit(message);
5967
+ async function noResult({ git, logger }) {
5968
+ const { staged, unstaged, untracked } = await getChanges({ git });
5969
+ const hasStaged = staged && staged.length > 0;
5970
+ const hasUnstaged = unstaged && unstaged.length > 0;
5971
+ const hasUntracked = untracked && untracked.length > 0;
5972
+ if (hasStaged) {
5973
+ logger.log(`Staged files detected, but no summary generated...`, { color: 'red' });
5974
+ logger.log(`Files are likely either:\n • changed files are ignored\n • file diff is too large.`, { color: 'yellow' });
5975
+ }
5976
+ else if (hasUnstaged || hasUntracked) {
5977
+ logger.log('Forget something? No staged changes found... 👻', { color: 'red' });
5978
+ if (hasUnstaged) {
5979
+ logger.log('\nChanges not staged for commit:', { color: 'yellow' });
5980
+ logger.verbose(`\t${unstaged.map(({ summary }) => summary).join('\n\t')}`, {
5981
+ color: 'red',
5982
+ });
5983
+ }
5984
+ if (hasUntracked) {
5985
+ logger.log('\nUntracked changes:', { color: 'yellow' });
5986
+ logger.verbose(`\t${untracked.map(({ summary }) => summary).join('\n\t')}`, {
5987
+ color: 'red',
5988
+ });
5989
+ }
5990
+ }
5991
+ else {
5992
+ logger.log('No repo changes detected. 👀', { color: 'blue' });
5993
+ }
5994
5994
  }
5995
5995
 
5996
5996
  const handler$2 = async (argv, logger) => {
@@ -6138,7 +6138,7 @@ async function getCommitLogRange(from, to, { noMerges, git }) {
6138
6138
  try {
6139
6139
  const logOptions = { from: `${from}^1`, to, '--no-merges': noMerges };
6140
6140
  const commitLog = await git.log(logOptions);
6141
- return commitLog.all.map(({ message, date, body, author_name, hash, author_email }) => `[${date}] ${message}\n${body}\n - ${author_name}<${author_email}> (${hash})`);
6141
+ return commitLog.all.map(({ message, date, body, author_name, hash, author_email }) => `[${date}] ${message}\n${body}\n(${hash}) - ${author_name}<${author_email}>`);
6142
6142
  }
6143
6143
  catch (error) {
6144
6144
  // If there's an error, handle it appropriately
@@ -6211,8 +6211,8 @@ async function getCommitLogCurrentBranch({ git, logger, comparisonBranch = 'main
6211
6211
 
6212
6212
  const template = `Write informative git changelog, in the imperative, based on a series of individual messages.
6213
6213
 
6214
- - Typically a hyphen or asterisk is used for the bullet
6215
- - Summarize dependency updates
6214
+ - Include the git commit hash as reference for each change, including just the first 7 characters
6215
+ - Logically group changes, and if necessary, summarize dependency updates
6216
6216
 
6217
6217
  {format_instructions}
6218
6218
 
@@ -6257,8 +6257,8 @@ const handler$1 = async (argv, logger) => {
6257
6257
  };
6258
6258
  }
6259
6259
  async function parser({ branch, commits }) {
6260
- console.log({ branch, commits });
6261
- const result = `## ${branch}\n\n${commits.map((commit) => `- ${commit}`).join('\n')}`;
6260
+ const result = `## ${branch}\n\n${commits.map((commit) => `${commit}`).join('\n\n\n')}`;
6261
+ console.log({ result });
6262
6262
  return result;
6263
6263
  }
6264
6264
  const changelogMsg = await generateAndReviewLoop({
@@ -6272,7 +6272,7 @@ const handler$1 = async (argv, logger) => {
6272
6272
  variables: CHANGELOG_PROMPT.inputVariables,
6273
6273
  fallback: CHANGELOG_PROMPT,
6274
6274
  });
6275
- const formatInstructions = "Respond with a valid JSON object, containing two fields: 'header' and 'content'.";
6275
+ const formatInstructions = "Respond with a valid JSON object, containing two fields: 'header' and 'content', both strings.";
6276
6276
  const changelog = await executeChain({
6277
6277
  llm,
6278
6278
  prompt,
@@ -6282,7 +6282,6 @@ const handler$1 = async (argv, logger) => {
6282
6282
  },
6283
6283
  parser,
6284
6284
  });
6285
- console.log({ changelog });
6286
6285
  return `${changelog.header}\n\n${changelog.content}`;
6287
6286
  },
6288
6287
  noResult: async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-coco",
3
- "version": "0.11.0",
3
+ "version": "0.11.1",
4
4
  "description": "zero-effort git commits with coco.",
5
5
  "author": "gfargo <ghfargo@gmail.com>",
6
6
  "license": "MIT",
@@ -54,7 +54,7 @@
54
54
  "@types/ini": "^1.3.31",
55
55
  "@types/inquirer": "^9.0.3",
56
56
  "@types/jest": "^29.5.10",
57
- "@types/node": "^20.14.4",
57
+ "@types/node": "^22.7.5",
58
58
  "@types/yargs": "^17.0.32",
59
59
  "@typescript-eslint/eslint-plugin": "^7.13.1",
60
60
  "@typescript-eslint/parser": "^7.13.1",
@@ -63,7 +63,7 @@
63
63
  "jest": "^29.7.0",
64
64
  "jest-mock": "^29.5.0",
65
65
  "release-it": "^17.0.0",
66
- "rimraf": "^5.0.1",
66
+ "rimraf": "^6.0.1",
67
67
  "rollup": "^3.26.1",
68
68
  "rollup-plugin-banner2": "^1.2.2",
69
69
  "rollup-plugin-bin": "^1.0.0",
@@ -83,10 +83,10 @@
83
83
  "dependencies": {
84
84
  "@inquirer/prompts": "3.3.0",
85
85
  "@jridgewell/sourcemap-codec": "^1.4.15",
86
- "@langchain/community": "^0.3.2",
87
- "@langchain/core": "^0.3.3",
86
+ "@langchain/community": "^0.3.4",
87
+ "@langchain/core": "^0.3.7",
88
88
  "@langchain/ollama": "^0.1.0",
89
- "@langchain/openai": "^0.3.0",
89
+ "@langchain/openai": "^0.3.5",
90
90
  "ajv": "^8.16.0",
91
91
  "ajv-formats": "^3.0.1",
92
92
  "chalk": "4.1.2",
@@ -98,7 +98,7 @@
98
98
  "performance-now": "2.1.0",
99
99
  "pretty-ms": "7.0.1",
100
100
  "simple-git": "3.25.0",
101
- "tiktoken": "^1.0.15",
101
+ "tiktoken": "^1.0.17",
102
102
  "yargs": "17.7.2"
103
103
  }
104
104
  }