@d5render/cli 0.1.60 → 0.1.62
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/.github/instructions/severity.instructions.md +34 -19
- package/.skills/code-review/SKILL.md +32 -31
- package/.skills/devops/{README.md → SKILL.md} +21 -15
- package/README.md +32 -2
- package/bin/d5cli +206 -205
- package/bin/{copilot.js → mcpServer.js} +243 -204
- package/package.json +26 -22
- package/CHANGELOG.md +0 -10
package/bin/d5cli
CHANGED
|
@@ -1,51 +1,51 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { argv, env, platform } from "node:process";
|
|
2
3
|
import { execSync, spawn } from "node:child_process";
|
|
3
|
-
import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync,
|
|
4
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
4
5
|
import { dirname, join } from "node:path";
|
|
5
|
-
import { argv, env, platform } from "node:process";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
|
|
8
|
-
//#region
|
|
9
|
-
|
|
8
|
+
//#region package.json
|
|
9
|
+
var name$1 = "@d5render/cli";
|
|
10
|
+
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region packages/env.ts
|
|
13
|
+
const name = "d5_mcp_review_builtin";
|
|
10
14
|
const report = "report";
|
|
11
15
|
const getHash = "hash";
|
|
12
|
-
const file = "bin/
|
|
16
|
+
const file = "bin/mcpServer.js";
|
|
13
17
|
const RUNTIME_CWD = join(dirname(fileURLToPath(import.meta.url)), "../");
|
|
14
18
|
const serveFile = join(RUNTIME_CWD, file);
|
|
15
19
|
const envJson = buildEnv();
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const tools = [
|
|
35
|
-
"--additional-mcp-config",
|
|
36
|
-
JSON.stringify({ mcpServers: { [name$1]: {
|
|
37
|
-
type: "local",
|
|
38
|
-
command: "node",
|
|
39
|
-
args: [serveFile, `--customizenv=${JSON.stringify(envUsed)}`],
|
|
40
|
-
tools: ["*"]
|
|
41
|
-
} } }),
|
|
42
|
-
"--allow-all-paths",
|
|
43
|
-
"--allow-all-tools",
|
|
44
|
-
"--deny-tool",
|
|
45
|
-
"write",
|
|
46
|
-
"--deny-tool",
|
|
47
|
-
"github-mcp-server"
|
|
20
|
+
const envConfigKeys = [
|
|
21
|
+
"CI_SERVER_URL",
|
|
22
|
+
"CI_PROJECT_PATH",
|
|
23
|
+
"CI_PROJECT_ID",
|
|
24
|
+
"CI_PROJECT_NAME",
|
|
25
|
+
"CI_COMMIT_SHA",
|
|
26
|
+
"CI_COMMIT_BEFORE_SHA",
|
|
27
|
+
"CI_MERGE_REQUEST_IID",
|
|
28
|
+
"CI_MERGE_REQUEST_TITLE",
|
|
29
|
+
"CI_MERGE_REQUEST_DESCRIPTION",
|
|
30
|
+
"JIRA_BASE_URL",
|
|
31
|
+
"DINGTALK_WEBHOOK",
|
|
32
|
+
"GITLAB_TOKEN",
|
|
33
|
+
"JIRA_PAT",
|
|
34
|
+
"JIRA_COOKIE",
|
|
35
|
+
"JIRA_USERNAME",
|
|
36
|
+
"JIRA_PASSWORD",
|
|
37
|
+
"TOKEN_USAGE"
|
|
48
38
|
];
|
|
39
|
+
const envUsed = Object.defineProperty({}, "JIRA_BASE_URL", {
|
|
40
|
+
get: () => toEnv("CI_SERVER_URL", "http://jira.d5techs.com.cn"),
|
|
41
|
+
enumerable: true,
|
|
42
|
+
configurable: true
|
|
43
|
+
});
|
|
44
|
+
envConfigKeys.forEach((key) => Object.defineProperty(envUsed, key, {
|
|
45
|
+
get: () => toEnv(key),
|
|
46
|
+
enumerable: true,
|
|
47
|
+
configurable: true
|
|
48
|
+
}));
|
|
49
49
|
function toEnv(key, defaultValue) {
|
|
50
50
|
return envJson[key] || process.env[key] || defaultValue;
|
|
51
51
|
}
|
|
@@ -56,59 +56,6 @@ function buildEnv() {
|
|
|
56
56
|
return envJson;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
//#endregion
|
|
60
|
-
//#region copilot/bin/install.ts
|
|
61
|
-
function install() {
|
|
62
|
-
if (!env.CI) return;
|
|
63
|
-
console.log("install copilot...");
|
|
64
|
-
let success = false;
|
|
65
|
-
let local = "";
|
|
66
|
-
try {
|
|
67
|
-
local = execSync("npm list @github/copilot -g --depth=0 --json").toString();
|
|
68
|
-
} catch {
|
|
69
|
-
local = "{}";
|
|
70
|
-
}
|
|
71
|
-
try {
|
|
72
|
-
const localInfo = JSON.parse(local);
|
|
73
|
-
const localVersion = localInfo.dependencies ? localInfo.dependencies?.["@github/copilot"]?.version : void 0;
|
|
74
|
-
if (!localVersion) {
|
|
75
|
-
installCopilot();
|
|
76
|
-
success = true;
|
|
77
|
-
console.log("install copilot success");
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
if (localVersion !== execSync("npm view @github/copilot version --registry=https://registry.npmmirror.com").toString().trim()) {
|
|
81
|
-
execSync("npm uninstall -g @github/copilot --force");
|
|
82
|
-
installCopilot();
|
|
83
|
-
success = true;
|
|
84
|
-
console.log("update copilot success");
|
|
85
|
-
} else {
|
|
86
|
-
success = true;
|
|
87
|
-
console.log("copilot exists and is up-to-date");
|
|
88
|
-
}
|
|
89
|
-
} catch (error) {
|
|
90
|
-
console.error(error);
|
|
91
|
-
}
|
|
92
|
-
if (!success) try {
|
|
93
|
-
console.warn("try to reinstall copilot...");
|
|
94
|
-
installCopilot();
|
|
95
|
-
success = true;
|
|
96
|
-
} catch (error) {
|
|
97
|
-
console.error(error);
|
|
98
|
-
}
|
|
99
|
-
if (success) return;
|
|
100
|
-
console.warn("try to reinstall copilot...");
|
|
101
|
-
installCopilot();
|
|
102
|
-
}
|
|
103
|
-
function installCopilot() {
|
|
104
|
-
execSync("npm install -g @github/copilot --registry=https://registry.npmmirror.com", { stdio: "inherit" });
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
//#endregion
|
|
108
|
-
//#region package.json
|
|
109
|
-
var name = "@d5render/cli";
|
|
110
|
-
var version = "0.1.60";
|
|
111
|
-
|
|
112
59
|
//#endregion
|
|
113
60
|
//#region packages/gitlab/url.ts
|
|
114
61
|
function buildHeaders() {
|
|
@@ -153,8 +100,8 @@ const commits = () => {
|
|
|
153
100
|
//#endregion
|
|
154
101
|
//#region packages/message/sendding.ts
|
|
155
102
|
async function sendding(title, text) {
|
|
156
|
-
if (!envUsed.DINGTALK_WEBHOOK) throw new Error("non DINGTALK_WEBHOOK");
|
|
157
103
|
let res = new Response();
|
|
104
|
+
if (!envUsed.DINGTALK_WEBHOOK) throw res;
|
|
158
105
|
for (const url of envUsed.DINGTALK_WEBHOOK.split(",")) res = await fetch(url, {
|
|
159
106
|
method: "POST",
|
|
160
107
|
headers: { "Content-Type": "application/json" },
|
|
@@ -174,53 +121,39 @@ async function sendding(title, text) {
|
|
|
174
121
|
}
|
|
175
122
|
|
|
176
123
|
//#endregion
|
|
177
|
-
//#region
|
|
178
|
-
const NAME = name.replaceAll("/", "_");
|
|
179
|
-
const
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
124
|
+
//#region review/helper.ts
|
|
125
|
+
const NAME = name$1.replaceAll("/", "_");
|
|
126
|
+
const TEMP = join(env.CI_PROJECT_DIR || "", `../../.${NAME}`);
|
|
127
|
+
const common_review_prompt = `Load code-review skills, then call the mcp tool '${name}-${getHash}' to load code-review commits.
|
|
128
|
+
Then use chinese(中文) to call the mcp tool '${name}-${report}', only main agent can call the tool '${name}-${report}', **prevent** subagent from calling tool '${name}-${report}`;
|
|
129
|
+
async function changelog() {
|
|
130
|
+
const changelog = readFileSync(join(RUNTIME_CWD, "README.md"), "utf8");
|
|
131
|
+
const cachepath = join(TEMP, "CHANGELOG_" + (env.CI_RUNNER_ID ?? env.CI_PROJECT_ID ?? "0"));
|
|
132
|
+
if (changelog === (existsSync(cachepath) ? readFileSync(cachepath, "utf8") : "")) return;
|
|
133
|
+
if (!existsSync(TEMP)) mkdirSync(TEMP, { recursive: true });
|
|
134
|
+
writeFileSync(cachepath, changelog, "utf8");
|
|
135
|
+
console.log("updated CHANGELOG cache.");
|
|
136
|
+
let matched = changelog.match(/CHANGELOG[\s\S]*?(#+[^\n]*\n+([\s\S]*?))(?=#+|$)/)?.[1] ?? "";
|
|
137
|
+
const matcheds = matched.split("\n");
|
|
138
|
+
matcheds.shift();
|
|
139
|
+
matched = matcheds.join("\n").trim();
|
|
140
|
+
if (matched) await dingding("NOTICE", `skills 更新\n\n\n${matched}\n\n\n历史请参考 [线上文档内容.skills文件夹](https://www.npmjs.com/package/@d5render/cli)`);
|
|
141
|
+
}
|
|
142
|
+
function deploySkills(SKILLS_DIR = ".copilot/skills") {
|
|
191
143
|
const HOME = env.USERPROFILE ?? env.HOME ?? env.HOMEPATH;
|
|
192
144
|
if (!HOME) throw new Error("cannot find `USERPROFILE` directory");
|
|
193
|
-
const
|
|
194
|
-
const cachepath = join(TEMP, "CHANGELOG-" + env.CI_RUNNER_ID || "0");
|
|
195
|
-
let cache = "";
|
|
196
|
-
if (existsSync(cachepath)) cache = readFileSync(cachepath, "utf8");
|
|
197
|
-
else if (!existsSync(TEMP)) mkdirSync(TEMP, { recursive: true });
|
|
198
|
-
if (changelog !== cache) {
|
|
199
|
-
writeFileSync(cachepath, changelog, "utf8");
|
|
200
|
-
console.log("updated CHANGELOG cache.");
|
|
201
|
-
await dingding("NOTICE", `code-review/SKILL.md 更新\n\n细节请参考 [线上文档内容.skills](https://www.npmjs.com/package/@d5render/cli?activeTab=code)`);
|
|
202
|
-
}
|
|
203
|
-
const config = join(HOME, ".copilot/config.json"), dir = join(HOME, ".copilot/skills/code-review");
|
|
204
|
-
console.log("deploy...");
|
|
205
|
-
if (existsSync(config)) {
|
|
206
|
-
rmSync(config);
|
|
207
|
-
console.log("removed config cache.");
|
|
208
|
-
}
|
|
209
|
-
if (existsSync(dir)) rmSync(dir, {
|
|
210
|
-
recursive: true,
|
|
211
|
-
force: true
|
|
212
|
-
});
|
|
145
|
+
const dir = join(HOME, `${SKILLS_DIR}/code-review`);
|
|
213
146
|
mkdirSync(dir, { recursive: true });
|
|
147
|
+
console.log("deploy code-review skills...");
|
|
214
148
|
const skillRoot = join(RUNTIME_CWD, ".skills/code-review");
|
|
215
|
-
readdirSync(skillRoot).forEach((
|
|
149
|
+
readdirSync(skillRoot).forEach((file) => copyFileSync(join(skillRoot, file), join(dir, file)));
|
|
216
150
|
const instructionsRoot = join(RUNTIME_CWD, ".github/instructions");
|
|
217
151
|
readdirSync(instructionsRoot).forEach((instruction) => copyFileSync(join(instructionsRoot, instruction), join(dir, instruction)));
|
|
218
|
-
console.log("to new skill.");
|
|
219
152
|
}
|
|
220
153
|
async function need() {
|
|
221
154
|
if (!env.CI) return true;
|
|
222
155
|
const { CI_MERGE_REQUEST_IID, CI_COMMIT_SHA } = env;
|
|
223
|
-
const file = join(TEMP, "
|
|
156
|
+
const file = join(TEMP, "CODEREVIEW_" + (env.CI_PROJECT_ID ?? "0"));
|
|
224
157
|
if (CI_MERGE_REQUEST_IID) {
|
|
225
158
|
let appended = `${existsSync(file) ? readFileSync(file, "utf8") : ""}\n${CI_MERGE_REQUEST_IID}`.split("\n");
|
|
226
159
|
const max = 1e4;
|
|
@@ -237,7 +170,7 @@ async function need() {
|
|
|
237
170
|
encoding: "utf8"
|
|
238
171
|
}).toString().match(/See merge request[\s\S]+!(\d+)/);
|
|
239
172
|
if (!match) return true;
|
|
240
|
-
const iid = match
|
|
173
|
+
const [, iid] = match;
|
|
241
174
|
const yes = (existsSync(file) ? readFileSync(file, "utf8") : "").split("\n").includes(iid);
|
|
242
175
|
if (yes) {
|
|
243
176
|
console.warn(`Merge Request !${iid} has been AI reviewed before.`);
|
|
@@ -254,31 +187,136 @@ async function need() {
|
|
|
254
187
|
}
|
|
255
188
|
return !yes;
|
|
256
189
|
}
|
|
190
|
+
const dingding = async (...args) => {
|
|
191
|
+
try {
|
|
192
|
+
const msg = await (await sendding(...args)).text();
|
|
193
|
+
console.log(msg);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
console.warn(error);
|
|
196
|
+
}
|
|
197
|
+
};
|
|
257
198
|
|
|
258
199
|
//#endregion
|
|
259
|
-
//#region
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
200
|
+
//#region review/token.copilot.ts
|
|
201
|
+
const GITHUB_API = "https://api.github.com";
|
|
202
|
+
const COPILOT_HEADERS = {
|
|
203
|
+
"User-Agent": "GitHubCopilotChat/0.35.0",
|
|
204
|
+
"Editor-Version": "vscode/1.107.0",
|
|
205
|
+
"Editor-Plugin-Version": "copilot-chat/0.35.0",
|
|
206
|
+
"Copilot-Integration-Id": "vscode-chat"
|
|
207
|
+
};
|
|
208
|
+
function getOAuthToken() {
|
|
209
|
+
const token = env.GITHUB_COPILOT_TOKEN || env.COPILOT_TOKEN || env.GITHUB_TOKEN || env.GH_TOKEN;
|
|
210
|
+
if (!token) throw new Error("未找到 GitHub Token,请设置 GITHUB_COPILOT_TOKEN / GITHUB_TOKEN / GH_TOKEN 环境变量");
|
|
211
|
+
return token;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* 将 OAuth token 换成 Copilot session token
|
|
215
|
+
* 新版 OpenCode 官方 OAuth 接入需要此步骤才能访问 /copilot_internal/* API
|
|
216
|
+
*/
|
|
217
|
+
async function exchangeForCopilotToken(oauthToken) {
|
|
218
|
+
try {
|
|
219
|
+
const res = await fetch(`${GITHUB_API}/copilot_internal/v2/token`, { headers: {
|
|
220
|
+
Accept: "application/json",
|
|
221
|
+
Authorization: `Bearer ${oauthToken}`,
|
|
222
|
+
...COPILOT_HEADERS
|
|
223
|
+
} });
|
|
224
|
+
if (!res.ok) return void 0;
|
|
225
|
+
return (await res.json()).token || void 0;
|
|
226
|
+
} catch {
|
|
268
227
|
return;
|
|
269
228
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
229
|
+
}
|
|
230
|
+
async function fetchInternalUsage() {
|
|
231
|
+
const oauthToken = getOAuthToken();
|
|
232
|
+
const directRes = await fetch(`${GITHUB_API}/copilot_internal/user`, { headers: {
|
|
233
|
+
Accept: "application/json",
|
|
234
|
+
Authorization: `token ${oauthToken}`,
|
|
235
|
+
...COPILOT_HEADERS
|
|
236
|
+
} });
|
|
237
|
+
if (directRes.ok) return directRes.json();
|
|
238
|
+
const copilotToken = await exchangeForCopilotToken(oauthToken);
|
|
239
|
+
if (!copilotToken) throw new Error([
|
|
240
|
+
"Copilot OAuth token 无法访问配额 API。",
|
|
241
|
+
"请创建 fine-grained PAT(https://github.com/settings/tokens?type=beta)",
|
|
242
|
+
"并在 Account permissions 中设置 Plan = Read-only,",
|
|
243
|
+
"然后通过 GITHUB_PAT 环境变量传入。"
|
|
244
|
+
].join("\n"));
|
|
245
|
+
const res = await fetch(`${GITHUB_API}/copilot_internal/user`, { headers: {
|
|
246
|
+
Accept: "application/json",
|
|
247
|
+
Authorization: `Bearer ${copilotToken}`,
|
|
248
|
+
...COPILOT_HEADERS
|
|
249
|
+
} });
|
|
250
|
+
if (!res.ok) {
|
|
251
|
+
const text = await res.text();
|
|
252
|
+
throw new Error(`查询 Copilot 内部 API 失败: ${res.status} ${text}`);
|
|
253
|
+
}
|
|
254
|
+
return res.json();
|
|
255
|
+
}
|
|
256
|
+
function formatInternalResult(data) {
|
|
257
|
+
const premium = data.quota_snapshots.premium_interactions;
|
|
258
|
+
return premium.entitlement - premium.remaining;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* 查询 Copilot Premium Request 使用量
|
|
262
|
+
*
|
|
263
|
+
* 优先级:
|
|
264
|
+
* 1. 若设置了 GITHUB_PAT(fine-grained PAT)→ 使用 Public Billing API,支持模型明细
|
|
265
|
+
* 2. 否则使用 Internal API(GITHUB_COPILOT_TOKEN OAuth token),返回配额百分比和重置时间
|
|
266
|
+
*/
|
|
267
|
+
async function getCopilotUsage(options = {}) {
|
|
268
|
+
try {
|
|
269
|
+
return formatInternalResult(await fetchInternalUsage());
|
|
270
|
+
} catch {
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
//#endregion
|
|
276
|
+
//#region review/copilot/deploy.ts
|
|
277
|
+
const config = join(dirname(fileURLToPath(import.meta.url)), "copilot-mcp.json");
|
|
278
|
+
const tools = [
|
|
279
|
+
"--additional-mcp-config",
|
|
280
|
+
platform === "win32" ? `"@${config}"` : `@${config}`,
|
|
281
|
+
"--model",
|
|
282
|
+
"claude-opus-4.6",
|
|
283
|
+
"--allow-all-paths",
|
|
284
|
+
"--allow-all-tools",
|
|
285
|
+
"--enable-all-github-mcp-tools",
|
|
286
|
+
"--deny-tool",
|
|
287
|
+
"write",
|
|
288
|
+
"--stream",
|
|
289
|
+
"off"
|
|
290
|
+
];
|
|
291
|
+
async function deploy() {
|
|
292
|
+
if (!env.CI) return;
|
|
293
|
+
await changelog();
|
|
294
|
+
execSync("npm i -g @github/copilot@latest --registry=https://registry.npmmirror.com", { stdio: "inherit" });
|
|
295
|
+
deploySkills();
|
|
296
|
+
const token = await getCopilotUsage();
|
|
297
|
+
env["TOKEN_USAGE"] = String(token);
|
|
298
|
+
console.log("deploy customized config...");
|
|
299
|
+
writeFileSync(config, JSON.stringify({ mcpServers: { [name]: {
|
|
300
|
+
type: "local",
|
|
301
|
+
command: "node",
|
|
302
|
+
args: [serveFile, `--customizenv=${JSON.stringify(envUsed)}`],
|
|
303
|
+
tools: ["*"]
|
|
304
|
+
} } }, void 0, 2), "utf8");
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
//#endregion
|
|
308
|
+
//#region review/copilot/index.ts
|
|
309
|
+
const bind = "copilot";
|
|
310
|
+
async function cli() {
|
|
311
|
+
await deploy();
|
|
312
|
+
const httpProxy = env.HTTP_PROXY || env.http_proxy || "";
|
|
313
|
+
const httpsProxy = env.HTTPS_PROXY || env.https_proxy || "";
|
|
314
|
+
if (httpProxy) env.HTTP_PROXY = httpProxy;
|
|
315
|
+
if (httpsProxy) env.HTTPS_PROXY = httpsProxy;
|
|
316
|
+
const child = spawn(bind, [
|
|
277
317
|
...tools,
|
|
278
|
-
"--stream",
|
|
279
|
-
"off",
|
|
280
318
|
"-p",
|
|
281
|
-
|
|
319
|
+
`"${common_review_prompt.replace(/"/g, "\\\"")}"`
|
|
282
320
|
], {
|
|
283
321
|
cwd: env.CI_PROJECT_DIR,
|
|
284
322
|
stdio: [
|
|
@@ -286,67 +324,30 @@ Otherwise, use chinese as default language to call the mcp tool '${name$1}-${rep
|
|
|
286
324
|
"pipe",
|
|
287
325
|
"pipe"
|
|
288
326
|
],
|
|
289
|
-
...platform === "win32" && {
|
|
290
|
-
env: {
|
|
291
|
-
...process.env,
|
|
292
|
-
HTTP_PROXY: httpProxy,
|
|
293
|
-
HTTPS_PROXY: httpsProxy
|
|
294
|
-
}
|
|
295
|
-
});
|
|
296
|
-
copilot.stdout.on("data", (chunk) => console.log(String(chunk)));
|
|
297
|
-
copilot.stderr.on("data", (chunk) => console.error(String(chunk)));
|
|
298
|
-
return new Promise((res, rej) => {
|
|
299
|
-
copilot.on("close", (code) => res());
|
|
327
|
+
...platform === "win32" && { shell: true }
|
|
300
328
|
});
|
|
329
|
+
child.stdout.on("data", (chunk) => console.log(String(chunk)));
|
|
330
|
+
child.stderr.on("data", (chunk) => console.error(String(chunk)));
|
|
331
|
+
return new Promise((res, rej) => child.on("close", (code) => getCopilotUsage().then((res) => console.log("本次Token积累使用量:", res)).catch(() => {}).finally(() => {
|
|
332
|
+
if (code === 0) res();
|
|
333
|
+
else rej(/* @__PURE__ */ new Error(`${bind} exited with code ${code}`));
|
|
334
|
+
})));
|
|
301
335
|
}
|
|
302
|
-
|
|
303
|
-
|
|
336
|
+
|
|
337
|
+
//#endregion
|
|
338
|
+
//#region review/index.ts
|
|
339
|
+
async function codereview() {
|
|
304
340
|
try {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
}
|
|
314
|
-
const pkg = join(copilot, "package.json");
|
|
315
|
-
if (!existsSync(pkg)) throw new Error("安装的包找不到正确版本 " + pkg);
|
|
316
|
-
const copilotPackage = JSON.parse(readFileSync(pkg, "utf8"));
|
|
317
|
-
const binPath = typeof copilotPackage.bin === "string" ? copilotPackage.bin : copilotPackage.bin?.copilot || copilotPackage.bin?.["@github/copilot"];
|
|
318
|
-
if (!binPath) throw new Error("non copilot executable found");
|
|
319
|
-
const copilotVersion = copilotPackage.version || "unknown";
|
|
320
|
-
const copilotPath = join(copilot, binPath);
|
|
321
|
-
console.log(`${NAME} server:
|
|
322
|
-
version: ${VERSION}
|
|
323
|
-
path: ${serveFile}
|
|
324
|
-
copilot:
|
|
325
|
-
version: ${copilotVersion}
|
|
326
|
-
path: ${copilotPath}`);
|
|
327
|
-
return copilotPath;
|
|
328
|
-
}
|
|
329
|
-
function win() {
|
|
330
|
-
const pathEnv = env.PATH || env.Path || "";
|
|
331
|
-
const pathSeparator = platform === "win32" ? ";" : ":";
|
|
332
|
-
const npm = pathEnv.split(pathSeparator).find((p) => p.includes("npm"));
|
|
333
|
-
if (!npm) return "";
|
|
334
|
-
const fallbackPath = join(npm, "node_modules", "@github/copilot");
|
|
335
|
-
if (existsSync(join(fallbackPath, "package.json"))) return fallbackPath;
|
|
336
|
-
return "";
|
|
337
|
-
}
|
|
338
|
-
function linux() {
|
|
339
|
-
let cached = env.NVM_BIN;
|
|
340
|
-
if (!cached) {
|
|
341
|
-
const pathEnv = env.PATH || env.Path || "";
|
|
342
|
-
const pathSeparator = platform === "win32" ? ";" : ":";
|
|
343
|
-
const npm = pathEnv.split(pathSeparator).find((p) => p.includes(".nvm"));
|
|
344
|
-
if (npm) cached = npm;
|
|
341
|
+
if (!await need()) {
|
|
342
|
+
console.log("重复提交,进程跳过");
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
await cli();
|
|
346
|
+
} catch (error) {
|
|
347
|
+
await dingding("CRITICAL", "CI ERROR: 未知错误,请自行检查日志");
|
|
348
|
+
throw error;
|
|
345
349
|
}
|
|
346
|
-
if (!cached) return "";
|
|
347
|
-
const fallbackPath = join(cached, "..", "lib", "node_modules", "@github/copilot");
|
|
348
|
-
if (existsSync(join(fallbackPath, "package.json"))) return fallbackPath;
|
|
349
|
-
return "";
|
|
350
350
|
}
|
|
351
|
+
if (argv.includes("codereview")) codereview();
|
|
351
352
|
|
|
352
353
|
//#endregion
|