youmna-git-glance 1.1.2 β†’ 1.1.3

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.
Files changed (5) hide show
  1. package/.env +2 -0
  2. package/README.md +75 -13
  3. package/index.js +154 -38
  4. package/package.json +11 -6
  5. package/utils/ui.js +57 -0
package/.env ADDED
@@ -0,0 +1,2 @@
1
+ GEMINI_API_KEY=AIzaSyDTw2571vjI5yiotCj2QPTHkcZ8aQAka_4
2
+ GEMINI_MODEL=gemini-3-flash-preview
package/README.md CHANGED
@@ -1,24 +1,86 @@
1
- # πŸš€ Git Glance
1
+ # πŸ¦‹ youmna-git (ygit)
2
2
 
3
- A lightweight, beautiful CLI dashboard to get an instant overview of your Git repository status. Built with Node.js.
3
+ **The AI-Powered Git Assistant that makes your workflow glide.**
4
4
 
5
- [![npm version](https://img.shields.io/npm/v/youmna-git-glance.svg)](https://www.npmjs.com/package/youmna-git-glance)
5
+ [![npm version](https://img.shields.io/npm/v/youmna-git.svg)](https://www.npmjs.com/package/youmna-git)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
 
8
+ `youmna-git` is a professional-grade CLI tool that transforms your terminal into a smart dashboard. Powered by **Google Gemini 3.0**, it doesn't just show you your git statusβ€”it helps you write code, review bugs, and understand your history.
9
+
10
+ ---
11
+
8
12
  ## ✨ Features
9
- - πŸ“Š **Instant Summary:** View current branch and remote URLs.
10
- - πŸ•’ **Latest Commit:** See the most recent commit message and author.
11
- - πŸ“‚ **File Tracking:** Instantly see how many files have been modified.
12
- - 🎨 **Beautiful UI:** Clean, color-coded dashboard output.
13
+
14
+ - πŸ“Š **Smart Dashboard:** A beautiful, color-coded summary of your branch, changes, and latest commits.
15
+ - πŸ€– **Gemini AI Commit:** Instantly generate professional, one-line commit messages by analyzing your file changes.
16
+ - πŸ” **AI Code Review:** Get a senior-level review of your current diff to spot bugs before you push.
17
+ - πŸ’¬ **Repo Chat:** Ask questions like "What did I change in the last hour?" and get answers based on your git logs.
18
+ - πŸ›‘οΈ **Merge Helper:** Solve complex merge conflicts with a step-by-step AI resolution plan.
19
+ - ⚑ **Lightweight & Fast:** Built for speed, keeping your hands on the keyboard.
20
+ ---
13
21
 
14
22
  ## πŸ“¦ Installation
23
+
15
24
  Install the tool globally using npm:
16
25
 
17
26
  ```bash
18
- npm install -g youmna-git-glance
19
- ``````
27
+ npm install -g youmna-git
28
+ ----------
29
+ # πŸ¦‹ youmna-git (ygit)
20
30
 
21
- πŸš€ Usage
22
- ```bash
23
- git-glance
24
- ```
31
+ **The AI-Powered Git Assistant that makes your workflow glide.**
32
+
33
+ [![npm version](https://img.shields.io/npm/v/youmna-git.svg)](https://www.npmjs.com/package/youmna-git)
34
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
35
+
36
+ `youmna-git` is a professional-grade CLI tool that transforms your terminal into a smart dashboard. Powered by **Google Gemini 1.5 Flash**, it doesn't just show you your git statusβ€”it helps you write code, review bugs, and understand your history.
37
+
38
+ ---
39
+
40
+ ## πŸ”‘ Setup
41
+
42
+ To use the AI features (Commit, Review, Chat), you need to get a free API Key from Google:
43
+
44
+ 1. **Get your Key:** Go to [Google AI Studio](https://aistudio.google.com/) and click **"Get API key"**.
45
+ 2. **Add to Environment:** Create a file named `.env` in your project root or add it to your shell profile:
46
+ ```text
47
+ GEMINI_API_KEY=your_key_here
48
+ ```
49
+ 3. **Important:** Make sure your `.env` `.npmrc` files are added to your `.gitignore` so your key stays private!
50
+
51
+ ---
52
+
53
+ ## πŸš€ Usage
54
+ Simply type ygit to launch the main dashboard, or use specific subcommands:
55
+
56
+ AI Commands:
57
+
58
+ # Launch the interactive dashboard
59
+ ygit
60
+
61
+ # Generate an AI commit message for staged changes
62
+ ygit commit
63
+
64
+ # Analyze current code diff for bugs
65
+ ygit review
66
+
67
+ # Ask a question about your history
68
+ ygit chat "What features did I add yesterday?"
69
+
70
+ # Get help resolving active merge conflicts
71
+ ygit merge-help
72
+
73
+
74
+ 🀝 Contributing
75
+
76
+ Contributions are welcome! Please feel free to submit a Pull Request.
77
+
78
+ 1- Fork the Project
79
+
80
+ 2- Create your Feature Branch (git checkout -b feature/AmazingFeature)
81
+
82
+ 3- Commit your Changes (git commit -m 'Add some AmazingFeature')
83
+
84
+ 4- Push to the Branch (git push origin feature/AmazingFeature)
85
+
86
+ 5- Open a Pull Request
package/index.js CHANGED
@@ -1,50 +1,166 @@
1
1
  #!/usr/bin/env node
2
-
2
+ import { program } from 'commander';
3
3
  import { simpleGit } from 'simple-git';
4
- import chalk from 'chalk';
5
- import boxen from 'boxen';
6
- import ora from 'ora';
4
+ import { GoogleGenerativeAI } from '@google/generative-ai';
5
+ import 'dotenv/config';
6
+ import { primary, success, accent, error, text, createSpinner, createBox, createProgressBar, log, logError } from './utils/ui.js'; // Updated import
7
+ import fs from 'fs'; // Ensure you have this import at the top
7
8
 
8
9
  const git = simpleGit();
9
10
 
10
- async function showGitStats() {
11
- const spinner = ora('Fetching Git Info...').start();
11
+ // --- Gemini AI Setup ---
12
+ const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
13
+ const model = genAI.getGenerativeModel({
14
+ model: process.env.GEMINI_MODEL || "gemini-3-flash-preview"
15
+ });
16
+
17
+ // --- πŸ“Š THE DASHBOARD (Default) ---
18
+ async function showDashboard() {
19
+ const spinner = createSpinner('Loading Git Dashboard...').start();
20
+ try {
21
+ const isRepo = await git.checkIsRepo();
22
+ if (!isRepo) {
23
+ spinner.fail(error('Error: Not a git repository!'));
24
+ return;
25
+ }
26
+
27
+ const status = await git.status();
28
+ const logResult = await git.log({ n: 1 });
29
+ const remote = await git.getRemotes(true);
30
+ spinner.stop();
31
+
32
+ const stats = `
33
+ ${primary.bold('Branch:')} ${text(status.current)}
34
+ ${success.bold('Latest:')} ${text(logResult.latest.message)}
35
+ ${accent.bold('Author:')} ${text(logResult.latest.author_name)}
36
+ ${primary.bold('Status:')} ${text(status.files.length + ' files modified')}
37
+ ${primary.bold('Remote:')} ${text(remote[0]?.refs.fetch || 'None')}
38
+ `;
39
+
40
+ log(createBox(stats, { title: 'πŸš€ Youmna Git Dashboard (Hacker Mode)', borderColor: primary.toString() })); // Using new createBox
41
+ } catch (err) {
42
+ spinner.fail(error('Failed to load dashboard.'));
43
+ logError(err.message);
44
+ }
45
+ }
12
46
 
47
+ // --- πŸ€– AI COMMANDS ---
48
+ program.name('ygit').version('2.2.0').description('Personal AI Git Assistant powered by Gemini');
49
+
50
+ // 1. AI Commit Suggestion
51
+ program
52
+ .command('commit')
53
+ .description('Suggest a commit message using Gemini AI')
54
+ .action(async () => {
55
+ const spinner = createSpinner('AI is analyzing changes...').start();
56
+ try {
57
+ const diff = await git.diff();
58
+ if (!diff) return spinner.info(text('No changes found to describe.'));
59
+
60
+ const prompt = `Write a professional, concise one-line git commit message for these changes: ${diff.substring(0, 5000)}`;
61
+ const result = await model.generateContent(prompt);
62
+
63
+ spinner.stop();
64
+ log(createBox(success(result.response.text().trim()), { title: '✨ Gemini Suggestion', borderColor: 'green' }));
65
+ } catch (err) {
66
+ spinner.stop();
67
+ if (err.message.includes('429')) {
68
+ logError("Quota reached! Please wait 60 seconds before trying again.");
69
+ } else if (err.message.includes('404')) {
70
+ logError("Model not found. Ensure line 12 is: gemini-3-flash-preview");
71
+ } else {
72
+ logError(err.message);
73
+ }
74
+ }
75
+ });
76
+
77
+ // 2. AI Code Review
78
+ program
79
+ .command('review')
80
+ .description('Let Gemini review your code for bugs')
81
+ .action(async () => {
82
+ const spinner = createSpinner('Gemini is inspecting your code...', accent).start();
13
83
  try {
14
- const isRepo = await git.checkIsRepo();
15
- if (!isRepo) {
16
- spinner.fail(chalk.red('Error: Not a git repository!'));
17
- return;
84
+ const diff = await git.diff();
85
+ const prompt = `You are a senior reviewer. Spot bugs or messy logic in this diff. Be concise: ${diff.substring(0, 5000)}`;
86
+ const result = await model.generateContent(prompt);
87
+
88
+ spinner.stop();
89
+
90
+ log(createBox(text(result.response.text()), {
91
+ title: 'πŸ” AI Code Review',
92
+ borderColor: 'magenta'
93
+ }));
94
+ } catch (err) { spinner.fail(error('Review failed.')); logError(err.message); }
95
+ });
96
+
97
+ // 3. Repo Chat
98
+ program
99
+ .command('chat <question>')
100
+ .description('Ask a question about your git history')
101
+ .action(async (question) => {
102
+ const spinner = createSpinner('Consulting history...').start();
103
+ try {
104
+ const logs = await git.log({ n: 10 });
105
+ const prompt = `Based on these git logs: ${JSON.stringify(logs)}, answer: ${question}`;
106
+ const result = await model.generateContent(prompt);
107
+
108
+ spinner.stop();
109
+ log(`${accent('πŸ€– Gemini Assistant:')} ${text(result.response.text())}`);
110
+ } catch (err) { spinner.fail(error('Chat failed.')); logError(err.message); }
111
+ });
112
+
113
+ // 4. AI-Powered Merge Conflict Helper (FIXED)
114
+ program
115
+ .command('merge-help')
116
+ .description('Analyze and suggest resolutions for merge conflicts')
117
+ .action(async () => {
118
+ const spinner = createSpinner('Scanning for πŸ’” conflicts...').start();
119
+ try {
120
+ const status = await git.status();
121
+ const conflictedFiles = status.conflicted; // Get files that are "unmerged"
122
+
123
+ if (conflictedFiles.length === 0) {
124
+ spinner.succeed(success('No merge conflicts detected! Everything is clean.'));
125
+ return;
126
+ }
127
+
128
+ const conflictDetails = [];
129
+ for (const file of conflictedFiles) {
130
+ // We read from the disk (worktree) instead of the Git index
131
+ // This avoids the "Stage 0" error
132
+ const content = await fs.promises.readFile(file, 'utf8');
133
+ if (content.includes('<<<<<<<')) {
134
+ conflictDetails.push(`File: ${file}\n${content}`);
18
135
  }
136
+ }
137
+
138
+ if (conflictDetails.length === 0) {
139
+ spinner.fail(error('Conflicted files found, but no markers (<<<<<<<) detected.'));
140
+ return;
141
+ }
142
+
143
+ spinner.text = primary('Gemini is resolving the puzzle...');
144
+ const prompt = `You are a Git Expert. Explain the conflict and suggest a solution for:
145
+ ${conflictDetails.join('\n\n').substring(0, 8000)}`;
19
146
 
20
- const status = await git.status();
21
- const log = await git.log({ n: 1 });
22
- const remote = await git.getRemotes(true);
23
-
24
- spinner.stop();
25
-
26
-
27
- const stats = `
28
- ${chalk.cyan.bold('Branch:')} ${chalk.white(status.current)}
29
- ${chalk.green.bold('Latest:')} ${chalk.white(log.latest.message)}
30
- ${chalk.yellow.bold('Author:')} ${chalk.white(log.latest.author_name)}
31
- ${chalk.magenta.bold('Changes:')} ${chalk.white(status.files.length + ' files modified')}
32
- ${chalk.blue.bold('Remote:')} ${chalk.white(remote[0]?.refs.fetch || 'None')}
33
- `;
34
-
35
- console.log(boxen(stats, {
36
- padding: 1,
37
- margin: 1,
38
- borderStyle: 'round',
39
- title: 'Git Glance Dashboard',
40
- titleAlignment: 'center',
41
- borderColor: 'cyan'
42
- }));
43
-
44
- } catch (error) {
45
- spinner.fail(chalk.red('Something went wrong!'));
46
- console.error(error);
147
+ const result = await model.generateContent(prompt);
148
+ spinner.stop();
149
+
150
+ log(createBox(text(result.response.text()), {
151
+ title: 'πŸ›‘οΈ AI Merge Resolution',
152
+ borderColor: 'red'
153
+ }));
154
+
155
+ } catch (err) {
156
+ spinner.stop();
157
+ logError("Could not analyze conflicts: " + err.message);
47
158
  }
159
+ });
160
+
161
+ // Default behavior
162
+ if (!process.argv.slice(2).length) {
163
+ showDashboard();
48
164
  }
49
165
 
50
- showGitStats();
166
+ program.parse(process.argv);
package/package.json CHANGED
@@ -1,14 +1,19 @@
1
1
  {
2
2
  "name": "youmna-git-glance",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
+ "description": "AI-powered Git assistant using Google Gemini with advanced features πŸ¦‹",
4
5
  "type": "module",
5
6
  "bin": {
6
- "git-glance": "./index.js"
7
+ "ygit": "./index.js"
7
8
  },
8
9
  "dependencies": {
9
- "simple-git": "^3.27.0",
10
- "chalk": "^5.3.0",
10
+ "@google/generative-ai": "^0.24.1",
11
11
  "boxen": "^7.1.1",
12
- "ora": "^8.0.1"
12
+ "chalk": "^5.3.0",
13
+ "cli-progress": "^3.12.0",
14
+ "commander": "^11.1.0",
15
+ "dotenv": "^16.4.2",
16
+ "ora": "^8.0.1",
17
+ "simple-git": "^3.27.0"
13
18
  }
14
- }
19
+ }
package/utils/ui.js ADDED
@@ -0,0 +1,57 @@
1
+ // utils/ui.js
2
+ import chalk from 'chalk';
3
+ import boxen from 'boxen';
4
+ import ora from 'ora';
5
+ import cliProgress from 'cli-progress'; // New dependency for progress bar
6
+
7
+ // --- Theme Colors ---
8
+ export const primary = chalk.hex('#00FFFF'); // Electric Cyan
9
+ export const success = chalk.hex('#00FF00'); // Bright Green
10
+ export const accent = chalk.hex('#FF00FF'); // Magenta
11
+ export const warning = chalk.hex('#FFFF00'); // Yellow
12
+ export const error = chalk.hex('#FF0000'); // Red
13
+ export const text = chalk.whiteBright;
14
+
15
+ // --- CLI Components ---
16
+ // utils/ui.js
17
+ export const createSpinner = (textMsg, color = primary) => {
18
+ // Safe check for hex codes
19
+ const match = color.toString().match(/#(?:[0-9a-fA-F]{3}){1,2}/);
20
+ const spinnerColor = match ? match[0] : 'cyan';
21
+
22
+ return ora({
23
+ text: color(textMsg),
24
+ spinner: { interval: 80, frames: ['β ‹', 'β ™', 'β Ή', 'β Έ', 'β Ό', 'β ΄', 'β ¦', 'β §', 'β ‡', '⠏'] },
25
+ // Don't pass hex codes to 'ora', use 'cyan' as a fallback
26
+ color: spinnerColor.startsWith('#') ? 'cyan' : spinnerColor
27
+ });
28
+ };
29
+
30
+ export const createProgressBar = (name = "Progress", barSize = 20) => {
31
+ const bar = new cliProgress.SingleBar({
32
+ format: `${accent('{bar}')} ${text('{percentage}%')} | {value}/{total} ${primary(name)}`,
33
+ barCompleteChar: '\u2588', // Full block
34
+ barIncompleteChar: '\u2591', // Light shade
35
+ hideCursor: true,
36
+ barsize: barSize,
37
+ linewrap: false
38
+ }, cliProgress.Presets.shades_classic);
39
+ return bar;
40
+ };
41
+
42
+ export const createBox = (content, options = {}) => {
43
+ const defaultOptions = {
44
+ padding: 1,
45
+ margin: 1,
46
+ borderStyle: 'double', // Hacker Mode border
47
+ borderColor: primary.name,
48
+ titleAlignment: 'center',
49
+ ...options
50
+ };
51
+ return boxen(content, defaultOptions);
52
+ };
53
+
54
+ export const log = (message, color = text) => console.log(color(message));
55
+ export const logError = (message) => console.error(error('Error: ') + error(message));
56
+ export const logSuccess = (message) => console.log(success(message));
57
+ export const logWarning = (message) => console.log(warning(message));