-
-
Notifications
You must be signed in to change notification settings - Fork 5
🚀 UPDATE: v0.2.7 #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
🚀 UPDATE: v0.2.7 #21
Changes from all commits
d841961
f6019c3
52bc934
3ec5f01
f561c84
30c8ab0
0bd8d93
ac7dcec
e1e9bbb
d8be1e8
085714f
efdb11e
0868f52
c3fc47a
c133e68
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,48 +1,7 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import React from 'react'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import {Text, Newline} from 'ink'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import BigText from 'ink-big-text'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import Gradient from 'ink-gradient'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import isGit from 'is-git-repository'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import isCommitterSet from './utils/errors.js'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import info from './utils/info.js'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import askForCommitMessage from './utils/commit.js'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { getOpenAIKey, setOpenAIKey, deleteOPenAIKey } from './utils/api.js'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import Logo from './utils/logo.js'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export default function App({flags}) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(flags.setopenai) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setOpenAIKey(flags.setopenai); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(flags.delopenai) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| deleteOPenAIKey(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!getOpenAIKey()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log('Please provide an OpenAI API key.'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log('You can get one from https://platform.openai.com/account/api-keys') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log('Run `magicc --setopenai=<api-key>` to save your API key and try again.'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log('You have an OpenAI API key, you can now generate a commit message.'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const gitCheck = isGit(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const committerCheck = isCommitterSet(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (gitCheck && committerCheck) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| askForCommitMessage(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log('This is not a git repository.'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Gradient name='passion'> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <BigText text='Magicc' /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Text>You can do `magicc`, you can build anything that you desire. 🪄</Text> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Gradient> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Text> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Version: <Text color='green'>{info('version')}</Text> | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Author: <Text color='blue'>{info('author')}</Text><Newline/> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Text> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Need Help? <Text color="cyan">magicc --help</Text> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Text><Newline/> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ================================================== | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Text> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return <Logo flags={flags} />; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
1
to
7
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prop naming inconsistency with Logo component The simplification looks good, but there's a naming issue. The Consider updating the Logo component to use a more appropriate parameter name: -export default function Logo(children) {
+export default function Logo(props) {
return (
<>
...
- <ModelSelection {...children} />
+ <ModelSelection {...props} />
</>
);
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,36 @@ | ||||||||||||||||||||||||
| import Ollama from 'ollama'; // Import the Ollama model | ||||||||||||||||||||||||
| import config from '../utils/config.json'; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| async function ollamaModel(model, flags, diffContent) { | ||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||
| // Use the prompt from the config file emoji and send to Ollama | ||||||||||||||||||||||||
| const categoryResponse = await Ollama.chat({ | ||||||||||||||||||||||||
| messages: [ | ||||||||||||||||||||||||
| {role: 'system', content: config.commitConfig.emoji}, | ||||||||||||||||||||||||
| {role: 'user', content: diffContent}, | ||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||
| model, | ||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||
| // Use the prompt from the config file message and send to Ollama | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| const messageResponse = await Ollama.chat({ | ||||||||||||||||||||||||
| messages: [ | ||||||||||||||||||||||||
| {role: 'system', content: config.commitConfig.message}, | ||||||||||||||||||||||||
| {role: 'user', content: diffContent}, | ||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||
| model, | ||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||
| console.log('categoryResponse', categoryResponse); | ||||||||||||||||||||||||
| console.log('messageResponse', messageResponse); | ||||||||||||||||||||||||
|
Comment on lines
+23
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Remove debug console.log statements Debug logging should be removed or replaced with proper logging mechanism if needed. - console.log('categoryResponse', categoryResponse);
- console.log('messageResponse', messageResponse);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||
| category: categoryResponse?.message?.content, | ||||||||||||||||||||||||
| message: messageResponse?.message?.content, | ||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||
| throw new Error( | ||||||||||||||||||||||||
| 'Failed to connect to local Ollama instance. To start Ollama, first download it at https://ollama.ai.', | ||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
Comment on lines
+29
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Preserve original error for better debugging The generic error message loses valuable debugging information from the original error. } catch (error) {
+ console.error('Ollama API error:', error);
throw new Error(
- 'Failed to connect to local Ollama instance. To start Ollama, first download it at https://ollama.ai.',
+ `Failed to connect to local Ollama instance: ${error.message}. To start Ollama, first download it at https://ollama.ai.`,
);
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| export default ollamaModel; | ||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,54 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import OpenAI from 'openai'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import config from '../utils/config.json'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import dotenv from 'dotenv'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import {getOpenAIKey, setOpenAIKey, deleteOPenAIKey} from '../utils/api.js'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| dotenv.config(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async function openAiModel(model, flags, diffContent) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (flags.setopenai) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setOpenAIKey(flags.setopenai); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (flags.delopenai) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| deleteOPenAIKey(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+10
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion API key management should be handled separately Setting and deleting API keys within the model function violates single responsibility principle. This should be handled at a higher level (e.g., in the CLI or UI layer). Consider moving API key management to the appropriate layer and keeping this function focused solely on generating commit messages. 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!getOpenAIKey()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'Please provide an OpenAI API key.\n' + | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'You can get one from https://platform.openai.com/account/api-keys\n' + | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'Run `magicc --setopenai=<api-key>` to save your API key and try again.', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'You have an OpenAI API key, you can now generate a commit message.', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const apiKey = await getOpenAIKey(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const openai = new OpenAI({apiKey: apiKey}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const category = await openai.chat.completions.create({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| messages: [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {role: 'system', content: config.commitConfig.emoji}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {role: 'user', content: diffContent}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| model, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // use the prmopt from the config file message and send to openai | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const message = await openai.chat.completions.create({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| messages: [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {role: 'system', content: config.commitConfig.message}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {role: 'user', content: diffContent}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| model, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| category: category.choices[0].message.content, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: message.choices[0].message.content, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+31
to
+50
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add error handling for API calls The OpenAI API calls lack error handling, which could cause unhandled exceptions. + try {
const category = await openai.chat.completions.create({
messages: [
{role: 'system', content: config.commitConfig.emoji},
{role: 'user', content: diffContent},
],
model,
});
// use the prompt from the config file message and send to openai
const message = await openai.chat.completions.create({
messages: [
{role: 'system', content: config.commitConfig.message},
{role: 'user', content: diffContent},
],
model,
});
return {
category: category.choices[0].message.content,
message: message.choices[0].message.content,
};
+ } catch (error) {
+ console.error('OpenAI API error:', error);
+ throw new Error(`Failed to generate commit message: ${error.message}`);
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export default openAiModel; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,13 @@ | ||
| import generatePrompt from './openai.js'; | ||
| import generateCommitMessage from './generateCommitMessage.js'; | ||
| import {execa} from 'execa'; | ||
| import readline from 'readline'; | ||
| import React from 'react'; | ||
| import {Box, render, Text, useApp} from 'ink'; | ||
| import SelectInput from 'ink-select-input'; | ||
| import Logo from './logo.js'; | ||
|
|
||
| async function askForCommitMessage() { | ||
| const prompt = await generatePrompt(); | ||
| async function askForCommitMessage(flags, model) { | ||
| const prompt = await generateCommitMessage(flags, model); | ||
|
|
||
| const rl = readline.createInterface({ | ||
| input: process.stdin, | ||
|
|
@@ -24,10 +25,10 @@ async function askForCommitMessage() { | |
| .catch(error => { | ||
| console.error('Failed to commit changes:', error); | ||
| }); | ||
| } | ||
| else { | ||
| } else { | ||
| console.log('Changes not committed.'); | ||
| } | ||
| rl.close(); | ||
| exit(); | ||
| }; | ||
|
|
||
|
|
@@ -43,13 +44,14 @@ async function askForCommitMessage() { | |
| ]; | ||
|
|
||
| return ( | ||
| <Box flexDirection="column"> | ||
| <Text>{`Suggested commit message: ${prompt}\nDo you want to proceed?`}</Text> | ||
| <SelectInput items={items} onSelect={handleSelect} /> | ||
| </Box> | ||
| <Logo> | ||
| <Box flexDirection="column"> | ||
| <Text>{`Suggested commit message: ${prompt}\nDo you want to proceed?`}</Text> | ||
| <SelectInput items={items} onSelect={handleSelect} /> | ||
| </Box> | ||
| </Logo> | ||
| ); | ||
| }; | ||
|
|
||
| if (prompt) { | ||
| render(<SelectSuggestedCommit />); | ||
| } else { | ||
|
|
@@ -58,4 +60,54 @@ async function askForCommitMessage() { | |
| } | ||
| } | ||
|
|
||
| export async function initGit() { | ||
| try { | ||
| await execa('git', ['restore', '--staged', '.']); | ||
| } catch (error) { | ||
| console.error(error); | ||
| } | ||
|
Comment on lines
+65
to
+68
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Improve error handling in git functions Errors are caught and logged but not re-thrown, making it difficult for callers to handle failures properly. } catch (error) {
- console.error(error);
+ console.error('Git operation failed:', error);
+ throw error;
}Apply this pattern to all three functions: Also applies to: 97-99, 107-109 🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| // git status to see if there are any changes | ||
| // if there's any changes add the first file in the list of changes | ||
| let firstFilePath = ''; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Avoid module-level mutable state Using a module-level variable Consider returning the first file path from 🤖 Prompt for AI Agents |
||
|
|
||
| export async function gitStatus() { | ||
| try { | ||
| const {stdout: status} = await execa('git', ['status', '--porcelain']); | ||
| if (status) { | ||
| // get the first file path in the list of changes | ||
| const lines = status.split('\n'); | ||
| const filePaths = lines | ||
| .map(line => line.split(' ').slice(2).join(' ').trim()) | ||
| .filter(filePath => filePath !== '') | ||
| .concat( | ||
| lines | ||
| .filter(line => line.startsWith('??')) | ||
| .map(line => line.split(' ').slice(1).join(' ').trim()), | ||
| ); | ||
|
Comment on lines
+81
to
+88
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainComplex file path parsing logic The file path parsing logic is complex and might not handle all git status formats correctly (e.g., renamed files, files with spaces). Consider using a more robust git parsing library or simplifying the logic. Also, verify that this handles all git status codes correctly: 🏁 Script executed: #!/bin/bash
# Test various git status formats
echo "Testing git status parsing with different file states..."
# Create test files with various states
touch "test file with spaces.txt"
git add "test file with spaces.txt"
git status --porcelain | head -5
# Show git status format documentation
echo -e "\nGit status format reference:"
git status --porcelain | head -5
echo "First two characters indicate: XY where X=index, Y=worktree"Length of output: 558 Refine git status parsing to handle spaces and renames The current logic in source/utils/commit.js (lines 81–88) splits each status line on spaces and then slices/join—this:
To fix this, replace the ad-hoc splitting with one of the following: • Use • Or leverage a well-tested library (e.g. simple-git, nodegit) to parse porcelain output instead of manual string operations. Making this change will ensure all status codes (A, M, D, R, C, ??, etc.) and file names with arbitrary characters are parsed reliably. 🤖 Prompt for AI Agents |
||
| // git add the first file in the list of changes | ||
| firstFilePath = filePaths[0]; | ||
| await execa('git', ['add', firstFilePath]); | ||
| console.log(`${firstFilePath} has been added to the staging area.`); | ||
| } else { | ||
| console.log('No changes to commit.'); | ||
| return false; | ||
| } | ||
| } catch (error) { | ||
| console.error(error); | ||
| } | ||
| } | ||
|
|
||
| // get the diff of the staged changes | ||
| export async function gitDiff() { | ||
| try { | ||
| const {stdout: gitDiff} = await execa('git', ['diff', '--staged']); | ||
| return gitDiff; | ||
| } catch (error) { | ||
| console.error(error); | ||
| } | ||
| } | ||
|
|
||
|
|
||
| export default askForCommitMessage; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,22 @@ | ||
| { | ||
| "emoji": "YYou are the author of the commit message. Your task is to select the appropriate category for the git diff based on the changes. Use the following categories (emoji category name => usage): 📦 new => for new files or new features; ✨ tweak => for enhancements or updates to the codebase; ☕ chore => for updates or changes outside the project codebase, including README.md; 🐞 fix => for fixing code bugs and errors. Please reply with the category name only.", | ||
| "message": "You are the author of the changes, you are going to provide a professional git commit message that is no longer than 25 characters in imperative present tense. Stricly no emojis are allowed and no conventional commit message as prefix is already provided. For example, instead of 'fix: fix a bug' make it 'fix a bug'. The message should be in lower case and no period at the end.", | ||
| "default_model": "gpt-4o-mini", | ||
| "maxDiffSize": 4000 | ||
| "commitConfig": { | ||
| "emoji": "You are the author of the commit message. Your task is to select the appropriate category for the git diff based on the changes. Use the following categories (emoji category name => usage): 📦 new => for new files or new features; ✨ tweak => for enhancements or updates to the codebase; ☕ chore => for updates or changes outside the project codebase, including README.md; 🐞 fix => for fixing code bugs and errors. Please reply with the category name only.", | ||
| "message": "You are the author of the changes, and you will provide a professional git commit message that is no longer than 25 characters in imperative present tense. Strictly no emojis are allowed, and no conventional commit message prefix is provided. For example, instead of 'fix: fix a bug,' make it 'fix a bug.' The message should be in lowercase and should not have a period at the end." | ||
| }, | ||
|
|
||
| "models": [ | ||
| { | ||
| "title": "GPT-4o Mini", | ||
| "provider": "openai", | ||
| "model": "gpt-4o-mini", | ||
| "maxDiffSize": 4000, | ||
| "apiKey": "" | ||
| }, | ||
| { | ||
| "title": "Llama 3.1 8B", | ||
| "provider": "ollama", | ||
| "model": "llama3.1:8b", | ||
| "maxDiffSize": 4000 | ||
| } | ||
| ] | ||
|
Comment on lines
+9
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainValidate model configuration completeness. The OpenAI model has an empty 🏁 Script executed: #!/bin/bash
# Check if there are any references to apiKey validation in the codebase
rg -A 3 -B 3 "apiKey" --type jsLength of output: 954 🏁 Script executed: #!/bin/bash
# Inspect OpenAI model integration
sed -n '1,200p' source/models/openai.js
echo "-----"
# Inspect API key utility functions
sed -n '1,200p' source/utils/api.jsLength of output: 2663 Clarify and resolve unused Your code already handles OpenAI key presence and validity via the
🤖 Prompt for AI Agents |
||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,61 @@ | ||||||||||||||||||||||||||||||
| import openAiModel from '../models/openai.js'; | ||||||||||||||||||||||||||||||
| import ollamaModel from '../models/ollama.js'; | ||||||||||||||||||||||||||||||
| import config from './config.json'; | ||||||||||||||||||||||||||||||
| import {gitDiff, gitStatus, initGit} from './commit.js'; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| // remove any staged changes in git | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| async function generateCommitMessage(flags, model) { | ||||||||||||||||||||||||||||||
| const maxDiffSize = config.maxDiffSize; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| await initGit(); | ||||||||||||||||||||||||||||||
| const status = await gitStatus(); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const gitDiffContent = await gitDiff(); | ||||||||||||||||||||||||||||||
| const {category, message} = await getModelResponse( | ||||||||||||||||||||||||||||||
| model, | ||||||||||||||||||||||||||||||
| flags, | ||||||||||||||||||||||||||||||
| gitDiffContent, | ||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (gitDiffContent.length > maxDiffSize) { | ||||||||||||||||||||||||||||||
| console.log('Diff content is too large. Skipping OpenAI request.'); | ||||||||||||||||||||||||||||||
| return `✨ tweak (${firstFilePath}): update ${firstFilePath}`; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
Comment on lines
+8
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical: Diff size check happens after API calls The diff size validation occurs after making expensive API calls, which wastes resources and time. Also, async function generateCommitMessage(flags, model) {
- const maxDiffSize = config.maxDiffSize;
+ // Get model-specific configuration
+ const modelConfig = config.models.find(m => m.name === model);
+ const maxDiffSize = modelConfig ? modelConfig.maxDiffSize : config.maxDiffSize;
await initGit();
const status = await gitStatus();
+
+ if (!status) {
+ return false;
+ }
const gitDiffContent = await gitDiff();
+
+ // Check diff size before making API calls
+ if (gitDiffContent.length > maxDiffSize) {
+ console.log(`Diff content is too large for ${model}. Skipping AI request.`);
+ const firstFilePath = await getFirstFilePath(); // Need to import or access this properly
+ return `✨ tweak (${firstFilePath}): update ${firstFilePath}`;
+ }
+
const {category, message} = await getModelResponse(
model,
flags,
gitDiffContent,
);
- if (gitDiffContent.length > maxDiffSize) {
- console.log('Diff content is too large. Skipping OpenAI request.');
- return `✨ tweak (${firstFilePath}): update ${firstFilePath}`;
- }
-
- if (status !== false) {
+ const firstFilePath = await getFirstFilePath(); // Need to import or access this properly
+ if (category && message) {
return `${category} (${firstFilePath}): ${message}`;
} else {
return false;
}Also need to import or properly access
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (status !== false) { | ||||||||||||||||||||||||||||||
| return `${category} (${firstFilePath}): ${message}`; | ||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| async function getModelResponse(model, flags, gitDiffContent) { | ||||||||||||||||||||||||||||||
| let response; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||
| switch (model) { | ||||||||||||||||||||||||||||||
| case 'gpt-4o-mini': | ||||||||||||||||||||||||||||||
| response = await openAiModel(model, flags, gitDiffContent); | ||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||
| case 'llama3.1:8b': | ||||||||||||||||||||||||||||||
| response = await ollamaModel(model, flags, gitDiffContent); | ||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||
| default: | ||||||||||||||||||||||||||||||
| throw new Error('Unsupported model selected'); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| console.log('response', response); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (response && response.category && response.message) { | ||||||||||||||||||||||||||||||
| // Destructure and return the required fields | ||||||||||||||||||||||||||||||
| const {category, message} = response; | ||||||||||||||||||||||||||||||
| return {category, message}; | ||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||
| throw new Error(response.message); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
Comment on lines
+49
to
+55
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use optional chaining and fix error handling The static analysis correctly suggests using optional chaining. Also, the error throwing logic is flawed - it throws - if (response && response.category && response.message) {
+ if (response?.category && response?.message) {
// Destructure and return the required fields
const {category, message} = response;
return {category, message};
} else {
- throw new Error(response.message);
+ throw new Error('Invalid response from AI model: missing category or message');
}📝 Committable suggestion
Suggested change
🧰 Tools🪛 Biome (1.9.4)[error] 49-49: Change to an optional chain. Unsafe fix: Change to an optional chain. (lint/complexity/useOptionalChain) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||
| console.log(error.message); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
Comment on lines
+56
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Error is caught but not re-thrown Catching and logging errors without re-throwing them causes silent failures. The caller won't know that an error occurred. } catch (error) {
- console.log(error.message);
+ console.error('Model response error:', error.message);
+ throw error;
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| export default generateCommitMessage; | ||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Verify Ollama dependency version and security.
The new Ollama dependency supports the AI model integration. Please ensure this version is stable and free from known vulnerabilities.
🌐 Web query:
💡 Result:
The latest stable version of the
ollamanpm package is 0.5.16, released approximately one month ago. (security.snyk.io)Regarding version 0.5.9, there are no known security vulnerabilities associated with it. Snyk's vulnerability database indicates that version 0.5.16, which is the latest release, has no direct vulnerabilities. (security.snyk.io)
It's important to note that while version 0.5.9 does not have reported vulnerabilities, it is an older release. For the most up-to-date features and security patches, it's recommended to use the latest stable version, 0.5.16.
Citations:
Upgrade Ollama to the latest stable version
Ollama v0.5.9 has no known security vulnerabilities, but the latest stable release is v0.5.16 (also free of reported issues). To benefit from new features and security patches, please update:
package.json, line 50📝 Committable suggestion
🤖 Prompt for AI Agents