@d5render/cli 0.1.31 → 0.1.33

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 CHANGED
@@ -1,3 +1,3 @@
1
- for devops, [please refer](.skills/devops)
1
+ for devops, please refer [.skills/devops](.skills/devops)
2
2
 
3
- for codereview, [please refer](.skills/review/SKILL.md)
3
+ for codereview, please refer[.skills/review/SKILL.md](.skills/review/SKILL.md)
package/bin/copilot.js CHANGED
@@ -18872,7 +18872,7 @@ const NAME = name$1.replaceAll("/", "_");
18872
18872
  const RUNTIME_CWD = join(dirname(fileURLToPath(import.meta.url)), "../");
18873
18873
  const HOME = env.USERPROFILE ?? env.HOME ?? env.HOMEPATH;
18874
18874
  if (!HOME) throw new Error("cannot find `USERPROFILE` directory");
18875
- const TEMP = env.CI_PROJECT_DIR + NAME;
18875
+ const TEMP = env.CI_PROJECT_DIR + "." + NAME;
18876
18876
 
18877
18877
  //#endregion
18878
18878
  //#region copilot/server/config.ts
package/bin/d5cli CHANGED
@@ -7,7 +7,59 @@ import { fileURLToPath } from "node:url";
7
7
 
8
8
  //#region package.json
9
9
  var name$1 = "@d5render/cli";
10
- var version = "0.1.31";
10
+ var version = "0.1.33";
11
+
12
+ //#endregion
13
+ //#region copilot/server/config.ts
14
+ const name = "d5_mcp_review_builtin";
15
+ const report = "report";
16
+ const getHash = "hash";
17
+ const file = "bin/copilot.js";
18
+ const serveFile = join(RUNTIME_CWD, file);
19
+ const envJson = buildEnv();
20
+ const envUsed = {
21
+ CI_SERVER_URL: toEnv("CI_SERVER_URL"),
22
+ CI_PROJECT_PATH: toEnv("CI_PROJECT_PATH"),
23
+ CI_PROJECT_ID: toEnv("CI_PROJECT_ID"),
24
+ CI_PROJECT_NAME: toEnv("CI_PROJECT_NAME"),
25
+ CI_COMMIT_SHA: toEnv("CI_COMMIT_SHA"),
26
+ CI_COMMIT_BEFORE_SHA: toEnv("CI_COMMIT_BEFORE_SHA"),
27
+ CI_MERGE_REQUEST_IID: toEnv("CI_MERGE_REQUEST_IID"),
28
+ CI_MERGE_REQUEST_TITLE: toEnv("CI_MERGE_REQUEST_TITLE"),
29
+ CI_MERGE_REQUEST_DESCRIPTION: toEnv("CI_MERGE_REQUEST_DESCRIPTION"),
30
+ JIRA_BASE_URL: toEnv("JIRA_BASE_URL", "http://jira.d5techs.com.cn"),
31
+ DINGTALK_WEBHOOK: toEnv("DINGTALK_WEBHOOK"),
32
+ GITLAB_TOKEN: toEnv("GITLAB_TOKEN"),
33
+ JIRA_PAT: toEnv("JIRA_PAT"),
34
+ JIRA_COOKIE: toEnv("JIRA_COOKIE"),
35
+ JIRA_USERNAME: toEnv("JIRA_USERNAME"),
36
+ JIRA_PASSWORD: toEnv("JIRA_PASSWORD")
37
+ };
38
+ const tools = [
39
+ "--additional-mcp-config",
40
+ JSON.stringify({ mcpServers: { [name]: {
41
+ type: "local",
42
+ command: "node",
43
+ args: [serveFile, `--customizenv=${JSON.stringify(envUsed)}`],
44
+ tools: ["*"]
45
+ } } }),
46
+ "--allow-all-paths",
47
+ "--allow-all-tools",
48
+ "--deny-tool",
49
+ "write",
50
+ "--deny-tool",
51
+ "github-mcp-server"
52
+ ];
53
+ tools.push("--model", "claude-sonnet-4.5");
54
+ function toEnv(key, defaultValue) {
55
+ return envJson[key] || process.env[key] || defaultValue;
56
+ }
57
+ function buildEnv() {
58
+ const envArg = argv.find((arg) => arg.startsWith("--customizenv="));
59
+ let envJson$1 = {};
60
+ if (envArg) envJson$1 = JSON.parse(envArg.replace("--customizenv=", ""));
61
+ return envJson$1;
62
+ }
11
63
 
12
64
  //#endregion
13
65
  //#region packages/gitlab/url.ts
@@ -71,8 +123,16 @@ const VERSION = version;
71
123
  const RUNTIME_CWD = join(dirname(fileURLToPath(import.meta.url)), "../");
72
124
  const HOME = env.USERPROFILE ?? env.HOME ?? env.HOMEPATH;
73
125
  if (!HOME) throw new Error("cannot find `USERPROFILE` directory");
74
- const TEMP = env.CI_PROJECT_DIR + NAME;
75
- function deploy() {
126
+ const TEMP = env.CI_PROJECT_DIR + "." + NAME;
127
+ const dingding = async (...args) => {
128
+ try {
129
+ const msg = await (await sendding(...args)).text();
130
+ console.log(msg);
131
+ } catch (error) {
132
+ console.error(error);
133
+ }
134
+ };
135
+ async function deploy() {
76
136
  if (!env.CI) return;
77
137
  const config = join(HOME, ".copilot/config.json"), dir = join(HOME, ".copilot/skills/codereview");
78
138
  console.log("deploy...");
@@ -82,6 +142,14 @@ function deploy() {
82
142
  }
83
143
  if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
84
144
  const versiono = readFileSync(join(RUNTIME_CWD, ".skills/review/version"), "utf8");
145
+ const changelog = readFileSync(join(RUNTIME_CWD, "CHANGELOG.md"), "utf8");
146
+ const cachepath = join(TEMP, "CHANGELOG");
147
+ if (changelog !== (existsSync(cachepath) ? readFileSync(cachepath, "utf8") : "")) {
148
+ if (!existsSync(TEMP)) mkdirSync(TEMP, { recursive: true });
149
+ writeFileSync(cachepath, changelog, "utf8");
150
+ console.log("updated CHANGELOG cache.");
151
+ await dingding("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)`);
152
+ }
85
153
  const versionnPath = join(dir, "version");
86
154
  if ((existsSync(versionnPath) ? readFileSync(versionnPath, "utf8") : "") === versiono) return;
87
155
  const skillRoot = join(RUNTIME_CWD, ".skills/review");
@@ -89,25 +157,16 @@ function deploy() {
89
157
  const instructionsRoot = join(RUNTIME_CWD, ".github/instructions");
90
158
  readdirSync(instructionsRoot).forEach((instruction) => copyFileSync(join(instructionsRoot, instruction), join(dir, instruction)));
91
159
  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
160
  }
102
- function need() {
161
+ async function need() {
103
162
  if (!env.CI) return;
104
- if (!existsSync(TEMP)) mkdirSync(TEMP, { recursive: true });
105
163
  const { CI_MERGE_REQUEST_IID, CI_COMMIT_SHA } = env;
106
164
  const file$1 = join(TEMP, "CODEREVIEW");
107
165
  if (CI_MERGE_REQUEST_IID) {
108
166
  let appended = `${existsSync(file$1) ? readFileSync(file$1, "utf8") : ""}\n${CI_MERGE_REQUEST_IID}`.split("\n");
109
167
  const max = 1e4;
110
168
  if (appended.length > max) appended = appended.slice(-max);
169
+ if (!existsSync(TEMP)) mkdirSync(TEMP, { recursive: true });
111
170
  writeFileSync(file$1, appended.join("\n"), "utf8");
112
171
  console.log("merge pipeline, recorded IID:", CI_MERGE_REQUEST_IID, "to:", file$1);
113
172
  return true;
@@ -125,70 +184,18 @@ function need() {
125
184
  console.warn(`Merge Request !${iid} has been AI reviewed before.`);
126
185
  const mergeURL = visitPipeline(iid).url;
127
186
  const url = `${commits()}/${CI_COMMIT_SHA}/comments`;
128
- fetch(url, {
187
+ await fetch(url, {
129
188
  method: "POST",
130
189
  headers: buildHeaders(),
131
190
  body: JSON.stringify({
132
191
  note: `请查看管道评论:${mergeURL}#note`,
133
192
  line_type: "new"
134
193
  })
135
- }).then((res) => res.text());
194
+ }).then((res) => res.text()).then((v) => console.log(v)).catch((e) => console.error(e));
136
195
  }
137
196
  return !yes;
138
197
  }
139
198
 
140
- //#endregion
141
- //#region copilot/server/config.ts
142
- const name = "d5_mcp_review_builtin";
143
- const report = "report";
144
- const getHash = "hash";
145
- const file = "bin/copilot.js";
146
- const serveFile = join(RUNTIME_CWD, file);
147
- const envJson = buildEnv();
148
- const envUsed = {
149
- CI_SERVER_URL: toEnv("CI_SERVER_URL"),
150
- CI_PROJECT_PATH: toEnv("CI_PROJECT_PATH"),
151
- CI_PROJECT_ID: toEnv("CI_PROJECT_ID"),
152
- CI_PROJECT_NAME: toEnv("CI_PROJECT_NAME"),
153
- CI_COMMIT_SHA: toEnv("CI_COMMIT_SHA"),
154
- CI_COMMIT_BEFORE_SHA: toEnv("CI_COMMIT_BEFORE_SHA"),
155
- CI_MERGE_REQUEST_IID: toEnv("CI_MERGE_REQUEST_IID"),
156
- CI_MERGE_REQUEST_TITLE: toEnv("CI_MERGE_REQUEST_TITLE"),
157
- CI_MERGE_REQUEST_DESCRIPTION: toEnv("CI_MERGE_REQUEST_DESCRIPTION"),
158
- JIRA_BASE_URL: toEnv("JIRA_BASE_URL", "http://jira.d5techs.com.cn"),
159
- DINGTALK_WEBHOOK: toEnv("DINGTALK_WEBHOOK"),
160
- GITLAB_TOKEN: toEnv("GITLAB_TOKEN"),
161
- JIRA_PAT: toEnv("JIRA_PAT"),
162
- JIRA_COOKIE: toEnv("JIRA_COOKIE"),
163
- JIRA_USERNAME: toEnv("JIRA_USERNAME"),
164
- JIRA_PASSWORD: toEnv("JIRA_PASSWORD")
165
- };
166
- const tools = [
167
- "--additional-mcp-config",
168
- JSON.stringify({ mcpServers: { [name]: {
169
- type: "local",
170
- command: "node",
171
- args: [serveFile, `--customizenv=${JSON.stringify(envUsed)}`],
172
- tools: ["*"]
173
- } } }),
174
- "--allow-all-paths",
175
- "--allow-all-tools",
176
- "--deny-tool",
177
- "write",
178
- "--deny-tool",
179
- "github-mcp-server"
180
- ];
181
- tools.push("--model", "claude-sonnet-4.5");
182
- function toEnv(key, defaultValue) {
183
- return envJson[key] || process.env[key] || defaultValue;
184
- }
185
- function buildEnv() {
186
- const envArg = argv.find((arg) => arg.startsWith("--customizenv="));
187
- let envJson$1 = {};
188
- if (envArg) envJson$1 = JSON.parse(envArg.replace("--customizenv=", ""));
189
- return envJson$1;
190
- }
191
-
192
199
  //#endregion
193
200
  //#region copilot/bin/install.ts
194
201
  function install() {
@@ -247,13 +254,13 @@ function logImmediate(message) {
247
254
  try {
248
255
  codereview();
249
256
  } catch (error) {
250
- sendding("CRITICAL", "CRITICAL CI ERROR: 未知错误,请自行检查日志");
257
+ dingding("CRITICAL", "CI ERROR: 未知错误,请自行检查日志");
251
258
  throw error;
252
259
  }
253
- function codereview() {
254
- deploy();
255
- if (!need()) {
256
- logImmediate("重复提交,进程跳过");
260
+ async function codereview() {
261
+ await deploy();
262
+ if (!await need()) {
263
+ console.log("重复提交,进程跳过");
257
264
  return;
258
265
  }
259
266
  install();
@@ -280,7 +287,6 @@ Otherwise, use chinese as default language to call the mcp tool '${name}-${repor
280
287
  },
281
288
  ...platform === "win32" && { windowsHide: true }
282
289
  });
283
- console.log(`node ${findCopilopt()} ${tools.join(" ")} --stream off -p ${prompt}`);
284
290
  copilot.stdout.setEncoding("utf8");
285
291
  copilot.stderr.setEncoding("utf8");
286
292
  copilot.stdout.on("data", (chunk) => {
@@ -290,61 +296,41 @@ Otherwise, use chinese as default language to call the mcp tool '${name}-${repor
290
296
  process.stderr.write(chunk);
291
297
  });
292
298
  copilot.on("close", (code) => {
293
- sendding("CRITICAL", "CRITICAL CI ERROR: 代码审查任务失败,请自行检查日志");
299
+ if (!code) dingding("CRITICAL", "CI ERROR: 代码审查任务失败,请自行检查日志");
294
300
  exit(code);
295
301
  });
296
302
  }
297
303
  /**
298
- * 根据平台和架构获取对应的 @github/copilot 包名
299
- * @returns 包名,如 @github/copilot-win32-x64 或 @github/copilot
304
+ * 根据操作系统和架构获取对应的 copilot 包名
305
+ * @returns 平台特定的包名数组,按优先级排序
300
306
  */
301
- function getCopilotPackageName() {
302
- const platformMap = {
303
- win32: "win32",
304
- linux: "linux",
305
- darwin: "darwin"
306
- };
307
- const archMap = {
308
- x64: "x64",
309
- arm64: "arm64"
310
- };
311
- const platformName = platformMap[platform];
312
- const archName = archMap[arch];
313
- if (platformName && archName) {
314
- const specificPackage = `@github/copilot-${platformName}-${archName}`;
315
- try {
316
- if (execSync(`npm list ${specificPackage} -g -p`, {
317
- encoding: "utf8",
318
- stdio: "pipe"
319
- }).trim()) {
320
- logImmediate(`[调试] 使用平台特定包: ${specificPackage}`);
321
- return specificPackage;
322
- }
323
- } catch {}
324
- }
325
- logImmediate(`[调试] 使用通用包: @github/copilot`);
326
- return "@github/copilot";
307
+ function getCopilotPackageNames() {
308
+ const packages = [];
309
+ if (platform === "win32" && arch === "x64") packages.push("@github/copilot-win32-x64");
310
+ else if (platform === "linux" && arch === "x64") packages.push("@github/copilot-linux-x64");
311
+ else if (platform === "linux" && arch === "arm64") packages.push("@github/copilot-linux-arm64");
312
+ else if (platform === "darwin" && arch === "arm64") packages.push("@github/copilot-darwin-arm64");
313
+ packages.push("@github/copilot");
314
+ return packages;
327
315
  }
328
316
  function findCopilopt() {
329
- const packageName = getCopilotPackageName();
317
+ const packageNames = getCopilotPackageNames();
330
318
  let copilot = "";
331
- try {
332
- copilot = execSync(`npm list ${packageName} -g -p`, {
333
- encoding: "utf8",
334
- stdio: "pipe"
335
- }).trim();
319
+ for (const packageName of packageNames) try {
320
+ copilot = execSync(`npm list ${packageName} -g -p`).toString().trim();
321
+ if (copilot) break;
336
322
  } catch {}
337
323
  if (!copilot) {
338
324
  const first = platform === "win32" ? win : linux;
339
325
  const second = platform === "win32" ? linux : win;
340
- copilot = first(packageName);
341
- if (!copilot) copilot = second(packageName);
342
- if (!copilot) throw new Error(`没找到安装的包: ${packageName},请运行: npm install -g ${packageName}`);
326
+ copilot = first();
327
+ if (!copilot) copilot = second();
328
+ if (!copilot) throw new Error("没找到安装的包");
343
329
  }
344
330
  const pkg = join(copilot, "package.json");
345
331
  if (!existsSync(pkg)) throw new Error("安装的包找不到正确版本 " + pkg);
346
332
  const copilotPackage = JSON.parse(readFileSync(pkg, "utf8"));
347
- const binPath = typeof copilotPackage.bin === "string" ? copilotPackage.bin : copilotPackage.bin?.copilot || copilotPackage.bin?.["@github/copilot"] || copilotPackage.bin?.[packageName];
333
+ const binPath = typeof copilotPackage.bin === "string" ? copilotPackage.bin : copilotPackage.bin?.copilot || copilotPackage.bin?.["@github/copilot"];
348
334
  if (!binPath) throw new Error("non copilot executable found");
349
335
  const copilotVersion = copilotPackage.version || "unknown";
350
336
  const copilotPath = join(copilot, binPath);
@@ -352,19 +338,23 @@ function findCopilopt() {
352
338
  version: ${VERSION}
353
339
  path: ${serveFile}
354
340
  copilot:
355
- package: ${packageName}
356
341
  version: ${copilotVersion}
357
342
  path: ${copilotPath}`);
358
343
  return copilotPath;
359
344
  }
360
- function win(packageName = "@github/copilot") {
345
+ function win() {
361
346
  const pathEnv = env.PATH || env.Path || "";
362
347
  const pathSeparator = platform === "win32" ? ";" : ":";
363
348
  const npm = pathEnv.split(pathSeparator).find((p) => p.includes("npm"));
364
- if (npm) return join(npm, "node_modules", packageName.replace("/", pathSeparator === ";" ? "\\" : "/"));
349
+ if (!npm) return "";
350
+ const packageNames = getCopilotPackageNames();
351
+ for (const packageName of packageNames) {
352
+ const packagePath = join(npm, "node_modules", ...packageName.split("/"));
353
+ if (existsSync(join(packagePath, "package.json"))) return packagePath;
354
+ }
365
355
  return "";
366
356
  }
367
- function linux(packageName = "@github/copilot") {
357
+ function linux() {
368
358
  let cached = env.NVM_BIN;
369
359
  if (!cached) {
370
360
  const pathEnv = env.PATH || env.Path || "";
@@ -372,9 +362,11 @@ function linux(packageName = "@github/copilot") {
372
362
  const npm = pathEnv.split(pathSeparator).find((p) => p.includes(".nvm"));
373
363
  if (npm) cached = npm;
374
364
  }
375
- if (cached) {
376
- const packageDir = packageName.replace("/", "/");
377
- return join(cached, "..", "lib", "node_modules", packageDir);
365
+ if (!cached) return "";
366
+ const packageNames = getCopilotPackageNames();
367
+ for (const packageName of packageNames) {
368
+ const packagePath = join(cached, "..", "lib", "node_modules", ...packageName.split("/"));
369
+ if (existsSync(join(packagePath, "package.json"))) return packagePath;
378
370
  }
379
371
  return "";
380
372
  }
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.31",
7
+ "version": "0.1.33",
8
8
  "devDependencies": {
9
9
  "@modelcontextprotocol/sdk": "^1.25.1",
10
10
  "@types/node": "^25.0.3",