@payal-jat/gitready-ai 1.1.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/README.md +177 -0
- package/bin/index.js +28 -0
- package/package.json +25 -0
- package/src/ai.js +122 -0
- package/src/commands/audit.js +44 -0
- package/src/commands/commit.js +87 -0
- package/src/fallback.js +54 -0
- package/src/git.js +27 -0
- package/src/readme.js +43 -0
- package/src/security/scanner.js +30 -0
- package/src/security.js +118 -0
package/README.md
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
## 🚀 GitReady AI: The Future of AI-Powered Git Workflow
|
|
2
|
+
|
|
3
|
+
**Elevate Your Development with Automated Commits, Security, and Dynamic Documentation.**
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
[](https://nodejs.org/)
|
|
8
|
+
[](https://ai.google.dev/)
|
|
9
|
+
[](https://opensource.org/licenses/MIT)
|
|
10
|
+
[](https://github.com/your-username/gitready-ai/stargazers)
|
|
11
|
+
[](https://github.com/your-username/gitready-ai/issues)
|
|
12
|
+
|
|
13
|
+
GitReady AI is a cutting-edge CLI tool that revolutionizes your Git workflow by integrating advanced AI capabilities with best-in-class development practices. It streamlines everything from commit message generation to security checks and even keeps your project's `README.md` dynamically updated, all with a single command. Say goodbye to manual overhead and inconsistent documentation – GitReady AI ensures every commit is professional, secure, and perfectly documented.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## ✨ Key Features
|
|
18
|
+
|
|
19
|
+
GitReady AI comes packed with features designed to boost your productivity and code quality:
|
|
20
|
+
|
|
21
|
+
* **🔍 Smart Security Scanner:** Before you commit, GitReady AI automatically scans for unignored sensitive files like `.env` or `node_modules` and alerts you, preventing accidental exposure of critical data and maintaining repository hygiene.
|
|
22
|
+
* **🤖 AI-Powered Commit Messages:** Leveraging the power of Google Gemini AI, GitReady AI analyzes your staged changes (`git diff`) to generate highly relevant, professional, and Conventional Commit-compliant messages. No more generic "fix" or "update" commits!
|
|
23
|
+
* **📝 Automated README Updates:** Keeps your project documentation vibrant and current. GitReady AI intelligently identifies significant changes in your code and offers to append a "Latest Updates" summary directly to your `README.md`, reflecting your most recent work.
|
|
24
|
+
* **💡 Intelligent Fallback System:** If AI services are unreachable or your API key isn't configured, GitReady AI gracefully falls back to a smart, heuristic-based commit message generator, ensuring your workflow is never interrupted.
|
|
25
|
+
* **💬 Interactive Review & Edit:** The AI-generated commit message is presented for your review. You have the option to accept it as is, or easily edit it before the final commit, giving you complete control.
|
|
26
|
+
* **⚡ Boosted Developer Productivity:** Consolidate multiple manual steps into one powerful command. GitReady AI handles security, intelligent commit generation, and documentation updates in seconds, allowing you to focus on writing code.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 🛠️ Professional Installation Guide
|
|
31
|
+
|
|
32
|
+
Getting started with GitReady AI is quick and easy. Follow these steps to set up the CLI tool globally on your system.
|
|
33
|
+
|
|
34
|
+
### Prerequisites
|
|
35
|
+
|
|
36
|
+
* **Node.js**: Ensure you have Node.js (version 16 or higher recommended) installed. You can download it from [nodejs.org](https://nodejs.org/).
|
|
37
|
+
* **Git**: Git must be installed and configured on your system.
|
|
38
|
+
* **Google Gemini API Key**: GitReady AI uses Google Gemini for its advanced capabilities.
|
|
39
|
+
1. Visit [Google AI Studio](https://aistudio.google.com/) or the [Google Cloud Console](https://console.cloud.google.com/apis/credentials) to create a new API key.
|
|
40
|
+
2. Ensure the Generative Language API is enabled for your project.
|
|
41
|
+
|
|
42
|
+
### Installation Steps
|
|
43
|
+
|
|
44
|
+
1. **Clone the Repository:**
|
|
45
|
+
Start by cloning the GitReady AI repository to your local machine:
|
|
46
|
+
```bash
|
|
47
|
+
git clone https://github.com/your-username/gitready-ai.git
|
|
48
|
+
cd gitready-ai
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
2. **Install Dependencies:**
|
|
52
|
+
Navigate into the cloned directory and install all necessary Node.js packages:
|
|
53
|
+
```bash
|
|
54
|
+
npm install
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
3. **Configure API Key:**
|
|
58
|
+
Create a `.env` file in the root of the `gitready-ai` project directory and add your Google Gemini API key:
|
|
59
|
+
```env
|
|
60
|
+
# .env
|
|
61
|
+
GEMINI_API_KEY=your_google_gemini_api_key_here
|
|
62
|
+
```
|
|
63
|
+
Replace `your_google_gemini_api_key_here` with the actual API key you obtained.
|
|
64
|
+
|
|
65
|
+
4. **Link the Tool Globally:**
|
|
66
|
+
To use `gitready` from any directory in your terminal, link it globally:
|
|
67
|
+
```bash
|
|
68
|
+
npm link
|
|
69
|
+
```
|
|
70
|
+
Now, `gitready` is available as a command-line tool.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 🚀 Usage
|
|
75
|
+
|
|
76
|
+
Using GitReady AI is incredibly straightforward. Simply stage your changes and run the `gitready` command within your Git repository.
|
|
77
|
+
|
|
78
|
+
1. **Stage Your Changes:**
|
|
79
|
+
As with any Git workflow, first stage the files you want to commit:
|
|
80
|
+
```bash
|
|
81
|
+
git add .
|
|
82
|
+
```
|
|
83
|
+
Or stage specific files:
|
|
84
|
+
```bash
|
|
85
|
+
git add src/new-feature.js README.md
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
2. **Run GitReady AI:**
|
|
89
|
+
Execute the tool. It will guide you through the process:
|
|
90
|
+
```bash
|
|
91
|
+
gitready
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Workflow at a Glance
|
|
95
|
+
|
|
96
|
+
When you run `gitready`, here's what happens:
|
|
97
|
+
|
|
98
|
+
1. **Repository Check:** Verifies if you are in a valid Git repository and have staged changes.
|
|
99
|
+
2. **Security Scan:** Performs a quick check for potentially exposed `.env` or `node_modules` files.
|
|
100
|
+
3. **AI Analysis:** GitReady AI analyzes your staged `git diff` using Google Gemini (or the smart fallback if unavailable).
|
|
101
|
+
4. **Commit Message Suggestion:** Presents an AI-generated commit message for your review. You can accept it or edit it interactively.
|
|
102
|
+
5. **README Update Prompt:** Asks if you'd like to update your `README.md` with a summary of the changes. If confirmed, it will update and stage the `README.md`.
|
|
103
|
+
6. **Final Commit:** Commits your changes with the chosen message.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## 🧰 Tech Stack
|
|
108
|
+
|
|
109
|
+
GitReady AI is built with a robust and modern tech stack to deliver a seamless and powerful user experience.
|
|
110
|
+
|
|
111
|
+
* **Runtime:** [](https://nodejs.org/)
|
|
112
|
+
* The core runtime environment for the CLI application.
|
|
113
|
+
* **AI Engine:** [](https://ai.google.dev/models/gemini)
|
|
114
|
+
* Powers the intelligent commit message generation and analysis. Specifically uses the `gemini-1.5-flash` model for high performance.
|
|
115
|
+
* **Git Integration:** [](https://github.com/steveukx/git-js)
|
|
116
|
+
* A lightweight library for running Git commands in a Node.js environment.
|
|
117
|
+
* **Interactive CLI:** [](https://github.com/SBoudrias/Inquirer.js)
|
|
118
|
+
* Provides a beautiful and intuitive command-line interface with prompts, confirmations, and input fields.
|
|
119
|
+
* **Terminal Styling:** [](https://github.com/chalk/chalk)
|
|
120
|
+
* Enables colorful and styled console output for better readability and user experience.
|
|
121
|
+
* **Environment Variables:** [](https://github.com/motdotla/dotenv)
|
|
122
|
+
* Manages environment variables securely from a `.env` file.
|
|
123
|
+
* **CLI Spinners:** [](https://github.com/sindresorhus/ora)
|
|
124
|
+
* Provides elegant loading spinners for a polished command-line user experience (not explicitly shown in diff, but assumed from previous README and typical CLI patterns).
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## 🏗️ Technical Architecture
|
|
129
|
+
|
|
130
|
+
GitReady AI is designed with a modular and robust architecture, enabling clear separation of concerns and easy extensibility.
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
.
|
|
134
|
+
├── bin/
|
|
135
|
+
│ └── index.js # Main CLI Entry Point & Orchestrator
|
|
136
|
+
├── src/
|
|
137
|
+
│ ├── ai.js # Google Gemini AI Integration (API Calls, Model Configuration, Retry Logic)
|
|
138
|
+
│ ├── git.js # Git Operations (Diff, Add, Commit)
|
|
139
|
+
│ ├── readme.js # README Update Logic (Parsing, Appending, Formatting)
|
|
140
|
+
│ └── utils.js # Utility functions (e.g., security scan, fallback message generator)
|
|
141
|
+
├── .env.example # Template for environment variables
|
|
142
|
+
├── package.json # Project dependencies and scripts
|
|
143
|
+
└── README.md # Project documentation (this file)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
1. **`bin/index.js` (The Orchestrator):** This is the heart of GitReady AI. It serves as the main entry point for the CLI, orchestrating the entire workflow. It initializes the tool, performs initial checks (Git repository, staged changes), manages the sequence of operations (security scan, AI analysis, interactive prompts, README update, commit), and handles global error catching. It uses `chalk` for terminal output styling and `simple-git` for core Git operations.
|
|
147
|
+
|
|
148
|
+
2. **`src/ai.js` (AI Core):** This module encapsulates all interactions with the Google Gemini API. It's responsible for loading the API key, configuring the generative model (`gemini-1.5-flash`), crafting prompts for optimal commit message generation, and handling API calls with robust retry logic to ensure reliability.
|
|
149
|
+
|
|
150
|
+
3. **`src/git.js` (Git Operations):** (Implied from usage in `index.js`) This module would abstract all direct interactions with Git, such as getting the staged diff, adding files to the staging area, and executing the final commit. It leverages `simple-git` for these functionalities.
|
|
151
|
+
|
|
152
|
+
4. **`src/readme.js` (Documentation Engine):** (Implied from usage in `index.js`) Dedicated to managing README updates. It parses the existing `README.md`, intelligently formats and appends new "Latest Updates" sections based on the code changes, and prepares the file for staging.
|
|
153
|
+
|
|
154
|
+
5. **`src/utils.js` (Utilities & Fallback):** (Implied from usage in `index.js`) Contains helper functions, including the logic for the "Smart Security Scan" (checking for `.env`, `node_modules` in `.gitignore`) and the "Smart Fallback Generator" which provides a heuristic-based commit message when the AI service is unavailable.
|
|
155
|
+
|
|
156
|
+
This architecture ensures a clean, maintainable, and scalable codebase, allowing individual components to be developed and tested independently.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 👨💻 Author
|
|
161
|
+
|
|
162
|
+
GitReady AI was developed with ❤️ by Payal Jat.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## 🤝 Contributing
|
|
167
|
+
|
|
168
|
+
We welcome contributions of all kinds! Whether it's reporting bugs, suggesting new features, improving documentation, or submitting pull requests, your input helps make GitReady AI even better. Please refer to our `CONTRIBUTING.md` (to be created) for detailed guidelines.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## 📜 License
|
|
173
|
+
|
|
174
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
*Generated by GitReady AI*
|
package/bin/index.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
const program = new Command();
|
|
6
|
+
|
|
7
|
+
program
|
|
8
|
+
.name('gitready')
|
|
9
|
+
.description('AI-powered developer workflow automator')
|
|
10
|
+
.version('1.1.0');
|
|
11
|
+
|
|
12
|
+
program
|
|
13
|
+
.command('commit')
|
|
14
|
+
.description('Analyze changes and generate AI commit & README update')
|
|
15
|
+
.action(async () => {
|
|
16
|
+
const { runCommitFlow } = await import('../src/commands/commit.js');
|
|
17
|
+
await runCommitFlow();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
program
|
|
21
|
+
.command('audit')
|
|
22
|
+
.description('Deep scan the repository for leaked secrets (AWS, JWT, Keys)')
|
|
23
|
+
.action(async () => {
|
|
24
|
+
const { runAuditFlow } = await import('../src/commands/audit.js');
|
|
25
|
+
await runAuditFlow();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
program.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@payal-jat/gitready-ai",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
7
|
+
"description": "Professional AI-powered Git workflow automator",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "bin/index.js",
|
|
10
|
+
"bin": {
|
|
11
|
+
"gitready": "bin/index.js"
|
|
12
|
+
},
|
|
13
|
+
"author": "Payal Jat",
|
|
14
|
+
"license": "ISC",
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@google/generative-ai": "^0.24.1",
|
|
17
|
+
"chalk": "^4.1.2",
|
|
18
|
+
"commander": "^15.0.0",
|
|
19
|
+
"dotenv": "^17.4.2",
|
|
20
|
+
"fs-extra": "^11.3.5",
|
|
21
|
+
"inquirer": "^14.0.2",
|
|
22
|
+
"openai": "^6.39.1",
|
|
23
|
+
"simple-git": "^3.36.0"
|
|
24
|
+
}
|
|
25
|
+
}
|
package/src/ai.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { GoogleGenerativeAI } from "@google/generative-ai";
|
|
2
|
+
import dotenv from "dotenv";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
8
|
+
dotenv.config({ path: path.join(__dirname, "../.env") });
|
|
9
|
+
|
|
10
|
+
const apiKey = process.env.GEMINI_API_KEY?.trim();
|
|
11
|
+
const genAI = new GoogleGenerativeAI(apiKey || "");
|
|
12
|
+
|
|
13
|
+
async function generateContent(prompt) {
|
|
14
|
+
if (!apiKey) return null;
|
|
15
|
+
const modelsToTry = ["gemini-2.5-flash", "gemini-2.5-pro"];
|
|
16
|
+
|
|
17
|
+
for (const modelName of modelsToTry) {
|
|
18
|
+
try {
|
|
19
|
+
const model = genAI.getGenerativeModel({ model: modelName });
|
|
20
|
+
const result = await model.generateContent(prompt);
|
|
21
|
+
const response = await result.response;
|
|
22
|
+
const text = response.text().trim();
|
|
23
|
+
if (text) return text;
|
|
24
|
+
} catch (error) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function getAICommitMessage(diff) {
|
|
32
|
+
const prompt = `You are an expert software engineer. Analyze this git diff and write a single Git commit message.
|
|
33
|
+
|
|
34
|
+
STRICT RULES:
|
|
35
|
+
- Format: <type>(<scope>): <short description>
|
|
36
|
+
- Allowed types: feat, fix, refactor, docs, style, test, chore, perf
|
|
37
|
+
- scope = the main file or module changed (e.g., readme, auth, cli, scanner)
|
|
38
|
+
- description: max 72 chars, imperative mood ("add" not "added"), lowercase
|
|
39
|
+
- If changes are complex, add ONE blank line then 2-3 bullet points explaining WHY
|
|
40
|
+
- Be SPECIFIC — mention actual function names, file names, or features changed
|
|
41
|
+
- NO generic phrases like "update files", "fix bug", "make changes"
|
|
42
|
+
|
|
43
|
+
GOOD examples:
|
|
44
|
+
feat(cli): add interactive model selection before commit
|
|
45
|
+
fix(readme): replace appendFile with section-aware changelog update
|
|
46
|
+
refactor(ai): strengthen prompts with explicit rules and examples
|
|
47
|
+
docs(readme): add changelog section with dated entries
|
|
48
|
+
|
|
49
|
+
BAD examples (never do this):
|
|
50
|
+
update files
|
|
51
|
+
fix bug
|
|
52
|
+
changes made
|
|
53
|
+
minor improvements
|
|
54
|
+
|
|
55
|
+
Git diff to analyze:
|
|
56
|
+
\`\`\`
|
|
57
|
+
${diff.slice(0, 4000)}
|
|
58
|
+
\`\`\`
|
|
59
|
+
|
|
60
|
+
Respond with ONLY the commit message. No explanation, no markdown formatting, no quotes.`;
|
|
61
|
+
|
|
62
|
+
const result = await generateContent(prompt);
|
|
63
|
+
return result ? result.replace(/^['"`]+|['"`]+$/g, "").trim() : null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export async function getAIReadmeSummary(diff) {
|
|
67
|
+
const prompt = `You are a technical writer updating a project changelog.
|
|
68
|
+
|
|
69
|
+
Analyze this git diff and write a changelog entry as markdown bullet points.
|
|
70
|
+
|
|
71
|
+
STRICT RULES:
|
|
72
|
+
- Start every bullet with "- "
|
|
73
|
+
- Be specific: mention actual file names, function names, or feature names
|
|
74
|
+
- Use past tense: "Added", "Fixed", "Removed", "Refactored", "Improved"
|
|
75
|
+
- Max 5 bullets
|
|
76
|
+
- NO generic phrases like "various improvements", "minor fixes", "updated code"
|
|
77
|
+
- If a function was renamed or logic was changed, say exactly what
|
|
78
|
+
|
|
79
|
+
GOOD example output:
|
|
80
|
+
- Refactored \`readme.js\` to maintain a persistent Changelog section instead of appending duplicates
|
|
81
|
+
- Improved commit message prompt in \`ai.js\` with explicit Conventional Commits rules and examples
|
|
82
|
+
- Added manual fallback input when AI summary generation fails
|
|
83
|
+
- Fixed \`generateContent()\` to return null on empty response instead of throwing
|
|
84
|
+
|
|
85
|
+
BAD example output:
|
|
86
|
+
- Updated various files
|
|
87
|
+
- Fixed some bugs
|
|
88
|
+
- Made improvements to the codebase
|
|
89
|
+
|
|
90
|
+
Git diff:
|
|
91
|
+
\`\`\`
|
|
92
|
+
${diff.slice(0, 4000)}
|
|
93
|
+
\`\`\`
|
|
94
|
+
|
|
95
|
+
Respond with ONLY the bullet points. No heading, no explanation, no intro line.`;
|
|
96
|
+
|
|
97
|
+
return await generateContent(prompt);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
export async function getFullProjectReadme(diff) {
|
|
102
|
+
const prompt = `
|
|
103
|
+
You are a World-Class Open Source Maintainer.
|
|
104
|
+
Analyze the following code changes and project structure to generate a TOP-TIER README.md.
|
|
105
|
+
|
|
106
|
+
The README MUST include:
|
|
107
|
+
1. 🚀 A Catchy Project Title and a "High-Impact" Tagline.
|
|
108
|
+
2. ✨ Key Features (Extract these from the code logic).
|
|
109
|
+
3. 🛠️ Professional Installation Guide.
|
|
110
|
+
4. 🚀 Usage instructions with code blocks.
|
|
111
|
+
5. 🧰 Tech Stack (List the libraries you see in the code).
|
|
112
|
+
6. 🏗️ Technical Architecture (Explain how the code is organized).
|
|
113
|
+
7. 👨💻 Author section.
|
|
114
|
+
|
|
115
|
+
Use professional Markdown, Badges, and Emojis.
|
|
116
|
+
Make it look like a repository that has 10k+ stars on GitHub.
|
|
117
|
+
|
|
118
|
+
Code Context:
|
|
119
|
+
${diff.slice(0, 8000)}
|
|
120
|
+
`;
|
|
121
|
+
return await generateContent(prompt);
|
|
122
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { deepScan } from '../security/scanner.js';
|
|
5
|
+
|
|
6
|
+
export async function runAuditFlow() {
|
|
7
|
+
console.log(chalk.blue.bold('\n Running GitReady Repository Audit...'));
|
|
8
|
+
|
|
9
|
+
let score = 100;
|
|
10
|
+
const issues = [];
|
|
11
|
+
const currentDir = process.cwd();
|
|
12
|
+
|
|
13
|
+
const findings = await deepScan(currentDir);
|
|
14
|
+
if (findings.length > 0) {
|
|
15
|
+
score -= (findings.length * 15);
|
|
16
|
+
issues.push(chalk.red(`- Found ${findings.length} leaked secrets/keys!`));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (!(await fs.pathExists(path.join(currentDir, 'README.md')))) {
|
|
20
|
+
score -= 30;
|
|
21
|
+
issues.push(chalk.yellow("- README.md is missing."));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (!(await fs.pathExists(path.join(currentDir, '.gitignore')))) {
|
|
25
|
+
score -= 20;
|
|
26
|
+
issues.push(chalk.yellow("- .gitignore is missing."));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (await fs.pathExists(path.join(currentDir, 'node_modules'))) {
|
|
30
|
+
score += 5;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
console.log(chalk.bold('\n--- Audit Report ---'));
|
|
34
|
+
|
|
35
|
+
let scoreColor = score > 80 ? chalk.green : score > 50 ? chalk.yellow : chalk.red;
|
|
36
|
+
console.log(`Repo Health Score: ${scoreColor(score + '/100')}`);
|
|
37
|
+
|
|
38
|
+
if (issues.length > 0) {
|
|
39
|
+
console.log(chalk.bold('\nSuggestions to improve:'));
|
|
40
|
+
issues.forEach(issue => console.log(issue));
|
|
41
|
+
} else {
|
|
42
|
+
console.log(chalk.green('\n Your repository structure is excellent!'));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import inquirer from 'inquirer';
|
|
3
|
+
import simpleGit from 'simple-git';
|
|
4
|
+
|
|
5
|
+
import { runSecurityCheck } from '../security.js';
|
|
6
|
+
import { getGitDiff, commitCode } from '../git.js';
|
|
7
|
+
import { getAICommitMessage } from '../ai.js';
|
|
8
|
+
import { updateReadme } from '../readme.js';
|
|
9
|
+
import { generateFallbackCommitMessage } from '../fallback.js';
|
|
10
|
+
|
|
11
|
+
const currentDir = process.cwd();
|
|
12
|
+
const git = simpleGit(currentDir);
|
|
13
|
+
|
|
14
|
+
export async function runCommitFlow() {
|
|
15
|
+
console.log(chalk.blue.bold('\n GitReady AI: Commit Workflow Starting...'));
|
|
16
|
+
|
|
17
|
+
await runSecurityCheck(currentDir);
|
|
18
|
+
|
|
19
|
+
const result = await getGitDiff();
|
|
20
|
+
|
|
21
|
+
if (result.error === 'NOT_A_REPO') {
|
|
22
|
+
console.log(chalk.red('\n Error: This folder is not a Git repository.'));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const diff = result.diff;
|
|
27
|
+
if (!diff || diff.trim() === '') {
|
|
28
|
+
console.log(chalk.red('\n No staged changes found. Use "git add ." first.'));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 3. AI Analysis
|
|
33
|
+
console.log(chalk.yellow('\n Analyzing your changes with AI...'));
|
|
34
|
+
let suggestion = "";
|
|
35
|
+
let isAIGenerated = false;
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
suggestion = await getAICommitMessage(diff);
|
|
39
|
+
if (suggestion) {
|
|
40
|
+
isAIGenerated = true;
|
|
41
|
+
} else {
|
|
42
|
+
suggestion = generateFallbackCommitMessage(diff);
|
|
43
|
+
isAIGenerated = false;
|
|
44
|
+
}
|
|
45
|
+
} catch (error) {
|
|
46
|
+
suggestion = generateFallbackCommitMessage(diff);
|
|
47
|
+
isAIGenerated = false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const { finalMessage } = await inquirer.prompt([{
|
|
51
|
+
type: 'input',
|
|
52
|
+
name: 'finalMessage',
|
|
53
|
+
message: isAIGenerated ? chalk.cyan('AI Suggestion:') : chalk.yellow('Smart Suggestion (Fallback):'),
|
|
54
|
+
default: suggestion,
|
|
55
|
+
validate: input => input.trim() !== '' || 'Commit message cannot be empty.'
|
|
56
|
+
}]);
|
|
57
|
+
|
|
58
|
+
const { confirmReadmeUpdate } = await inquirer.prompt([{
|
|
59
|
+
type: 'confirm',
|
|
60
|
+
name: 'confirmReadmeUpdate',
|
|
61
|
+
message: 'Would you like to update README.md with these changes?',
|
|
62
|
+
default: true
|
|
63
|
+
}]);
|
|
64
|
+
|
|
65
|
+
if (confirmReadmeUpdate) {
|
|
66
|
+
console.log(chalk.yellow(' Updating README...'));
|
|
67
|
+
const success = await updateReadme(currentDir, diff);
|
|
68
|
+
if (success) {
|
|
69
|
+
await git.add('README.md');
|
|
70
|
+
console.log(chalk.green(' README.md updated and staged.'));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const { confirmFinalCommit } = await inquirer.prompt([{
|
|
75
|
+
type: 'confirm',
|
|
76
|
+
name: 'confirmFinalCommit',
|
|
77
|
+
message: 'Ready to commit all staged changes?',
|
|
78
|
+
default: true
|
|
79
|
+
}]);
|
|
80
|
+
|
|
81
|
+
if (confirmFinalCommit) {
|
|
82
|
+
await commitCode(finalMessage);
|
|
83
|
+
console.log(chalk.green.bold('\n Success: Everything committed successfully!'));
|
|
84
|
+
} else {
|
|
85
|
+
console.log(chalk.gray('\nCommit process cancelled by user.'));
|
|
86
|
+
}
|
|
87
|
+
}
|
package/src/fallback.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export function generateFallbackCommitMessage(diff) {
|
|
2
|
+
const lowerDiff = diff.toLowerCase();
|
|
3
|
+
|
|
4
|
+
// 1. Extract file names from the diff to be more specific
|
|
5
|
+
// This regex looks for files being changed in the git diff format
|
|
6
|
+
const changedFiles = [...diff.matchAll(/\+\+\+ b\/(.*)/g)].map(m => m[1]);
|
|
7
|
+
const mainFile = changedFiles[0] || "";
|
|
8
|
+
|
|
9
|
+
if (changedFiles.some(f => f.toLowerCase().includes("readme.md"))) {
|
|
10
|
+
return "docs: update project documentation";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (changedFiles.some(f => f.endsWith(".css") || f.endsWith(".scss"))) {
|
|
14
|
+
const fileName = mainFile.split('/').pop();
|
|
15
|
+
return `style: updated styling in ${fileName || 'project'}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (lowerDiff.includes("package.json")) {
|
|
19
|
+
if (lowerDiff.includes("\"dependencies\"") || lowerDiff.includes("\"devdependencies\"")) {
|
|
20
|
+
return "build: update npm dependencies";
|
|
21
|
+
}
|
|
22
|
+
return "chore: update package configuration";
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (changedFiles.some(f => /\.(png|jpg|jpeg|gif|svg|ico)$/i.test(f))) {
|
|
26
|
+
return "assets: update image resources";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (lowerDiff.includes("console.log") && lowerDiff.startsWith("-")) {
|
|
30
|
+
return "chore: remove debug logs";
|
|
31
|
+
}
|
|
32
|
+
if (lowerDiff.includes("fix") || lowerDiff.includes("prevent") || lowerDiff.includes("issue")) {
|
|
33
|
+
return "fix: resolve detected logic issue";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (mainFile.includes("components/")) {
|
|
37
|
+
const componentName = mainFile.split('/').pop().split('.')[0];
|
|
38
|
+
return `feat: update ${componentName} component`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (mainFile.includes("utils/") || mainFile.includes("helpers/")) {
|
|
42
|
+
return "refactor: optimize utility functions";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (mainFile.endsWith(".js") || mainFile.endsWith(".jsx") || mainFile.endsWith(".ts")) {
|
|
46
|
+
return `feat: update logic in ${mainFile.split('/').pop()}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (mainFile.endsWith(".html")) {
|
|
50
|
+
return "feat: update html structure";
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return "chore: general project maintenance";
|
|
54
|
+
}
|
package/src/git.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import simpleGit from 'simple-git';
|
|
2
|
+
|
|
3
|
+
const git = simpleGit({
|
|
4
|
+
baseDir: process.cwd(),
|
|
5
|
+
binary: 'git',
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export async function getGitDiff() {
|
|
9
|
+
try {
|
|
10
|
+
const isRepo = await git.checkIsRepo();
|
|
11
|
+
|
|
12
|
+
if (!isRepo) {
|
|
13
|
+
return { error: 'NOT_A_REPO' };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const diff = await git.diff(['--staged']);
|
|
17
|
+
|
|
18
|
+
return { diff: diff || '' };
|
|
19
|
+
|
|
20
|
+
} catch (err) {
|
|
21
|
+
return { error: err.message };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function commitCode(message) {
|
|
26
|
+
return await git.commit(message);
|
|
27
|
+
}
|
package/src/readme.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// src/readme.js
|
|
2
|
+
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import inquirer from 'inquirer';
|
|
7
|
+
import { getFullProjectReadme } from './ai.js';
|
|
8
|
+
|
|
9
|
+
export async function updateReadme(currentDir, diff) {
|
|
10
|
+
const readmePath = path.join(currentDir, 'README.md');
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
if (await fs.pathExists(readmePath)) {
|
|
14
|
+
const { confirmOverwrite } = await inquirer.prompt([{
|
|
15
|
+
type: 'confirm',
|
|
16
|
+
name: 'confirmOverwrite',
|
|
17
|
+
message: chalk.yellow('README.md already exists. Do you want to REGENERATE the full professional documentation?'),
|
|
18
|
+
default: false
|
|
19
|
+
}]);
|
|
20
|
+
|
|
21
|
+
if (!confirmOverwrite) {
|
|
22
|
+
console.log(chalk.gray(' README update skipped by user.'));
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
console.log(chalk.cyan(' AI is architecting your professional README...'));
|
|
28
|
+
|
|
29
|
+
const professionalContent = await getFullProjectReadme(diff);
|
|
30
|
+
|
|
31
|
+
if (!professionalContent) {
|
|
32
|
+
console.log(chalk.red(' AI failed to generate content.'));
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
await fs.writeFile(readmePath, professionalContent + `\n\n---\n*Generated by GitReady AI*`);
|
|
37
|
+
|
|
38
|
+
return true;
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error(chalk.red(` README Error: ${error.message}`));
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
const SECRET_PATTERNS = [
|
|
5
|
+
{ name: "AWS Access Key", regex: /AKIA[0-9A-Z]{16}/ },
|
|
6
|
+
{ name: "GitHub Token", regex: /ghp_[a-zA-Z0-9]{36}/ },
|
|
7
|
+
{ name: "Private Key", regex: /-----BEGIN (RSA|EC|DSA|OPENSSH) PRIVATE KEY-----/ },
|
|
8
|
+
{ name: "Generic Secret", regex: /secret[:=]\s*['"][a-zA-Z0-9]{16,}['"]/i }
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
export async function deepScan(directory) {
|
|
12
|
+
const findings = [];
|
|
13
|
+
const files = await fs.readdir(directory, { recursive: true });
|
|
14
|
+
|
|
15
|
+
for (const file of files) {
|
|
16
|
+
if (file.includes('node_modules') || file.includes('.git')) continue;
|
|
17
|
+
|
|
18
|
+
const fullPath = path.join(directory, file);
|
|
19
|
+
if ((await fs.lstat(fullPath)).isFile()) {
|
|
20
|
+
const content = await fs.readFile(fullPath, 'utf8');
|
|
21
|
+
|
|
22
|
+
SECRET_PATTERNS.forEach(pattern => {
|
|
23
|
+
if (pattern.regex.test(content)) {
|
|
24
|
+
findings.push({ file, type: pattern.name });
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return findings;
|
|
30
|
+
}
|
package/src/security.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// src/security.js
|
|
2
|
+
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import inquirer from 'inquirer';
|
|
7
|
+
|
|
8
|
+
export async function runSecurityCheck(currentDir) {
|
|
9
|
+
const gitIgnorePath = path.join(currentDir, '.gitignore');
|
|
10
|
+
|
|
11
|
+
const envExists =
|
|
12
|
+
await fs.pathExists(path.join(currentDir, '.env'));
|
|
13
|
+
|
|
14
|
+
const nodeModulesExists =
|
|
15
|
+
await fs.pathExists(
|
|
16
|
+
path.join(currentDir, 'node_modules')
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
let missingEntries = [];
|
|
20
|
+
|
|
21
|
+
let gitIgnoreContent = '';
|
|
22
|
+
|
|
23
|
+
if (await fs.pathExists(gitIgnorePath)) {
|
|
24
|
+
gitIgnoreContent = await fs.readFile(
|
|
25
|
+
gitIgnorePath,
|
|
26
|
+
'utf8'
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Check .env
|
|
31
|
+
if (
|
|
32
|
+
envExists &&
|
|
33
|
+
!gitIgnoreContent.includes('.env')
|
|
34
|
+
) {
|
|
35
|
+
missingEntries.push('.env');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Check node_modules
|
|
39
|
+
if (
|
|
40
|
+
nodeModulesExists &&
|
|
41
|
+
!gitIgnoreContent.includes('node_modules')
|
|
42
|
+
) {
|
|
43
|
+
missingEntries.push('node_modules');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (missingEntries.length === 0) {
|
|
47
|
+
console.log(
|
|
48
|
+
chalk.green(
|
|
49
|
+
' Security Check Passed.'
|
|
50
|
+
)
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
success: true,
|
|
55
|
+
updated: false
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
console.log(
|
|
60
|
+
chalk.yellow(
|
|
61
|
+
` Security Alert: ${missingEntries.join(', ')} not found in .gitignore`
|
|
62
|
+
)
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const { fixIgnore } = await inquirer.prompt([
|
|
66
|
+
{
|
|
67
|
+
type: 'confirm',
|
|
68
|
+
name: 'fixIgnore',
|
|
69
|
+
message: `Add ${missingEntries.join(
|
|
70
|
+
' and '
|
|
71
|
+
)} to .gitignore?`,
|
|
72
|
+
default: true
|
|
73
|
+
}
|
|
74
|
+
]);
|
|
75
|
+
|
|
76
|
+
if (!fixIgnore) {
|
|
77
|
+
console.log(
|
|
78
|
+
chalk.yellow(
|
|
79
|
+
' Security recommendations skipped.'
|
|
80
|
+
)
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
success: true,
|
|
85
|
+
updated: false
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const entriesToAdd = [
|
|
90
|
+
'',
|
|
91
|
+
'# Added by GitReady AI',
|
|
92
|
+
...missingEntries
|
|
93
|
+
].join('\n');
|
|
94
|
+
|
|
95
|
+
if (await fs.pathExists(gitIgnorePath)) {
|
|
96
|
+
await fs.appendFile(
|
|
97
|
+
gitIgnorePath,
|
|
98
|
+
`\n${entriesToAdd}\n`
|
|
99
|
+
);
|
|
100
|
+
} else {
|
|
101
|
+
await fs.writeFile(
|
|
102
|
+
gitIgnorePath,
|
|
103
|
+
`${entriesToAdd}\n`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
console.log(
|
|
108
|
+
chalk.green(
|
|
109
|
+
'.gitignore updated successfully.'
|
|
110
|
+
)
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
success: true,
|
|
115
|
+
updated: true,
|
|
116
|
+
added: missingEntries
|
|
117
|
+
};
|
|
118
|
+
}
|