git-ai-helper 1.0.0
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/index.js +73 -0
- package/package.json +21 -0
- package/src/aiService.js +20 -0
- package/src/cliHelper.js +18 -0
- package/src/gitManager.js +39 -0
package/index.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
require('dotenv').config();
|
|
3
|
+
const git = require('./src/gitManager');
|
|
4
|
+
const ai = require('./src/aiService');
|
|
5
|
+
const cli = require('./src/cliHelper');
|
|
6
|
+
|
|
7
|
+
async function main() {
|
|
8
|
+
await git.ensureRoot();
|
|
9
|
+
|
|
10
|
+
console.log("Staging changes...");
|
|
11
|
+
await git.stageAll();
|
|
12
|
+
|
|
13
|
+
const status = await git.getStatus();
|
|
14
|
+
if (status.files.length === 0) {
|
|
15
|
+
console.log("No changes detected.");
|
|
16
|
+
cli.close();
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
console.log("Syncing branches...");
|
|
21
|
+
await git.fetch();
|
|
22
|
+
const { unique, current } = await git.getBranches();
|
|
23
|
+
|
|
24
|
+
console.log("\n Branches:", unique.join(', '));
|
|
25
|
+
const target = await cli.ask(`Push to branch? (Default: ${current}): `) || current;
|
|
26
|
+
|
|
27
|
+
for (const file of status.files) {
|
|
28
|
+
const { path: filePath, index } = file;
|
|
29
|
+
|
|
30
|
+
if (index === 'D') {
|
|
31
|
+
await git.commit(`file deleted: ${filePath}`, filePath);
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const isNew = index === 'A';
|
|
36
|
+
const diffData = await git.getDiff(filePath, isNew);
|
|
37
|
+
const instruction = isNew ? "New file created. Describe it." : "File modified. Summarize it.";
|
|
38
|
+
|
|
39
|
+
let finalizedMessage = "";
|
|
40
|
+
let approved = false;
|
|
41
|
+
|
|
42
|
+
while (!approved) {
|
|
43
|
+
console.log(`\n Analyzing: ${filePath}...`);
|
|
44
|
+
const aiMsg = await ai.getAICommitMessage(diffData, instruction);
|
|
45
|
+
console.log(`Suggestion: "${aiMsg}"`);
|
|
46
|
+
|
|
47
|
+
const ans = (await cli.ask("Accept? (y/n): ")).toLowerCase();
|
|
48
|
+
if (ans === 'y') {
|
|
49
|
+
finalizedMessage = aiMsg;
|
|
50
|
+
approved = true;
|
|
51
|
+
} else {
|
|
52
|
+
const choice = (await cli.ask("[r]egenerate or [m]anual? ")).toLowerCase();
|
|
53
|
+
if (choice === 'm') {
|
|
54
|
+
finalizedMessage = await cli.ask("Enter message: ");
|
|
55
|
+
approved = true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
await git.commit(finalizedMessage, filePath);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
console.log(`Pushing to origin/${target}...`);
|
|
63
|
+
try {
|
|
64
|
+
await git.push(current, target);
|
|
65
|
+
console.log("Success!");
|
|
66
|
+
} catch (e) {
|
|
67
|
+
console.error("Push failed.");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
cli.close();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "git-ai-helper",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"gitify": "./index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
|
+
},
|
|
12
|
+
"keywords": ["git", "ai", "gemini", "automation", "cli", "commit-messages"],
|
|
13
|
+
"author": "Vandana",
|
|
14
|
+
"license": "ISC",
|
|
15
|
+
"type": "commonjs",
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"axios": "^1.14.0",
|
|
18
|
+
"dotenv": "^17.4.0",
|
|
19
|
+
"simple-git": "^3.33.0"
|
|
20
|
+
}
|
|
21
|
+
}
|
package/src/aiService.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
|
|
3
|
+
const SERVER_URL = 'https://gitify-ai.onrender.com/generate-commit';
|
|
4
|
+
|
|
5
|
+
async function getAICommitMessage(diff, instruction) {
|
|
6
|
+
try {
|
|
7
|
+
const response = await axios.post(SERVER_URL, {
|
|
8
|
+
diff,
|
|
9
|
+
instruction
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
return response.data.commitMessage;
|
|
13
|
+
|
|
14
|
+
} catch (err) {
|
|
15
|
+
console.error("Gitify Server Error:", err.response?.data?.error || err.message);
|
|
16
|
+
return "Manual commit message required (Server unreachable)";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
module.exports = { getAICommitMessage };
|
package/src/cliHelper.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const readline = require('node:readline/promises');
|
|
2
|
+
const { stdin: input, stdout: output } = require('node:process');
|
|
3
|
+
|
|
4
|
+
class CLI {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.rl = readline.createInterface({ input, output });
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async ask(question) {
|
|
10
|
+
return await this.rl.question(question);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
close() {
|
|
14
|
+
this.rl.close();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = new CLI();
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const { simpleGit } = require('simple-git');
|
|
2
|
+
const git = simpleGit();
|
|
3
|
+
|
|
4
|
+
const gitManager = {
|
|
5
|
+
ensureRoot: async () => {
|
|
6
|
+
try {
|
|
7
|
+
const root = await git.revparse(['--show-toplevel']);
|
|
8
|
+
git.cwd(root);
|
|
9
|
+
} catch (err) {
|
|
10
|
+
console.error("Not a git repository.");
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
stageAll: () => git.add('.'),
|
|
16
|
+
|
|
17
|
+
getStatus: () => git.status(),
|
|
18
|
+
|
|
19
|
+
fetch: () => git.fetch(),
|
|
20
|
+
|
|
21
|
+
getBranches: async () => {
|
|
22
|
+
const branchInfo = await git.branch(['-a']);
|
|
23
|
+
const allNames = branchInfo.all.map(n => n.replace('remotes/origin/', ''));
|
|
24
|
+
return {
|
|
25
|
+
unique: [...new Set(allNames)],
|
|
26
|
+
current: branchInfo.current
|
|
27
|
+
};
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
getDiff: (filePath, isNew) => {
|
|
31
|
+
return isNew ? git.show([`:${filePath}`]) : git.diff(['--staged', filePath]);
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
commit: (msg, file) => git.commit(msg, file),
|
|
35
|
+
|
|
36
|
+
push: (local, remote) => git.push('origin', `${local}:${remote}`)
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
module.exports = gitManager;
|