@d5render/cli 0.1.18 → 0.1.24

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/d5cli CHANGED
@@ -7,15 +7,143 @@ import { fileURLToPath } from "node:url";
7
7
 
8
8
  //#region package.json
9
9
  var name$1 = "@d5render/cli";
10
- var version = "0.1.18";
10
+ var version = "0.1.24";
11
+
12
+ //#endregion
13
+ //#region packages/gitlab/url.ts
14
+ function buildHeaders() {
15
+ const headers = new Headers();
16
+ headers.set("Content-Type", "application/json");
17
+ const { GITLAB_TOKEN = "" } = envUsed;
18
+ if (GITLAB_TOKEN.startsWith("glpat-")) headers.set("PRIVATE-TOKEN", GITLAB_TOKEN);
19
+ else headers.set("Authorization", `Bearer ${GITLAB_TOKEN}`);
20
+ return headers;
21
+ }
22
+ const visitCommit = () => {
23
+ const { CI_PROJECT_PATH, CI_SERVER_URL } = envUsed;
24
+ if (CI_PROJECT_PATH && CI_SERVER_URL) return `${CI_SERVER_URL}/${CI_PROJECT_PATH}/-/commit`;
25
+ };
26
+ function visitPipeline(mid) {
27
+ const { CI_SERVER_URL, CI_PROJECT_PATH, CI_MERGE_REQUEST_IID = mid, CI_COMMIT_SHA } = envUsed;
28
+ if (!CI_SERVER_URL || !CI_PROJECT_PATH) return {};
29
+ if (CI_MERGE_REQUEST_IID) return {
30
+ url: `${CI_SERVER_URL}/${CI_PROJECT_PATH}/-/merge_requests/${CI_MERGE_REQUEST_IID}`,
31
+ type: "merge_request"
32
+ };
33
+ if (CI_COMMIT_SHA) return {
34
+ url: `${visitCommit()}/${CI_COMMIT_SHA}`,
35
+ type: "commit"
36
+ };
37
+ return {};
38
+ }
39
+ const commits = () => {
40
+ const { CI_PROJECT_ID, CI_SERVER_URL } = envUsed;
41
+ if (CI_PROJECT_ID && CI_SERVER_URL) return `${CI_SERVER_URL}/api/v4/projects/${CI_PROJECT_ID}/repository/commits`;
42
+ };
43
+
44
+ //#endregion
45
+ //#region packages/message/sendding.ts
46
+ async function sendding(title, text) {
47
+ if (!envUsed.DINGTALK_WEBHOOK) throw new Error("non DINGTALK_WEBHOOK");
48
+ let res = new Response();
49
+ for (const url of envUsed.DINGTALK_WEBHOOK.split(",")) res = await fetch(url, {
50
+ method: "POST",
51
+ headers: { "Content-Type": "application/json" },
52
+ body: JSON.stringify({
53
+ msgtype: "markdown",
54
+ markdown: {
55
+ title,
56
+ text
57
+ },
58
+ at: {
59
+ atMobiles: ["17856104313"],
60
+ isAtAll: false
61
+ }
62
+ })
63
+ });
64
+ return res;
65
+ }
66
+
67
+ //#endregion
68
+ //#region copilot/bin/utils.ts
69
+ const NAME = name$1.replaceAll("/", "_");
70
+ const VERSION = version;
71
+ const RUNTIME_CWD = join(dirname(fileURLToPath(import.meta.url)), "../");
72
+ const HOME = env.USERPROFILE ?? env.HOME ?? env.HOMEPATH;
73
+ if (!HOME) throw new Error("cannot find `USERPROFILE` directory");
74
+ const TEMP = env.CI_PROJECT_DIR + NAME;
75
+ function deploy() {
76
+ if (!env.CI) return;
77
+ const config = join(HOME, ".copilot/config.json"), dir = join(HOME, ".copilot/skills/codereview");
78
+ console.log("deploy...");
79
+ if (existsSync(config)) {
80
+ rmSync(config);
81
+ console.log("removed config cache.");
82
+ }
83
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
84
+ const versiono = readFileSync(join(RUNTIME_CWD, ".skills/review/version"), "utf8");
85
+ const versionnPath = join(dir, "version");
86
+ if ((existsSync(versionnPath) ? readFileSync(versionnPath, "utf8") : "") === versiono) return;
87
+ const skillRoot = join(RUNTIME_CWD, ".skills/review");
88
+ readdirSync(skillRoot).forEach((skill) => copyFileSync(join(skillRoot, skill), join(dir, skill)));
89
+ const instructionsRoot = join(RUNTIME_CWD, ".github/instructions");
90
+ readdirSync(instructionsRoot).forEach((instruction) => copyFileSync(join(instructionsRoot, instruction), join(dir, instruction)));
91
+ console.log("to new skill.");
92
+ const changelog = readFileSync(join(RUNTIME_CWD, "CHANGELOG.md"), "utf8");
93
+ const cachepath = join(TEMP, "CHANGELOG");
94
+ if (!existsSync(TEMP)) mkdirSync(TEMP, { recursive: true });
95
+ if (changelog !== (existsSync(cachepath) ? readFileSync(cachepath, "utf8") : "")) {
96
+ if (!existsSync(cachepath)) mkdirSync(cachepath, { recursive: true });
97
+ writeFileSync(cachepath, changelog, "utf8");
98
+ console.log("updated CHANGELOG cache.");
99
+ sendding("NOTICE", `NOTICE: codereview skills has been updated to version ${versiono}\n\nfor more details, please refer to [ONLINE](https://www.npmjs.com/package/@d5render/cli?activeTab=readme)`);
100
+ }
101
+ }
102
+ function need() {
103
+ if (!env.CI) return;
104
+ if (!existsSync(TEMP)) mkdirSync(TEMP, { recursive: true });
105
+ const { CI_MERGE_REQUEST_IID, CI_COMMIT_SHA } = env;
106
+ const file$1 = join(TEMP, "CODEREVIEW");
107
+ if (CI_MERGE_REQUEST_IID) {
108
+ let appended = `${existsSync(file$1) ? readFileSync(file$1, "utf8") : ""}\n${CI_MERGE_REQUEST_IID}`.split("\n");
109
+ const max = 1e4;
110
+ if (appended.length > max) appended = appended.slice(-max);
111
+ writeFileSync(file$1, appended.join("\n"), "utf8");
112
+ console.log("merge pipeline, recorded IID:", CI_MERGE_REQUEST_IID, "to:", file$1);
113
+ return true;
114
+ }
115
+ if (!CI_COMMIT_SHA) return true;
116
+ console.log("commit pipeline");
117
+ const match = execSync(`git log -1 --format=%B ${CI_COMMIT_SHA}`, {
118
+ cwd: env.CI_PROJECT_DIR,
119
+ encoding: "utf8"
120
+ }).toString().match(/See merge request[\s\S]+!(\d+)/);
121
+ if (!match) return true;
122
+ const iid = match[1];
123
+ const yes = (existsSync(file$1) ? readFileSync(file$1, "utf8") : "").split("\n").includes(iid);
124
+ if (yes) {
125
+ console.warn(`Merge Request !${iid} has been AI reviewed before.`);
126
+ const mergeURL = visitPipeline(iid).url;
127
+ const url = `${commits()}/${CI_COMMIT_SHA}/comments`;
128
+ fetch(url, {
129
+ method: "POST",
130
+ headers: buildHeaders(),
131
+ body: JSON.stringify({
132
+ note: `请查看管道评论:${mergeURL}#note`,
133
+ line_type: "new"
134
+ })
135
+ }).then((res) => res.text());
136
+ }
137
+ return !yes;
138
+ }
11
139
 
12
140
  //#endregion
13
141
  //#region copilot/server/config.ts
14
142
  const name = "d5_mcp_review_builtin";
15
143
  const report = "report";
16
144
  const getHash = "hash";
17
- const file = "./copilot.js";
18
- const serveFile = join(dirname(fileURLToPath(import.meta.url)), file);
145
+ const file = "bin/copilot.js";
146
+ const serveFile = join(RUNTIME_CWD, file);
19
147
  const envJson = buildEnv();
20
148
  const envUsed = {
21
149
  CI_SERVER_URL: toEnv("CI_SERVER_URL"),
@@ -109,99 +237,22 @@ function installCopilot() {
109
237
  }
110
238
 
111
239
  //#endregion
112
- //#region packages/gitlab/url.ts
113
- function buildHeaders() {
114
- const headers = new Headers();
115
- headers.set("Content-Type", "application/json");
116
- const { GITLAB_TOKEN = "" } = envUsed;
117
- if (GITLAB_TOKEN.startsWith("glpat-")) headers.set("PRIVATE-TOKEN", GITLAB_TOKEN);
118
- else headers.set("Authorization", `Bearer ${GITLAB_TOKEN}`);
119
- return headers;
120
- }
121
- const visitCommit = () => {
122
- const { CI_PROJECT_PATH, CI_SERVER_URL } = envUsed;
123
- if (CI_PROJECT_PATH && CI_SERVER_URL) return `${CI_SERVER_URL}/${CI_PROJECT_PATH}/-/commit`;
124
- };
125
- function visitPipeline(mid) {
126
- const { CI_SERVER_URL, CI_PROJECT_PATH, CI_MERGE_REQUEST_IID = mid, CI_COMMIT_SHA } = envUsed;
127
- if (!CI_SERVER_URL || !CI_PROJECT_PATH) return {};
128
- if (CI_MERGE_REQUEST_IID) return {
129
- url: `${CI_SERVER_URL}/${CI_PROJECT_PATH}/-/merge_requests/${CI_MERGE_REQUEST_IID}`,
130
- type: "merge_request"
131
- };
132
- if (CI_COMMIT_SHA) return {
133
- url: `${visitCommit()}/${CI_COMMIT_SHA}`,
134
- type: "commit"
135
- };
136
- return {};
137
- }
138
- const commits = () => {
139
- const { CI_PROJECT_ID, CI_SERVER_URL } = envUsed;
140
- if (CI_PROJECT_ID && CI_SERVER_URL) return `${CI_SERVER_URL}/api/v4/projects/${CI_PROJECT_ID}/repository/commits`;
141
- };
142
-
143
- //#endregion
144
- //#region copilot/bin/utils.ts
145
- const HOME = env.HOME ?? env.HOMEPATH;
146
- const root = HOME ?? env.LOCALAPPDATA;
147
- if (!root) throw new Error("cannot find home directory");
148
- const cwd = join(dirname(fileURLToPath(import.meta.url)), "../");
149
- function deploy() {
150
- const config = join(HOME, ".copilot/config.json");
151
- if (existsSync(config)) rmSync(config);
152
- const dir = join(root, ".copilot/skills/codereview");
153
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
154
- const skillRoot = join(cwd, ".skills/review");
155
- const versiono = readFileSync(join(cwd, ".skills/review/version"), "utf8");
156
- const versionnPath = join(dir, "version");
157
- if ((existsSync(versionnPath) ? readFileSync(versionnPath, "utf8") : "") === versiono) return;
158
- readdirSync(skillRoot).forEach((skill) => copyFileSync(join(skillRoot, skill), join(dir, skill)));
159
- const instructionsRoot = join(cwd, ".github/instructions");
160
- readdirSync(instructionsRoot).forEach((instruction) => copyFileSync(join(instructionsRoot, instruction), join(dir, instruction)));
240
+ //#region copilot/bin/index.ts
241
+ try {
242
+ codereview();
243
+ } catch (error) {
244
+ sendding("CRITICAL", "CRITICAL CI ERROR: 未知错误,请自行检查日志");
245
+ throw error;
161
246
  }
162
- function need() {
163
- const { CI_MERGE_REQUEST_IID, CI_COMMIT_SHA, CI_PROJECT_PATH } = env;
164
- const file$1 = join(root, ".ci-ai-review", CI_PROJECT_PATH || "defaults");
165
- const dir = dirname(file$1);
166
- if (CI_MERGE_REQUEST_IID) {
167
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
168
- let appended = `${existsSync(file$1) ? readFileSync(file$1, "utf8") : ""}\n${CI_MERGE_REQUEST_IID}`.split("\n");
169
- const max = 5;
170
- if (appended.length > max) appended = appended.slice(-max);
171
- writeFileSync(file$1, appended.join("\n"), "utf8");
172
- return true;
247
+ function codereview() {
248
+ deploy();
249
+ if (!need()) {
250
+ console.log("重复提交,进程跳过");
251
+ return;
173
252
  }
174
- if (!CI_COMMIT_SHA) return true;
175
- const match = execSync(`git log -1 --format=%B ${CI_COMMIT_SHA}`, {
176
- cwd: env.CI_PROJECT_DIR,
177
- encoding: "utf8"
178
- }).toString().match(/See merge request[\s\S]+!(\d+)/);
179
- if (!match) return true;
180
- const iid = match[1];
181
- const yes = (existsSync(file$1) ? readFileSync(file$1, "utf8") : "").split("\n").includes(iid);
182
- if (yes) {
183
- console.warn(`Merge Request !${iid} has been AI reviewed before.`);
184
- const mergeURL = visitPipeline(iid).url;
185
- const url = `${commits()}/${CI_COMMIT_SHA}/comments`;
186
- fetch(url, {
187
- method: "POST",
188
- headers: buildHeaders(),
189
- body: JSON.stringify({
190
- note: `请查看管道评论:${mergeURL}#note`,
191
- line_type: "new"
192
- })
193
- }).then((res) => res.text());
194
- }
195
- return !yes;
196
- }
197
-
198
- //#endregion
199
- //#region copilot/bin/index.ts
200
- const prompt = `Load skills, then call the mcp tool '${name}-${getHash}' to load code-review commits, if the task encounters an error, throw that.
201
- Otherwise, use chinese as default language to call the mcp tool '${name}-${report}'`;
202
- deploy();
203
- if (need()) {
204
253
  install();
254
+ const prompt = `Load skills, then call the mcp tool '${name}-${getHash}' to load code-review commits, if the task encounters an error, throw that.
255
+ Otherwise, use chinese as default language to call the mcp tool '${name}-${report}'`;
205
256
  const copilot = spawn("node", [
206
257
  findCopilopt(),
207
258
  ...tools,
@@ -220,8 +271,11 @@ if (need()) {
220
271
  });
221
272
  copilot.stdout.on("data", (chunk) => console.log(String(chunk)));
222
273
  copilot.stderr.on("data", (chunk) => console.error(String(chunk)));
223
- copilot.on("close", (code) => exit(code));
224
- } else console.log("重复提交,进程跳过");
274
+ copilot.on("close", (code) => {
275
+ sendding("CRITICAL", "CRITICAL CI ERROR: 代码审查任务失败,请自行检查日志");
276
+ exit(code);
277
+ });
278
+ }
225
279
  function findCopilopt() {
226
280
  let copilot = execSync("npm list @github/copilot -g -p").toString().trim();
227
281
  if (!copilot) {
@@ -238,8 +292,8 @@ function findCopilopt() {
238
292
  if (!binPath) throw new Error("non copilot executable found");
239
293
  const copilotVersion = copilotPackage.version || "unknown";
240
294
  const copilotPath = join(copilot, binPath);
241
- console.log(`${name$1} server:
242
- version: ${version}
295
+ console.log(`${NAME} server:
296
+ version: ${VERSION}
243
297
  path: ${serveFile}
244
298
  copilot:
245
299
  version: ${copilotVersion}
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "license": "MIT",
5
5
  "author": "jasirou",
6
6
  "main": "./bin/d5cli",
7
- "version": "0.1.18",
7
+ "version": "0.1.24",
8
8
  "devDependencies": {
9
9
  "@modelcontextprotocol/sdk": "^1.25.1",
10
10
  "@types/node": "^25.0.3",
@@ -18,16 +18,18 @@
18
18
  "files": [
19
19
  ".github/instructions/review.instructions.md",
20
20
  ".github/instructions/severity.instructions.md",
21
+ ".skills/devops",
21
22
  ".skills/review",
22
23
  "bin/copilot.js",
23
- "bin/d5cli"
24
+ "bin/d5cli",
25
+ "CHANGELOG.md"
24
26
  ],
25
27
  "bin": {
26
28
  "d5cli": "bin/d5cli"
27
29
  },
28
30
  "scripts": {
29
31
  "build:copilot": "node ./setup.js build",
30
- "setup": "node ./setup.js",
31
- "release": "node ./setup.js publish"
32
+ "release": "node ./setup.js publish",
33
+ "setup": "node ./setup.js"
32
34
  }
33
35
  }