@dev-angsu/cli 1.0.0 → 1.0.1

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
@@ -15,7 +15,7 @@ const program = new Command();
15
15
  // 1. Metadata
16
16
  program
17
17
  .name("cli")
18
- .description("A CLI to demonstrate industry standards")
18
+ .description("A CLI to demonstrate industry")
19
19
  .version("1.0.0");
20
20
 
21
21
  // 2. Define a Command
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.1",
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,142 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { simpleGit } from "simple-git";
4
+ import OpenAI from "openai";
5
+ import "dotenv/config"; // Loads .env file automatically
6
+
7
+ import * as core from "@actions/core";
8
+ import * as github from "@actions/github";
9
+
10
+ const git = simpleGit();
11
+
12
+ if (!process.env.OPENAI_API_KEY) {
13
+ console.error("❌ Error: OPENAI_API_KEY is missing in .env file.");
14
+ process.exit(1);
15
+ }
16
+
17
+ const openai = new OpenAI({
18
+ apiKey: process.env.OPENAI_API_KEY,
19
+ baseURL: process.env.AI_BASE_URL || "https://api.z.ai/api/paas/v4/",
20
+ });
21
+
22
+ // async function getStagedDiff() {
23
+ // const diff = await git.diff(["--staged"]);
24
+ // return diff;
25
+ // }
26
+ // STRATEGY 1: Local Development
27
+ async function getLocalDiff() {
28
+ console.log("💻 Running in Local Mode...");
29
+ const git = simpleGit();
30
+ const diff = await git.diff(["--staged"]);
31
+ return diff;
32
+ }
33
+ // STRATEGY 2: GitHub Actions (CI/CD)
34
+ async function getPRDiff() {
35
+ console.log("☁️ Running in GitHub Actions Mode...");
36
+
37
+ // The 'GITHUB_TOKEN' is automatically provided by the workflow
38
+ const token = process.env.GITHUB_TOKEN;
39
+ const octokit = github.getOctokit(token);
40
+
41
+ const context = github.context;
42
+ const prNumber = context.payload.pull_request?.number;
43
+
44
+ if (!prNumber) {
45
+ throw new Error(
46
+ "❌ No Pull Request found in context. Are you running this on push?"
47
+ );
48
+ }
49
+
50
+ // Fetch the diff specifically
51
+ const { data: diff } = await octokit.rest.pulls.get({
52
+ owner: context.repo.owner,
53
+ repo: context.repo.repo,
54
+ pull_number: prNumber,
55
+ mediaType: {
56
+ format: "diff", // Ask GitHub to return the raw diff text
57
+ },
58
+ });
59
+
60
+ return diff;
61
+ }
62
+
63
+ async function generateReview(diff) {
64
+ // 1. Token Safety: Truncate if too huge (basic safety mechanism)
65
+ const MAX_CHARS = 15000;
66
+ const processedDiff =
67
+ diff.length > MAX_CHARS
68
+ ? diff.substring(0, MAX_CHARS) + "\n...[Diff Truncated due to size]..."
69
+ : diff;
70
+
71
+ console.log("🤔 Analyzing changes...");
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
+ 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
+ run();