@dev-angsu/cli 1.0.0 → 1.0.2

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/bin/index.js CHANGED
@@ -10,13 +10,15 @@ import chalk from "chalk";
10
10
  import ora from "ora";
11
11
  import fs from "fs";
12
12
 
13
+ import { run as review } from "../src/utils/engine.js";
14
+
13
15
  const program = new Command();
14
16
 
15
17
  // 1. Metadata
16
18
  program
17
19
  .name("cli")
18
- .description("A CLI to demonstrate industry standards")
19
- .version("1.0.0");
20
+ .description("A CLI to demonstrate industry")
21
+ .version("1.0.1");
20
22
 
21
23
  // 2. Define a Command
22
24
  program
@@ -73,5 +75,14 @@ program
73
75
  }
74
76
  });
75
77
 
78
+ // 3. Review Command
79
+ program
80
+ .command("review")
81
+ .alias("r")
82
+ .description("Review staged changes using AI")
83
+ .action(async () => {
84
+ await review();
85
+ });
86
+
76
87
  // 6. Parse Arguments
77
88
  program.parse(process.argv);
package/package.json CHANGED
@@ -1,23 +1,29 @@
1
1
  {
2
2
  "name": "@dev-angsu/cli",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
7
  "test": "echo \"Error: no test specified\" && exit 1"
8
8
  },
9
9
  "bin": {
10
- "cli": "./bin/index.js"
10
+ "dev-angsu": "./bin/index.js",
11
+ "review-code": "./src/utils/engine.js"
11
12
  },
12
13
  "keywords": [],
13
14
  "author": "",
14
15
  "license": "ISC",
15
16
  "type": "module",
16
17
  "dependencies": {
18
+ "@actions/core": "^2.0.1",
19
+ "@actions/github": "^6.0.1",
17
20
  "chalk": "^5.6.2",
18
21
  "commander": "^14.0.2",
22
+ "dotenv": "^17.2.3",
19
23
  "inquirer": "^13.1.0",
20
- "ora": "^9.0.0"
24
+ "openai": "^6.15.0",
25
+ "ora": "^9.0.0",
26
+ "simple-git": "^3.30.0"
21
27
  },
22
28
  "files": [
23
29
  "bin",
@@ -0,0 +1,144 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { simpleGit } from "simple-git";
4
+ import OpenAI from "openai";
5
+ import { fileURLToPath } from "url";
6
+ import "dotenv/config"; // Loads .env file automatically
7
+
8
+ import * as core from "@actions/core";
9
+ import * as github from "@actions/github";
10
+
11
+ const git = simpleGit();
12
+
13
+ // async function getStagedDiff() {
14
+ // const diff = await git.diff(["--staged"]);
15
+ // return diff;
16
+ // }
17
+ // STRATEGY 1: Local Development
18
+ async function getLocalDiff() {
19
+ console.log("💻 Running in Local Mode...");
20
+ const git = simpleGit();
21
+ const diff = await git.diff(["--staged"]);
22
+ return diff;
23
+ }
24
+ // STRATEGY 2: GitHub Actions (CI/CD)
25
+ async function getPRDiff() {
26
+ console.log("☁️ Running in GitHub Actions Mode...");
27
+
28
+ // The 'GITHUB_TOKEN' is automatically provided by the workflow
29
+ const token = process.env.GITHUB_TOKEN;
30
+ const octokit = github.getOctokit(token);
31
+
32
+ const context = github.context;
33
+ const prNumber = context.payload.pull_request?.number;
34
+
35
+ if (!prNumber) {
36
+ throw new Error(
37
+ "❌ No Pull Request found in context. Are you running this on push?"
38
+ );
39
+ }
40
+
41
+ // Fetch the diff specifically
42
+ const { data: diff } = await octokit.rest.pulls.get({
43
+ owner: context.repo.owner,
44
+ repo: context.repo.repo,
45
+ pull_number: prNumber,
46
+ mediaType: {
47
+ format: "diff", // Ask GitHub to return the raw diff text
48
+ },
49
+ });
50
+
51
+ return diff;
52
+ }
53
+
54
+ async function generateReview(diff) {
55
+ // 1. Token Safety: Truncate if too huge (basic safety mechanism)
56
+ const MAX_CHARS = 15000;
57
+ const processedDiff =
58
+ diff.length > MAX_CHARS
59
+ ? diff.substring(0, MAX_CHARS) + "\n...[Diff Truncated due to size]..."
60
+ : diff;
61
+
62
+ console.log("🤔 Analyzing changes...");
63
+
64
+ if (!process.env.OPENAI_API_KEY) {
65
+ throw new Error("❌ Error: OPENAI_API_KEY is missing in .env file.");
66
+ }
67
+
68
+ const openai = new OpenAI({
69
+ apiKey: process.env.OPENAI_API_KEY,
70
+ baseURL: process.env.AI_BASE_URL || "https://api.z.ai/api/paas/v4/",
71
+ });
72
+
73
+ const response = await openai.chat.completions.create({
74
+ model: process.env.AI_MODEL || "glm-4.6v-flash",
75
+ messages: [
76
+ {
77
+ role: "system",
78
+ content: `You are a Senior Software Engineer doing a Code Review.
79
+
80
+ Rules:
81
+ 1. Summarize the changes in 1 sentence.
82
+ 2. Identify any critical bugs or security risks (SQL injection, hardcoded secrets).
83
+ 3. Suggest code style improvements (focus on readability).
84
+ 4. Generate a concise, conventional commit message for these changes.
85
+ 5. If the code looks good, output "LGTM" (Looks Good To Me) with a thumbs up.
86
+
87
+ Format your response in nice Markdown.`,
88
+ },
89
+ {
90
+ role: "user",
91
+ content: `Here is the git diff of the changes:\n\n${processedDiff}`,
92
+ },
93
+ ],
94
+ });
95
+
96
+ return response.choices[0].message.content;
97
+ }
98
+
99
+ // Main Execution
100
+ export async function run() {
101
+ try {
102
+ // const diff = await getStagedDiff();
103
+ // 1. SELECT STRATEGY
104
+ let diff;
105
+ if (process.env.CI) {
106
+ diff = await getPRDiff();
107
+ } else {
108
+ diff = await getLocalDiff();
109
+ }
110
+
111
+ if (!diff) {
112
+ console.log("⚠️ No staged changes found. Did you run 'git add'?");
113
+ return;
114
+ }
115
+
116
+ const review = await generateReview(diff);
117
+ if (process.env.CI) {
118
+ // In CI, we post a comment back to the PR
119
+ const token = process.env.GITHUB_TOKEN;
120
+ const octokit = github.getOctokit(token);
121
+ const context = github.context;
122
+
123
+ await octokit.rest.issues.createComment({
124
+ owner: context.repo.owner,
125
+ repo: context.repo.repo,
126
+ issue_number: context.payload.pull_request.number,
127
+ body: review,
128
+ });
129
+ console.log("✅ Review posted to GitHub PR!");
130
+ } else {
131
+ // Locally, we just print it
132
+ console.log("\n================ 🤖 AI CODE REVIEW ================ \n");
133
+ console.log(review);
134
+ console.log("\n=================================================== \n");
135
+ }
136
+ } catch (error) {
137
+ console.error("Error:", error.message);
138
+ if (process.env.CI) core.setFailed(error.message); // Fail the pipeline
139
+ }
140
+ }
141
+
142
+ if (process.argv[1] === fileURLToPath(import.meta.url)) {
143
+ run();
144
+ }