review-mark 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/README.md +14 -141
- package/dist/cli/review.cjs +89 -51
- package/dist/cli/review.cjs.map +1 -1
- package/dist/cli/review.js +97 -53
- package/dist/cli/review.js.map +1 -1
- package/dist/index.cjs +86 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +95 -50
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/cli/review.ts +3 -3
- package/src/core/BeLinkReview.ts +17 -16
- package/src/core/feishu.ts +10 -8
- package/src/core/git.ts +30 -23
- package/src/utils/checkCli.ts +58 -17
package/README.md
CHANGED
|
@@ -1,91 +1,30 @@
|
|
|
1
|
-
#
|
|
1
|
+
# review-mark
|
|
2
2
|
|
|
3
3
|
A powerful CLI tool for AI-powered code review using Git diffs.
|
|
4
4
|
|
|
5
5
|
## 目标
|
|
6
6
|
|
|
7
|
-
`
|
|
8
|
-
|
|
9
|
-
## 特性
|
|
10
|
-
|
|
11
|
-
- **TypeScript 支持**: 整个项目使用 TypeScript 编写,提供强大的类型安全和开发体验。
|
|
12
|
-
- **ESM + CommonJS**: 支持现代 Node.js 环境下的 ESM 和 CommonJS 模块系统。
|
|
13
|
-
- **CLI 工具**: 基于 `commander` 构建,提供友好的命令行接口。
|
|
14
|
-
- **自动化 Git Diff**: 自动检测并获取 Git 仓库中的代码变更(包括暂存区和工作区)。
|
|
15
|
-
- **AI 代码审查**: 将 Git diff 发送给 Cursor CLI 进行 AI 驱动的代码审查。
|
|
16
|
-
- **Cursor CLI 自动检测与安装**: 自动检测 `agent` 命令是否存在,如果不存在则提示并提供安装指引。
|
|
17
|
-
- **易于集成**: 通过简单的 `init` 方法即可在用户项目中配置 `review` 脚本。
|
|
18
|
-
- **可发布到 npm**: 完整的项目结构和打包配置,方便发布到 npm。
|
|
19
|
-
|
|
20
|
-
## 项目结构
|
|
21
|
-
|
|
22
|
-
```
|
|
23
|
-
be-link-review
|
|
24
|
-
│
|
|
25
|
-
├─ src
|
|
26
|
-
│ ├─ core
|
|
27
|
-
│ │ ├─ BeLinkReview.ts
|
|
28
|
-
│ │ ├─ git.ts
|
|
29
|
-
│ │ └─ prompt.ts
|
|
30
|
-
│ │
|
|
31
|
-
│ ├─ cli
|
|
32
|
-
│ │ └─ review.ts
|
|
33
|
-
│ │
|
|
34
|
-
│ ├─ utils
|
|
35
|
-
│ │ └─ checkCli.ts
|
|
36
|
-
│ │
|
|
37
|
-
│ └─ index.ts
|
|
38
|
-
│
|
|
39
|
-
├─ package.json
|
|
40
|
-
├─ tsconfig.json
|
|
41
|
-
├─ tsup.config.ts
|
|
42
|
-
└─ README.md
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## 技术栈
|
|
46
|
-
|
|
47
|
-
- **语言**: TypeScript
|
|
48
|
-
- **运行时**: Node.js 18+
|
|
49
|
-
- **CLI 框架**: [commander](https://www.npmjs.com/package/commander)
|
|
50
|
-
- **打包工具**: [tsup](https://www.npmjs.com/package/tsup)
|
|
51
|
-
- **AI 引擎**: [Cursor CLI](https://cursor.com/cn/docs/cli/headless)
|
|
7
|
+
`review-mark` 旨在提供一个自动化 AI 代码审查解决方案。用户可以在自己的项目中初始化该工具后,通过简单的 CLI 命令自动获取 `git diff`,并将其发送给 AI 进行代码审查,从而帮助开发者发现潜在的 bug、逻辑问题、性能问题和代码风格问题,并获得优化建议。
|
|
52
8
|
|
|
53
9
|
## 安装
|
|
54
10
|
|
|
55
|
-
首先,在你的项目根目录安装 `
|
|
11
|
+
首先,在你的项目根目录安装 `review-mark` 作为开发依赖:
|
|
56
12
|
|
|
57
13
|
```bash
|
|
58
|
-
pnpm add -D
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
# 或者
|
|
62
|
-
npm install -D be-link-review
|
|
14
|
+
pnpm add -D review-mark
|
|
15
|
+
yarn add --dev review-mark
|
|
16
|
+
npm install --save-dev review-mark
|
|
63
17
|
```
|
|
64
18
|
|
|
65
19
|
## 使用
|
|
66
20
|
|
|
67
21
|
### 1. 初始化
|
|
68
22
|
|
|
69
|
-
在你的项目入口文件(例如 `src/main.ts` 或 `app.ts`)中,调用 `BeLinkReview.init()` 方法进行初始化。你需要提供一个 `apiKey`,这将用于 Cursor CLI 的认证。
|
|
70
|
-
|
|
71
|
-
```typescript
|
|
72
|
-
// src/main.ts (或你的项目入口文件)
|
|
73
|
-
import { BeLinkReview } from "be-link-review";
|
|
74
|
-
|
|
75
|
-
BeLinkReview.init({
|
|
76
|
-
apiKey: process.env.CURSOR_API_KEY || "YOUR_CURSOR_API_KEY", // 建议从环境变量获取
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
// 你可以在这里继续你的应用逻辑
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
`BeLinkReview.init()` 会自动检测并向你的 `package.json` 文件中添加一个 `review` 脚本:
|
|
83
|
-
|
|
84
23
|
```json
|
|
85
24
|
// package.json
|
|
86
25
|
{
|
|
87
26
|
"scripts": {
|
|
88
|
-
"review": "
|
|
27
|
+
"review-mark": "CURSOR_API_KEY=your-api-key review-mark"
|
|
89
28
|
}
|
|
90
29
|
}
|
|
91
30
|
```
|
|
@@ -97,7 +36,7 @@ BeLinkReview.init({
|
|
|
97
36
|
初始化完成后,你可以在项目根目录执行以下命令来运行 AI 代码审查:
|
|
98
37
|
|
|
99
38
|
```bash
|
|
100
|
-
pnpm run review
|
|
39
|
+
pnpm run review-mark
|
|
101
40
|
```
|
|
102
41
|
|
|
103
42
|
CLI 将会执行以下步骤:
|
|
@@ -111,8 +50,8 @@ CLI 将会执行以下步骤:
|
|
|
111
50
|
#### CLI 输出示例
|
|
112
51
|
|
|
113
52
|
```
|
|
114
|
-
[
|
|
115
|
-
[
|
|
53
|
+
[review-mark] Getting git diff...
|
|
54
|
+
[review-mark] Sending to AI...
|
|
116
55
|
===== AI Review =====
|
|
117
56
|
(这里是 AI 返回结果)
|
|
118
57
|
```
|
|
@@ -120,33 +59,17 @@ CLI 将会执行以下步骤:
|
|
|
120
59
|
如果检测到没有代码变更,则会输出:
|
|
121
60
|
|
|
122
61
|
```
|
|
123
|
-
[
|
|
62
|
+
[review-mark] No code changes detected
|
|
124
63
|
```
|
|
125
64
|
|
|
126
|
-
## 配置
|
|
127
|
-
|
|
128
|
-
### 基础配置
|
|
129
|
-
|
|
130
|
-
`BeLinkReview.init()` 接受一个配置对象:
|
|
131
|
-
|
|
132
|
-
```typescript
|
|
133
|
-
interface BeLinkReviewOptions {
|
|
134
|
-
apiKey?: string; // 你的 Cursor API Key
|
|
135
|
-
agentPath?: string; // Cursor CLI agent 可执行文件路径
|
|
136
|
-
ignore?: string[]; // 需要忽略的文件模式
|
|
137
|
-
feishu?: FeiShuConfig; // 飞书机器人配置
|
|
138
|
-
}
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
建议将 `apiKey` 作为环境变量 `CURSOR_API_KEY` 进行管理,以避免将其硬编码到代码中。
|
|
142
|
-
|
|
143
65
|
### 飞书机器人集成
|
|
144
66
|
|
|
145
|
-
`
|
|
67
|
+
`review-mark` 已**完全内置**飞书机器人功能,所有飞书配置已写死在代码中,**无需任何配置即可使用**!
|
|
146
68
|
|
|
147
69
|
#### 1. 开箱即用
|
|
148
70
|
|
|
149
71
|
✅ 飞书配置已完全内置,包括:
|
|
72
|
+
|
|
150
73
|
- App ID 和 App Secret
|
|
151
74
|
- 接收者 ID (群聊/用户)
|
|
152
75
|
- 消息类型和标题
|
|
@@ -176,29 +99,6 @@ FEISHU_ENABLED=false pnpm run review
|
|
|
176
99
|
pnpm run review --no-feishu
|
|
177
100
|
```
|
|
178
101
|
|
|
179
|
-
**方式三:代码配置**
|
|
180
|
-
|
|
181
|
-
```typescript
|
|
182
|
-
BeLinkReview.init({
|
|
183
|
-
apiKey: process.env.CURSOR_API_KEY,
|
|
184
|
-
enableFeishu: false,
|
|
185
|
-
});
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
#### 3. 修改内置配置
|
|
189
|
-
|
|
190
|
-
如果需要修改飞书配置(如更换群聊、修改消息格式等),可以直接编辑 `src/constants.ts` 文件:
|
|
191
|
-
|
|
192
|
-
```typescript
|
|
193
|
-
// src/constants.ts
|
|
194
|
-
export const appId = "cli_a93822da7238dbb5";
|
|
195
|
-
export const appSecret = "ZQdcpLUHFb4gFa8cGfrlJfVfSSyGtyzF";
|
|
196
|
-
export const receiveId = "oc_482b6a04f95f4206c4fa9bc61829fd17"; // 修改为你的群聊 ID
|
|
197
|
-
export const receiveIdType = "chat_id";
|
|
198
|
-
export const messageType = "interactive"; // text | post | interactive
|
|
199
|
-
export const messageTitle = "🔍 Code Review 结果";
|
|
200
|
-
```
|
|
201
|
-
|
|
202
102
|
#### 4. 常见问题
|
|
203
103
|
|
|
204
104
|
**Q: 飞书通知会发送到哪里?**
|
|
@@ -209,6 +109,7 @@ A: 修改 `src/constants.ts` 中的 `receiveId` 为新的群聊 chat_id,然后
|
|
|
209
109
|
|
|
210
110
|
**Q: 支持哪些消息格式?**
|
|
211
111
|
A: 支持三种格式:
|
|
112
|
+
|
|
212
113
|
- `interactive` (默认): 美观的消息卡片,支持 Markdown
|
|
213
114
|
- `post`: 富文本格式
|
|
214
115
|
- `text`: 纯文本格式
|
|
@@ -216,34 +117,6 @@ A: 支持三种格式:
|
|
|
216
117
|
**Q: 如何完全禁用飞书功能?**
|
|
217
118
|
A: 使用 `--no-feishu` 参数或设置 `FEISHU_ENABLED=false` 环境变量。
|
|
218
119
|
|
|
219
|
-
## 开发
|
|
220
|
-
|
|
221
|
-
### 构建项目
|
|
222
|
-
|
|
223
|
-
```bash
|
|
224
|
-
cd be-link-review
|
|
225
|
-
pnpm install
|
|
226
|
-
pnpm run build
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
这将使用 `tsup` 将 TypeScript 代码编译为 `dist/index.js` (ESM) 和 `dist/index.cjs` (CommonJS)。
|
|
230
|
-
|
|
231
|
-
### 运行 CLI (开发模式)
|
|
232
|
-
|
|
233
|
-
```bash
|
|
234
|
-
pnpm run start
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
这将直接运行 `dist/cli/review.js`。
|
|
238
|
-
|
|
239
120
|
## 贡献
|
|
240
121
|
|
|
241
122
|
欢迎提交 Issue 或 Pull Request。
|
|
242
|
-
|
|
243
|
-
## 许可证
|
|
244
|
-
|
|
245
|
-
ISC License
|
|
246
|
-
|
|
247
|
-
---
|
|
248
|
-
|
|
249
|
-
**Manus AI** 生成
|
package/dist/cli/review.cjs
CHANGED
|
@@ -38,13 +38,42 @@ var import_node_fs = require("fs");
|
|
|
38
38
|
var import_node_os = require("os");
|
|
39
39
|
var import_node_path = require("path");
|
|
40
40
|
var execAsync = (0, import_node_util.promisify)(import_node_child_process.exec);
|
|
41
|
+
var LOCAL_BIN = (0, import_node_path.join)((0, import_node_os.homedir)(), ".local", "bin");
|
|
41
42
|
var COMMON_AGENT_PATHS = [
|
|
43
|
+
(0, import_node_path.join)(LOCAL_BIN, "agent"),
|
|
44
|
+
// Cursor 官方安装脚本默认路径
|
|
42
45
|
(0, import_node_path.join)((0, import_node_os.homedir)(), ".cursor", "agent"),
|
|
43
46
|
"/usr/local/bin/agent",
|
|
44
|
-
// macOS Homebrew 或手动安装的常见路径
|
|
45
47
|
"/opt/homebrew/bin/agent"
|
|
46
|
-
// macOS Apple Silicon Homebrew 路径
|
|
47
48
|
];
|
|
49
|
+
function setupLocalBinPath(silent) {
|
|
50
|
+
if (!process.env.PATH?.includes(LOCAL_BIN)) {
|
|
51
|
+
process.env.PATH = `${LOCAL_BIN}:${process.env.PATH}`;
|
|
52
|
+
}
|
|
53
|
+
const exportLine = `
|
|
54
|
+
export PATH="$HOME/.local/bin:$PATH"`;
|
|
55
|
+
const shell = process.env.SHELL ?? "";
|
|
56
|
+
const rcFiles = [];
|
|
57
|
+
if (shell.includes("zsh")) {
|
|
58
|
+
rcFiles.push((0, import_node_path.join)((0, import_node_os.homedir)(), ".zshrc"));
|
|
59
|
+
} else if (shell.includes("bash")) {
|
|
60
|
+
rcFiles.push((0, import_node_path.join)((0, import_node_os.homedir)(), ".bashrc"));
|
|
61
|
+
} else {
|
|
62
|
+
rcFiles.push((0, import_node_path.join)((0, import_node_os.homedir)(), ".zshrc"), (0, import_node_path.join)((0, import_node_os.homedir)(), ".bashrc"));
|
|
63
|
+
}
|
|
64
|
+
for (const rc of rcFiles) {
|
|
65
|
+
try {
|
|
66
|
+
const content = (0, import_node_fs.existsSync)(rc) ? require("fs").readFileSync(rc, "utf-8") : "";
|
|
67
|
+
if (!content.includes(".local/bin")) {
|
|
68
|
+
(0, import_node_fs.appendFileSync)(rc, exportLine);
|
|
69
|
+
if (!silent) {
|
|
70
|
+
console.log(`[review-mark] \u5DF2\u5C06 ~/.local/bin \u5199\u5165 ${rc}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
} catch {
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
48
77
|
async function findAgentExecutable(userAgentPath) {
|
|
49
78
|
if (userAgentPath && (0, import_node_fs.existsSync)(userAgentPath)) {
|
|
50
79
|
return userAgentPath;
|
|
@@ -70,15 +99,15 @@ async function isCheckCliInstall(options) {
|
|
|
70
99
|
if (actualAgentPath) {
|
|
71
100
|
if (!silent) {
|
|
72
101
|
console.log(
|
|
73
|
-
`[
|
|
102
|
+
`[review-mark] Cursor CLI (agent) \u5DF2\u5728 ${actualAgentPath} \u627E\u5230\u3002`
|
|
74
103
|
);
|
|
75
104
|
}
|
|
76
105
|
return { isInstalled: true, message: "Cursor CLI \u5DF2\u5B89\u88C5", actualAgentPath };
|
|
77
106
|
}
|
|
78
107
|
if (!silent) {
|
|
79
|
-
console.log("[
|
|
108
|
+
console.log("[review-mark] Cursor CLI (agent) \u672A\u627E\u5230\uFF0C\u6B63\u5728\u5C1D\u8BD5\u5B89\u88C5...");
|
|
80
109
|
console.log(
|
|
81
|
-
"[
|
|
110
|
+
"[review-mark] \u6267\u884C\u5B89\u88C5\u547D\u4EE4: curl https://cursor.com/install -fsS | bash"
|
|
82
111
|
);
|
|
83
112
|
}
|
|
84
113
|
return new Promise((resolve, reject) => {
|
|
@@ -92,10 +121,11 @@ async function isCheckCliInstall(options) {
|
|
|
92
121
|
);
|
|
93
122
|
installProcess.on("close", async (code) => {
|
|
94
123
|
if (code === 0) {
|
|
124
|
+
setupLocalBinPath(silent);
|
|
95
125
|
actualAgentPath = await findAgentExecutable(userAgentPath);
|
|
96
126
|
if (actualAgentPath) {
|
|
97
127
|
if (!silent) {
|
|
98
|
-
console.log("[
|
|
128
|
+
console.log("[review-mark] Cursor CLI \u5B89\u88C5\u6210\u529F\u3002");
|
|
99
129
|
}
|
|
100
130
|
resolve({
|
|
101
131
|
isInstalled: true,
|
|
@@ -105,14 +135,14 @@ async function isCheckCliInstall(options) {
|
|
|
105
135
|
} else {
|
|
106
136
|
reject(
|
|
107
137
|
new Error(
|
|
108
|
-
`[
|
|
138
|
+
`[review-mark] Cursor CLI \u5B89\u88C5\u547D\u4EE4\u6267\u884C\u6210\u529F\uFF0C\u4F46\u672A\u627E\u5230 agent \u53EF\u6267\u884C\u6587\u4EF6\u3002\u8BF7\u624B\u52A8\u68C0\u67E5\u5B89\u88C5\uFF1Acurl https://cursor.com/install -fsS | bash\u3002`
|
|
109
139
|
)
|
|
110
140
|
);
|
|
111
141
|
}
|
|
112
142
|
} else {
|
|
113
143
|
reject(
|
|
114
144
|
new Error(
|
|
115
|
-
`[
|
|
145
|
+
`[review-mark] Cursor CLI \u5B89\u88C5\u5931\u8D25\uFF0C\u9000\u51FA\u7801 ${code}\u3002\u8BF7\u624B\u52A8\u5B89\u88C5\uFF1Acurl https://cursor.com/install -fsS | bash\u3002`
|
|
116
146
|
)
|
|
117
147
|
);
|
|
118
148
|
}
|
|
@@ -120,7 +150,7 @@ async function isCheckCliInstall(options) {
|
|
|
120
150
|
installProcess.on("error", (err) => {
|
|
121
151
|
reject(
|
|
122
152
|
new Error(
|
|
123
|
-
`[
|
|
153
|
+
`[review-mark] \u65E0\u6CD5\u542F\u52A8\u5B89\u88C5\u8FDB\u7A0B\uFF1A${err.message}\u3002\u8BF7\u624B\u52A8\u5B89\u88C5\uFF1Acurl https://cursor.com/install -fsS | bash`
|
|
124
154
|
)
|
|
125
155
|
);
|
|
126
156
|
});
|
|
@@ -130,44 +160,50 @@ async function isCheckCliInstall(options) {
|
|
|
130
160
|
// src/core/git.ts
|
|
131
161
|
var import_node_child_process2 = require("child_process");
|
|
132
162
|
var import_node_util2 = require("util");
|
|
133
|
-
var
|
|
163
|
+
var execFileAsync = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
|
|
164
|
+
var FIXED_IGNORE_PATTERNS = ["package.json"];
|
|
165
|
+
async function runGit(args, cwd) {
|
|
166
|
+
const { stdout } = await execFileAsync("git", args, { cwd });
|
|
167
|
+
return stdout.trim();
|
|
168
|
+
}
|
|
134
169
|
async function getGitDiff(userIgnorePatterns = [], cwd = process.cwd()) {
|
|
135
170
|
try {
|
|
136
|
-
await
|
|
171
|
+
await runGit(["rev-parse", "--git-dir"], cwd);
|
|
137
172
|
} catch (error) {
|
|
138
|
-
console.error(`[
|
|
173
|
+
console.error(`[review-mark] \u5F53\u524D\u76EE\u5F55\u4E0D\u662F git \u4ED3\u5E93: ${cwd}`);
|
|
139
174
|
return "";
|
|
140
175
|
}
|
|
141
|
-
const allIgnorePatterns = [
|
|
142
|
-
|
|
176
|
+
const allIgnorePatterns = [
|
|
177
|
+
.../* @__PURE__ */ new Set([...FIXED_IGNORE_PATTERNS, ...userIgnorePatterns])
|
|
178
|
+
];
|
|
179
|
+
const excludeArgs = allIgnorePatterns.map((p) => `:(exclude)${p}`);
|
|
143
180
|
let diff = "";
|
|
144
|
-
const baseCommand = `git diff --no-color --relative ${excludeArgs}`;
|
|
145
181
|
try {
|
|
146
|
-
|
|
182
|
+
diff = await runGit(
|
|
183
|
+
["diff", "--no-color", "--relative", "--cached", "--", ...excludeArgs],
|
|
147
184
|
cwd
|
|
148
|
-
|
|
149
|
-
diff = cachedDiff.trim();
|
|
185
|
+
);
|
|
150
186
|
if (diff) {
|
|
151
|
-
console.log("[
|
|
187
|
+
console.log("[review-mark] \u68C0\u6D4B\u5230\u6682\u5B58\u533A\u6539\u52A8");
|
|
152
188
|
}
|
|
153
189
|
} catch (error) {
|
|
154
|
-
console.warn(`[
|
|
190
|
+
console.warn(`[review-mark] \u83B7\u53D6\u6682\u5B58\u533A diff \u5931\u8D25: ${error.message}`);
|
|
155
191
|
}
|
|
156
192
|
if (!diff) {
|
|
157
193
|
try {
|
|
158
|
-
|
|
194
|
+
diff = await runGit(
|
|
195
|
+
["diff", "--no-color", "--relative", "HEAD", "--", ...excludeArgs],
|
|
159
196
|
cwd
|
|
160
|
-
|
|
161
|
-
diff = headDiff.trim();
|
|
197
|
+
);
|
|
162
198
|
if (diff) {
|
|
163
|
-
console.log("[
|
|
199
|
+
console.log("[review-mark] \u68C0\u6D4B\u5230\u5DE5\u4F5C\u533A\u6539\u52A8\uFF08\u76F8\u5BF9\u4E8E HEAD\uFF09");
|
|
164
200
|
}
|
|
165
201
|
} catch (error) {
|
|
166
|
-
console.warn(`[
|
|
202
|
+
console.warn(`[review-mark] \u83B7\u53D6\u5DE5\u4F5C\u533A diff \u5931\u8D25: ${error.message}`);
|
|
167
203
|
}
|
|
168
204
|
}
|
|
169
205
|
if (!diff) {
|
|
170
|
-
console.log("[
|
|
206
|
+
console.log("[review-mark] \u672A\u68C0\u6D4B\u5230\u4EE3\u7801\u6539\u52A8\uFF08\u5DF2\u68C0\u67E5\u6682\u5B58\u533A\u548C\u5DE5\u4F5C\u533A\uFF09");
|
|
171
207
|
}
|
|
172
208
|
return diff;
|
|
173
209
|
}
|
|
@@ -198,8 +234,8 @@ var messageTitle = "\u{1F50D} Code Review \u7ED3\u679C";
|
|
|
198
234
|
|
|
199
235
|
// src/core/feishu.ts
|
|
200
236
|
async function sendReviewToFeishu(reviewContent) {
|
|
201
|
-
console.log("[
|
|
202
|
-
console.log(`[
|
|
237
|
+
console.log("[review-mark] \u6B63\u5728\u53D1\u9001\u6D88\u606F\u5230\u98DE\u4E66...");
|
|
238
|
+
console.log(`[review-mark] \u6D88\u606F\u7C7B\u578B: ${messageType}`);
|
|
203
239
|
try {
|
|
204
240
|
const client = new lark.Client({
|
|
205
241
|
appId,
|
|
@@ -261,9 +297,9 @@ ${reviewContent}`
|
|
|
261
297
|
});
|
|
262
298
|
msgType = "text";
|
|
263
299
|
} else {
|
|
264
|
-
throw new Error(`[
|
|
300
|
+
throw new Error(`[review-mark] \u4E0D\u652F\u6301\u7684\u6D88\u606F\u7C7B\u578B: ${messageType}`);
|
|
265
301
|
}
|
|
266
|
-
console.log(`[
|
|
302
|
+
console.log(`[review-mark] \u53D1\u9001\u53C2\u6570:`);
|
|
267
303
|
console.log(` - receive_id_type: ${receiveIdType}`);
|
|
268
304
|
console.log(` - receive_id: ${receiveId}`);
|
|
269
305
|
console.log(` - msg_type: ${msgType}`);
|
|
@@ -279,13 +315,15 @@ ${reviewContent}`
|
|
|
279
315
|
});
|
|
280
316
|
if (response.code !== 0) {
|
|
281
317
|
throw new Error(
|
|
282
|
-
`[
|
|
318
|
+
`[review-mark] \u98DE\u4E66 API \u8FD4\u56DE\u9519\u8BEF: ${response.msg || "\u672A\u77E5\u9519\u8BEF"}`
|
|
283
319
|
);
|
|
284
320
|
}
|
|
285
|
-
console.log("[
|
|
286
|
-
console.log(
|
|
321
|
+
console.log("[review-mark] \u2705 \u98DE\u4E66\u6D88\u606F\u53D1\u9001\u6210\u529F");
|
|
322
|
+
console.log(
|
|
323
|
+
`[review-mark] \u6D88\u606F ID: ${response.data?.message_id || "\u672A\u77E5"}`
|
|
324
|
+
);
|
|
287
325
|
} catch (error) {
|
|
288
|
-
console.error(`[
|
|
326
|
+
console.error(`[review-mark] \u274C \u98DE\u4E66\u6D88\u606F\u53D1\u9001\u5931\u8D25: ${error.message}`);
|
|
289
327
|
throw error;
|
|
290
328
|
}
|
|
291
329
|
}
|
|
@@ -460,7 +498,7 @@ var BeLinkReview = class _BeLinkReview {
|
|
|
460
498
|
const enableFeishu = cliEnableFeishu ?? process.env.FEISHU_ENABLED !== "false";
|
|
461
499
|
if (!apiKey) {
|
|
462
500
|
throw new Error(
|
|
463
|
-
'[
|
|
501
|
+
'[review-mark] \u8BF7\u5148\u8C03\u7528 BeLinkReview.init({ apiKey: "..." }) \u521D\u59CB\u5316\uFF0C\u6216\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF CURSOR_API_KEY\uFF0C\u6216\u901A\u8FC7\u547D\u4EE4\u884C\u53C2\u6570 --apiKey \u4F20\u5165\u3002'
|
|
464
502
|
);
|
|
465
503
|
}
|
|
466
504
|
_BeLinkReview.#instance = new _BeLinkReview(
|
|
@@ -489,7 +527,7 @@ var BeLinkReview = class _BeLinkReview {
|
|
|
489
527
|
const apiKey = this.#apiKey || process.env.CURSOR_API_KEY;
|
|
490
528
|
if (!apiKey) {
|
|
491
529
|
throw new Error(
|
|
492
|
-
'[
|
|
530
|
+
'[review-mark] \u8BF7\u5148\u5728 init({ apiKey: "..." }) \u4E2D\u4F20\u5165 apiKey\uFF0C\u6216\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF CURSOR_API_KEY\uFF0C\u6216\u901A\u8FC7\u547D\u4EE4\u884C\u53C2\u6570 --apiKey \u4F20\u5165\u3002'
|
|
493
531
|
);
|
|
494
532
|
}
|
|
495
533
|
return apiKey;
|
|
@@ -514,17 +552,17 @@ var BeLinkReview = class _BeLinkReview {
|
|
|
514
552
|
if (!packageJson.scripts) {
|
|
515
553
|
packageJson.scripts = {};
|
|
516
554
|
}
|
|
517
|
-
if (!packageJson.scripts
|
|
518
|
-
packageJson.scripts
|
|
555
|
+
if (!packageJson.scripts["review-mark"]) {
|
|
556
|
+
packageJson.scripts["review-mark"] = "review-mark";
|
|
519
557
|
(0, import_node_fs2.writeFileSync)(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
520
558
|
console.log(
|
|
521
|
-
"[
|
|
559
|
+
"[review-mark] \u5DF2\u5728 package.json \u4E2D\u6DFB\u52A0 'review-mark' \u811A\u672C\u3002"
|
|
522
560
|
);
|
|
523
561
|
} else {
|
|
524
|
-
console.log("[
|
|
562
|
+
console.log("[review-mark] 'review-mark' \u811A\u672C\u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u6DFB\u52A0\u3002");
|
|
525
563
|
}
|
|
526
564
|
} catch (error) {
|
|
527
|
-
console.error("[
|
|
565
|
+
console.error("[review-mark] \u65E0\u6CD5\u66F4\u65B0 package.json: ", error);
|
|
528
566
|
}
|
|
529
567
|
}
|
|
530
568
|
/**
|
|
@@ -537,17 +575,17 @@ var BeLinkReview = class _BeLinkReview {
|
|
|
537
575
|
const ensureResult = await this.ensureAgentInstalled(false, agentPath);
|
|
538
576
|
if (!ensureResult.isInstalled) {
|
|
539
577
|
throw new Error(
|
|
540
|
-
"[
|
|
578
|
+
"[review-mark] Cursor CLI \u672A\u5B89\u88C5\u4E14\u81EA\u52A8\u5B89\u88C5\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u5B89\u88C5\u3002"
|
|
541
579
|
);
|
|
542
580
|
}
|
|
543
|
-
console.log("[
|
|
581
|
+
console.log("[review-mark] Getting git diff...");
|
|
544
582
|
const diff = await getGitDiff(ignorePatterns, process.cwd());
|
|
545
583
|
if (!diff) {
|
|
546
|
-
console.log("[
|
|
584
|
+
console.log("[review-mark] No code changes detected");
|
|
547
585
|
return "No code changes detected";
|
|
548
586
|
}
|
|
549
587
|
const prompt = generateAIPrompt(diff);
|
|
550
|
-
console.log("[
|
|
588
|
+
console.log("[review-mark] Sending to AI...");
|
|
551
589
|
const response = await this.chat(prompt, {
|
|
552
590
|
agentPath: ensureResult.actualAgentPath,
|
|
553
591
|
force: true
|
|
@@ -559,7 +597,7 @@ var BeLinkReview = class _BeLinkReview {
|
|
|
559
597
|
await sendReviewToFeishu(response);
|
|
560
598
|
} catch (error) {
|
|
561
599
|
console.error(
|
|
562
|
-
`[
|
|
600
|
+
`[review-mark] \u98DE\u4E66\u901A\u77E5\u53D1\u9001\u5931\u8D25\uFF0C\u4F46\u4E0D\u5F71\u54CD review \u7ED3\u679C: ${error.message}`
|
|
563
601
|
);
|
|
564
602
|
}
|
|
565
603
|
}
|
|
@@ -601,7 +639,7 @@ var BeLinkReview = class _BeLinkReview {
|
|
|
601
639
|
proc.on("error", (err) => {
|
|
602
640
|
reject(
|
|
603
641
|
new Error(
|
|
604
|
-
`[
|
|
642
|
+
`[review-mark] \u65E0\u6CD5\u542F\u52A8 Cursor CLI (${actualAgentPath})\uFF0C\u8BF7\u5148\u5B89\u88C5\uFF1Acurl https://cursor.com/install -fsS | bash\u3002\u539F\u59CB\u9519\u8BEF: ${err.message}`
|
|
605
643
|
)
|
|
606
644
|
);
|
|
607
645
|
});
|
|
@@ -609,7 +647,7 @@ var BeLinkReview = class _BeLinkReview {
|
|
|
609
647
|
if (code !== 0) {
|
|
610
648
|
reject(
|
|
611
649
|
new Error(
|
|
612
|
-
`[
|
|
650
|
+
`[review-mark] agent \u9000\u51FA\u7801 ${code}${stderr ? `: ${stderr.trim()}` : ""}`
|
|
613
651
|
)
|
|
614
652
|
);
|
|
615
653
|
return;
|
|
@@ -622,7 +660,7 @@ var BeLinkReview = class _BeLinkReview {
|
|
|
622
660
|
|
|
623
661
|
// src/cli/review.ts
|
|
624
662
|
var program = new import_commander.Command();
|
|
625
|
-
program.name("
|
|
663
|
+
program.name("review-mark").description("AI-powered code review tool").version("1.0.0").option(
|
|
626
664
|
"--apiKey <key>",
|
|
627
665
|
"Cursor API Key (overrides CURSOR_API_KEY environment variable)"
|
|
628
666
|
).option(
|
|
@@ -660,7 +698,7 @@ program.name("belink-review").description("AI-powered code review tool").version
|
|
|
660
698
|
);
|
|
661
699
|
await instance.goCli();
|
|
662
700
|
} catch (error) {
|
|
663
|
-
console.error(`[
|
|
701
|
+
console.error(`[review-mark] Error: ${error.message}`);
|
|
664
702
|
process.exit(1);
|
|
665
703
|
}
|
|
666
704
|
});
|
|
@@ -702,7 +740,7 @@ program.command("review").description("Perform an AI code review on git diff").o
|
|
|
702
740
|
);
|
|
703
741
|
await instance.goCli();
|
|
704
742
|
} catch (error) {
|
|
705
|
-
console.error(`[
|
|
743
|
+
console.error(`[review-mark] Error: ${error.message}`);
|
|
706
744
|
process.exit(1);
|
|
707
745
|
}
|
|
708
746
|
});
|