@d5render/cli 0.1.60 → 0.1.61

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.
@@ -18799,48 +18799,43 @@ var StdioServerTransport = class {
18799
18799
  };
18800
18800
 
18801
18801
  //#endregion
18802
- //#region copilot/server/config.ts
18802
+ //#region packages/env.ts
18803
18803
  const name = "d5_mcp_review_builtin";
18804
18804
  const report = "report";
18805
18805
  const getHash = "hash";
18806
- const noMandatory = "dont't call under non-mandatory conditions";
18807
- const file = "bin/copilot.js";
18806
+ const file = "bin/mcpServer.js";
18808
18807
  const RUNTIME_CWD = join(dirname(fileURLToPath(import.meta.url)), "../");
18809
18808
  const serveFile = join(RUNTIME_CWD, file);
18810
18809
  const envJson = buildEnv();
18811
- const envUsed = {
18812
- CI_SERVER_URL: toEnv("CI_SERVER_URL"),
18813
- CI_PROJECT_PATH: toEnv("CI_PROJECT_PATH"),
18814
- CI_PROJECT_ID: toEnv("CI_PROJECT_ID"),
18815
- CI_PROJECT_NAME: toEnv("CI_PROJECT_NAME"),
18816
- CI_COMMIT_SHA: toEnv("CI_COMMIT_SHA"),
18817
- CI_COMMIT_BEFORE_SHA: toEnv("CI_COMMIT_BEFORE_SHA"),
18818
- CI_MERGE_REQUEST_IID: toEnv("CI_MERGE_REQUEST_IID"),
18819
- CI_MERGE_REQUEST_TITLE: toEnv("CI_MERGE_REQUEST_TITLE"),
18820
- CI_MERGE_REQUEST_DESCRIPTION: toEnv("CI_MERGE_REQUEST_DESCRIPTION"),
18821
- JIRA_BASE_URL: toEnv("JIRA_BASE_URL", "http://jira.d5techs.com.cn"),
18822
- DINGTALK_WEBHOOK: toEnv("DINGTALK_WEBHOOK"),
18823
- GITLAB_TOKEN: toEnv("GITLAB_TOKEN"),
18824
- JIRA_PAT: toEnv("JIRA_PAT"),
18825
- JIRA_COOKIE: toEnv("JIRA_COOKIE"),
18826
- JIRA_USERNAME: toEnv("JIRA_USERNAME"),
18827
- JIRA_PASSWORD: toEnv("JIRA_PASSWORD")
18828
- };
18829
- const tools = [
18830
- "--additional-mcp-config",
18831
- JSON.stringify({ mcpServers: { [name]: {
18832
- type: "local",
18833
- command: "node",
18834
- args: [serveFile, `--customizenv=${JSON.stringify(envUsed)}`],
18835
- tools: ["*"]
18836
- } } }),
18837
- "--allow-all-paths",
18838
- "--allow-all-tools",
18839
- "--deny-tool",
18840
- "write",
18841
- "--deny-tool",
18842
- "github-mcp-server"
18810
+ const envConfigKeys = [
18811
+ "CI_SERVER_URL",
18812
+ "CI_PROJECT_PATH",
18813
+ "CI_PROJECT_ID",
18814
+ "CI_PROJECT_NAME",
18815
+ "CI_COMMIT_SHA",
18816
+ "CI_COMMIT_BEFORE_SHA",
18817
+ "CI_MERGE_REQUEST_IID",
18818
+ "CI_MERGE_REQUEST_TITLE",
18819
+ "CI_MERGE_REQUEST_DESCRIPTION",
18820
+ "JIRA_BASE_URL",
18821
+ "DINGTALK_WEBHOOK",
18822
+ "GITLAB_TOKEN",
18823
+ "JIRA_PAT",
18824
+ "JIRA_COOKIE",
18825
+ "JIRA_USERNAME",
18826
+ "JIRA_PASSWORD",
18827
+ "TOKEN_USAGE"
18843
18828
  ];
18829
+ const envUsed = Object.defineProperty({}, "JIRA_BASE_URL", {
18830
+ get: () => toEnv("CI_SERVER_URL", "http://jira.d5techs.com.cn"),
18831
+ enumerable: true,
18832
+ configurable: true
18833
+ });
18834
+ envConfigKeys.forEach((key) => Object.defineProperty(envUsed, key, {
18835
+ get: () => toEnv(key),
18836
+ enumerable: true,
18837
+ configurable: true
18838
+ }));
18844
18839
  function toEnv(key, defaultValue) {
18845
18840
  return envJson[key] || process.env[key] || defaultValue;
18846
18841
  }
@@ -18850,6 +18845,7 @@ function buildEnv() {
18850
18845
  if (envArg) envJson = JSON.parse(envArg.replace("--customizenv=", ""));
18851
18846
  return envJson;
18852
18847
  }
18848
+ const noMandatory = "dont't call under non-mandatory conditions";
18853
18849
 
18854
18850
  //#endregion
18855
18851
  //#region packages/gitlab/url.ts
@@ -18897,60 +18893,58 @@ const commits = () => {
18897
18893
  if (api) return `${api}/repository/commits`;
18898
18894
  };
18899
18895
 
18900
- //#endregion
18901
- //#region packages/gitlab/commit.ts
18902
- const getCommits = () => {
18903
- const url = pipelineMerge();
18904
- if (url) return fetch(`${url}/commits`, { headers: buildHeaders() }).then((res) => {
18905
- if (!res.ok) throw new Error("请求GitLab API失败" + res.statusText);
18906
- return res.json();
18907
- }).then((commits) => ({ content: [{
18908
- type: "text",
18909
- description: "commits from `merge pipeline`",
18910
- text: `${commits.map((commit) => commit.id).join(",")}, the above review is from \`merge pipeline\` commits.`
18911
- }] })).catch((error) => ({
18912
- content: [{
18913
- type: "text",
18914
- text: "error " + (error.message || "请求GitLab API失败,请检查网络连接或访问权限")
18915
- }],
18916
- isError: true
18917
- }));
18918
- const { CI_COMMIT_SHA, CI_COMMIT_BEFORE_SHA } = envUsed;
18919
- if (CI_COMMIT_SHA && CI_COMMIT_BEFORE_SHA) return { content: [{
18920
- type: "text",
18921
- description: "commit from push pipeline",
18922
- text: `from ${CI_COMMIT_BEFORE_SHA} to ${CI_COMMIT_SHA}.`
18923
- }] };
18924
- return { content: [{
18925
- type: "text",
18926
- text: `latest commit`
18927
- }] };
18928
- };
18929
- const getMergeInfomation = () => {
18930
- const { CI_MERGE_REQUEST_DESCRIPTION, CI_MERGE_REQUEST_TITLE } = envUsed;
18931
- if (CI_MERGE_REQUEST_DESCRIPTION || CI_MERGE_REQUEST_TITLE) return { content: [{
18932
- type: "text",
18933
- text: `title: ${CI_MERGE_REQUEST_TITLE || ""}, description: ${CI_MERGE_REQUEST_DESCRIPTION || ""}`
18934
- }] };
18935
- return {
18936
- content: [{
18937
- type: "text",
18938
- text: "error"
18939
- }],
18940
- isError: true
18941
- };
18942
- };
18943
-
18944
18896
  //#endregion
18945
18897
  //#region packages/gitlab/index.ts
18946
18898
  function install$2(server) {
18947
- server.registerTool(getHash, { description: noMandatory }, getCommits);
18899
+ server.registerTool(getHash, { description: noMandatory }, () => {
18900
+ const url = pipelineMerge();
18901
+ if (url) return fetch(`${url}/commits`, { headers: buildHeaders() }).then((res) => {
18902
+ if (!res.ok) throw new Error("请求GitLab API失败" + res.statusText);
18903
+ return res.json();
18904
+ }).then((commits) => ({ content: [{
18905
+ type: "text",
18906
+ text: `${commits.map((commit) => commit.id).join(",")}, the above review is from \`merge pipeline\` commits.`
18907
+ }] })).catch(() => ({
18908
+ content: [{
18909
+ type: "text",
18910
+ text: "latest commit"
18911
+ }],
18912
+ isError: true
18913
+ }));
18914
+ const { CI_COMMIT_SHA, CI_COMMIT_BEFORE_SHA } = envUsed;
18915
+ if (CI_COMMIT_SHA && CI_COMMIT_BEFORE_SHA) return { content: [{
18916
+ type: "text",
18917
+ text: `from ${CI_COMMIT_BEFORE_SHA} to ${CI_COMMIT_SHA}.`
18918
+ }] };
18919
+ return { content: [{
18920
+ type: "text",
18921
+ text: `latest commit`
18922
+ }] };
18923
+ });
18948
18924
  server.registerTool("getMergeDescription", {
18949
18925
  title: "merge pipeline description",
18950
18926
  description: "When review task from `merge pipeline`, get the merge request description."
18951
- }, getMergeInfomation);
18927
+ }, () => {
18928
+ let { CI_MERGE_REQUEST_DESCRIPTION: CMED, CI_MERGE_REQUEST_TITLE: CMRT } = envUsed;
18929
+ if (CMED || CMRT) {
18930
+ CMED = CMED ? `, description: ${CMED || ""}` : "";
18931
+ CMRT = CMRT ? `title: ${CMRT || ""}` : "";
18932
+ return { content: [{
18933
+ type: "text",
18934
+ text: CMRT + CMED
18935
+ }] };
18936
+ }
18937
+ return { content: [{
18938
+ type: "text",
18939
+ text: ""
18940
+ }] };
18941
+ });
18952
18942
  }
18953
18943
 
18944
+ //#endregion
18945
+ //#region packages/jira/schema.ts
18946
+ const jiraSchema = { key: string().describe("JIRA task number such as `FUS-123`") };
18947
+
18954
18948
  //#endregion
18955
18949
  //#region packages/jira/url.ts
18956
18950
  function commonHeaders() {
@@ -18967,100 +18961,70 @@ function commonHeaders() {
18967
18961
  }
18968
18962
 
18969
18963
  //#endregion
18970
- //#region packages/jira/getIssue.ts
18971
- const getIssue = (request) => {
18964
+ //#region packages/jira/index.ts
18965
+ function install$1(server) {
18966
+ server.registerTool("get_jira_context", {
18967
+ title: "get jira context",
18968
+ description: "When the submission message contains a JIRA task number (e.g., `FUS-123`), this tool will be used to retrieve the contents of the JIRA task and supplement the current context.",
18969
+ inputSchema: jiraSchema
18970
+ }, caller);
18971
+ }
18972
+ async function caller(request) {
18972
18973
  const { key } = request;
18973
18974
  const { JIRA_BASE_URL } = envUsed;
18974
- return fetch(`${JIRA_BASE_URL}/rest/api/latest/issue/${key}`, { headers: commonHeaders() }).then((res) => res.json()).then((res) => {
18975
- const { fields = {}, key = "" } = res;
18975
+ try {
18976
+ const headers = commonHeaders();
18977
+ const res = await (await fetch(`${JIRA_BASE_URL}/rest/api/latest/issue/${key}`, { headers })).json();
18978
+ if (!res.fields) throw new Error("JIRA issue not found");
18979
+ const { fields = {} } = res;
18976
18980
  const { comment = {}, description = "", summary = "", priority = {} } = fields;
18977
18981
  const { comments = [] } = comment;
18978
- return { content: [{
18982
+ const content = [
18983
+ ...summary ? [{
18984
+ type: "text",
18985
+ description: "summary of the issue",
18986
+ text: summary
18987
+ }] : [],
18988
+ ...priority.name ? [{
18989
+ type: "text",
18990
+ description: "priority of the issue",
18991
+ text: priority.name
18992
+ }] : [],
18993
+ ...description ? [{
18994
+ type: "text",
18995
+ description: "description of the issue",
18996
+ text: description
18997
+ }] : [],
18998
+ ...comments.map((v) => ({
18999
+ type: "text",
19000
+ description: "one of comment of the issue, format like `author` - `comment`",
19001
+ text: (v.author?.displayName || "nobody") + " - " + v.body
19002
+ }))
19003
+ ];
19004
+ if (content.length > 0) content.unshift({
18979
19005
  type: "text",
18980
19006
  description: `tools has find the JIRA issue ${key}`,
18981
19007
  text: `JIRA ${key} find`
18982
- }].concat(summary ? [{
18983
- type: "text",
18984
- description: "summary of the issue",
18985
- text: summary
18986
- }] : [], priority.name ? [{
18987
- type: "text",
18988
- description: "priority of the issue",
18989
- text: priority.name
18990
- }] : [], description ? [{
19008
+ });
19009
+ else content.push({
18991
19010
  type: "text",
18992
- description: "description of the issue",
18993
- text: description
18994
- }] : [], comments.map((v) => ({
19011
+ description: `tools has find the JIRA issue ${key}`,
19012
+ text: `JIRA ${key} find with no content`
19013
+ });
19014
+ return { content };
19015
+ } catch {
19016
+ return { content: [{
18995
19017
  type: "text",
18996
- description: "one of comment of the issue, format like `author` - `comment`",
18997
- text: (v.author?.displayName || "nobody") + " - " + v.body
18998
- }))) };
18999
- }).catch(() => ({ content: [{
19000
- type: "text",
19001
- text: `JIRA ${key} Non Exist.`
19002
- }] }));
19003
- };
19004
-
19005
- //#endregion
19006
- //#region packages/jira/schema.ts
19007
- const jiraSchema = { key: string().describe("JIRA task number such as `FUS-123`") };
19008
-
19009
- //#endregion
19010
- //#region packages/jira/index.ts
19011
- function install$1(server) {
19012
- server.registerTool("get_jira_context", {
19013
- title: "get jira context",
19014
- description: "When the submission message contains a JIRA task number (e.g., `FUS-123`), this tool will be used to retrieve the contents of the JIRA task and supplement the current context.",
19015
- inputSchema: jiraSchema
19016
- }, getIssue);
19018
+ text: `JIRA ${key} Non Exist.`
19019
+ }] };
19020
+ }
19017
19021
  }
19018
19022
 
19019
- //#endregion
19020
- //#region packages/message/props.ts
19021
- const one = "If it can be explained in one sentence, then passing in one entry is sufficient.";
19022
- const code = {
19023
- file: string().optional().describe("The file path where the issue is found"),
19024
- line: string().optional().describe("Line number, e.g., '1-345' pr '205' or '17,35', **must** provide the line of final file"),
19025
- codeExample: string().optional().describe(`Code modification suggestions, recommended to use code in diff format, like: \`\`\`
19026
- while (condition) {
19027
- unchanged line;
19028
- - remove this;
19029
- + replace it with this;
19030
- + and this;
19031
- but keep this the same;
19032
- }\`\`\`.`)
19033
- };
19034
- const severity = "such as CRITICAL, HIGH, MEDIUM, LOW";
19035
- const reportSchema = {
19036
- title: string().describe("Please describe the problem in the shortest possible way."),
19037
- summary: array(string().describe(one)).optional().describe("Regarding the description of the current review, please summarize the main logic of the submission as concisely as possible."),
19038
- issues: array(object({
19039
- severity: string().optional().describe(`Bug severity levels, ${severity}.`),
19040
- commitTitle: string().describe("The commit title associated with the issue"),
19041
- commitAuthor: string().describe("The commit latest author associated with the issue"),
19042
- commitSha: string().optional().describe("The commit SHA associated with the issue"),
19043
- title: string().optional().describe("A short title for the issue"),
19044
- details: array(string()).optional().describe("Details about the issue"),
19045
- suggestions: array(string()).optional().describe("Improvement suggestion"),
19046
- ...code
19047
- })).optional().describe(`List all bugs, order by 'severity' from heaviest to lightest, such as ${severity}`),
19048
- jiras: array(object({
19049
- key: string().describe("JIRA issue key, e.g., 'FUS-123'"),
19050
- summary: string().describe("Summary of the JIRA issue")
19051
- }).describe("Related JIRA issues")).optional().describe("List of related JIRA issues"),
19052
- risks: array(string().describe(one).describe("A short summary of the risk")).optional().describe("After summarizing all the bugs, identify the main risks that could potentially impact the business."),
19053
- suggestions: array(object({
19054
- details: string().describe("Suggestions with the same meaning should be stated in one sentence; please do not increase the array length."),
19055
- example: object(code).optional().describe("Pass in when you feel it is necessary to provide code.")
19056
- })).optional().describe("After gaining a comprehensive understanding of the files involved in the commits, propose suggestions for code corrections beyond the diff.")
19057
- };
19058
-
19059
19023
  //#endregion
19060
19024
  //#region packages/message/sendding.ts
19061
19025
  async function sendding(title, text) {
19062
- if (!envUsed.DINGTALK_WEBHOOK) throw new Error("non DINGTALK_WEBHOOK");
19063
19026
  let res = new Response();
19027
+ if (!envUsed.DINGTALK_WEBHOOK) throw res;
19064
19028
  for (const url of envUsed.DINGTALK_WEBHOOK.split(",")) res = await fetch(url, {
19065
19029
  method: "POST",
19066
19030
  headers: { "Content-Type": "application/json" },
@@ -19085,14 +19049,22 @@ const lastComment = { value: {} };
19085
19049
  const schemaGitlabPipeline = "gitlab_pipeline";
19086
19050
  const schemaGitlabCommit = "gitlab_commit";
19087
19051
  const schemaDingdingTalk = "dingding_talk";
19052
+ const schemaRecord = "record";
19088
19053
  function distReports(input) {
19089
- const { CI_PROJECT_NAME = "", CI_COMMIT_SHA = "", JIRA_BASE_URL, CI_MERGE_REQUEST_IID, DINGTALK_WEBHOOK } = envUsed;
19090
- const { title = "代码审查报告", summary = [], issues = [], jiras = [], risks = [], suggestions = [] } = input;
19054
+ const { CI_PROJECT_NAME = "", CI_COMMIT_SHA = "", JIRA_BASE_URL, CI_MERGE_REQUEST_IID, DINGTALK_WEBHOOK, TOKEN_USAGE = "" } = envUsed;
19055
+ const { title = "代码审查报告", summary: _summary = [], issues = [], jiras = [], risks: _risks = [], suggestions: _sugg = [] } = input;
19056
+ const usage = () => {
19057
+ if (TOKEN_USAGE) gitlabReportMessage += `\n\n> Last Token Usage: ${TOKEN_USAGE}`;
19058
+ };
19059
+ const summary = Array.isArray(_summary) ? _summary : [_summary];
19060
+ const risks = Array.isArray(_risks) ? _risks : [_risks];
19061
+ const suggestions = Array.isArray(_sugg) ? _sugg : [_sugg];
19091
19062
  const mergeURL = pipelineMerge();
19092
19063
  const commitsURL = commits();
19093
19064
  let gitlabReportMessage = `## 📖 ${title}\n`;
19094
19065
  const commitComments = [];
19095
19066
  let dingdingReportMessage = "";
19067
+ let { url, type } = visitPipeline();
19096
19068
  const gitlabReport = {
19097
19069
  title: schemaGitlabPipeline,
19098
19070
  report: [() => {
@@ -19116,8 +19088,10 @@ function distReports(input) {
19116
19088
  method: "GET",
19117
19089
  headers: buildHeaders()
19118
19090
  })).then((res) => res.json()).then((res) => {
19119
- const { notes = [] } = res[res.length - 1] || {};
19120
- lastComment.value = notes[notes.length - 1] || {};
19091
+ if (res.length <= 0) return;
19092
+ const { notes = [] } = res.at(-1) || {};
19093
+ if (notes.length <= 0) return;
19094
+ lastComment.value = notes.at(-1) || {};
19121
19095
  });
19122
19096
  }
19123
19097
  return Promise.resolve(void 0);
@@ -19141,15 +19115,31 @@ function distReports(input) {
19141
19115
  });
19142
19116
  }]
19143
19117
  };
19118
+ let last_token_usage = Number(TOKEN_USAGE);
19119
+ last_token_usage = Number.isNaN(last_token_usage) ? null : last_token_usage;
19144
19120
  const result = [
19145
19121
  gitlabReport,
19146
19122
  gitlabCommitReport,
19147
- dingdingReport
19123
+ dingdingReport,
19124
+ {
19125
+ title: schemaRecord,
19126
+ report: [() => fetch("http://ai-code-review.d5techs.com.cn/api/code_review_logs", {
19127
+ method: "POST",
19128
+ headers: { "Content-Type": "application/json" },
19129
+ body: JSON.stringify({
19130
+ project_name: envUsed.CI_PROJECT_PATH || "unknown",
19131
+ commit_messages: url,
19132
+ last_token_usage,
19133
+ main_risk: risks.join("<br>"),
19134
+ review_result: gitlabReportMessage
19135
+ })
19136
+ })]
19137
+ }
19148
19138
  ];
19149
19139
  if (issues.length === 0 && suggestions.length === 0) {
19150
- gitlabReport.report = [];
19151
19140
  gitlabCommitReport.report = [];
19152
19141
  dingdingReport.report = [];
19142
+ usage();
19153
19143
  return result;
19154
19144
  }
19155
19145
  const fileMap = /* @__PURE__ */ new Map();
@@ -19161,12 +19151,12 @@ function distReports(input) {
19161
19151
  if (commitSha) {
19162
19152
  const lines = line.split(",").map((line) => {
19163
19153
  const str = line.trim().split("-");
19164
- const num = Number.parseInt(str[str.length - 1], 10);
19154
+ const num = Number.parseInt(str.at(-1), 10);
19165
19155
  return Number.isNaN(num) ? void 0 : num;
19166
19156
  }).filter((v) => v !== void 0);
19167
19157
  const attach = file ? {
19168
19158
  file,
19169
- line: lines.length > 0 ? lines[lines.length - 1] : void 0
19159
+ line: lines.length > 0 ? lines.at(-1) : void 0
19170
19160
  } : {};
19171
19161
  commitComments.push({
19172
19162
  sha: commitSha,
@@ -19195,30 +19185,30 @@ function distReports(input) {
19195
19185
  for (const [file, fileIssues] of fileMap) {
19196
19186
  gitlabReportMessage += `\n-----\n\n#### 文件: ${file}`;
19197
19187
  for (const issue of fileIssues) {
19198
- const { severity = "NON", line = "NON", title: issueTitle = "NON", details = [], suggestions: issueSuggestions = [], codeExample = "" } = issue;
19188
+ const { severity = "NON", line = "NON", title: issueTitle = "NON", details = [], suggestions: issueSuggestions = [], codeExample = "", score = "60" } = issue;
19199
19189
  gitlabReportMessage += `\n\n**${severity}** | ${line} | ${issueTitle}`;
19200
- gitlabReportMessage += `\n- 详情:\n - ${details.join("\n - ")}`;
19201
- gitlabReportMessage += `\n- 建议:\n - ${issueSuggestions.join("\n - ")}`;
19190
+ gitlabReportMessage += `\n- subagent 可信度:${score}`;
19191
+ gitlabReportMessage += `\n- 详情:${details.length === 1 ? ` ${details[0]}` : `\n - ${details.join("\n - ")}`}`;
19192
+ gitlabReportMessage += `\n- 建议:${issueSuggestions.length === 1 ? ` ${issueSuggestions[0]}` : `\n - ${issueSuggestions.join("\n - ")}`}`;
19202
19193
  if (codeExample) gitlabReportMessage += `\n${toCode(codeExample)}\n`;
19203
19194
  }
19204
19195
  }
19205
19196
  }
19206
19197
  if (suggestions.length > 0) {
19207
- gitlabReportMessage += "\n\n### 📈 其他建议\n\n-----\n";
19198
+ gitlabReportMessage += "\n\n### 📈 其他建议\n";
19208
19199
  let withNoFile = "", withFile = "";
19209
19200
  for (const suggestion of suggestions) {
19210
- const { details = "", example } = suggestion;
19211
- const { file = "", line = "", codeExample = "" } = example || {};
19201
+ const { details = "", file = "", line = "", codeExample = "" } = typeof suggestion === "string" ? { details: suggestion } : suggestion;
19212
19202
  if (file) {
19213
- withFile += `\n-----\n\n#### 文件: ${file}`;
19214
- if (line) withFile += `\n- 行数:${line}`;
19215
- withFile += `\n- 详情:\n - ${details}`;
19216
- if (codeExample) withFile += `\n${toCode(codeExample)}\n`;
19203
+ withFile += `\n\n-----\n\n#### 文件: ${file}\n`;
19204
+ withFile += `\n\n**${line === "" ? "文件整体逻辑问题" : line}** | ` + details;
19205
+ if (codeExample) withFile += `\n\n${toCode(codeExample)}\n`;
19217
19206
  } else withNoFile += `\n - ${details}`;
19218
19207
  }
19219
19208
  gitlabReportMessage += withNoFile + withFile;
19220
19209
  }
19221
- const { url, type } = visitPipeline();
19210
+ usage();
19211
+ let subCommitUrl = url;
19222
19212
  if (DINGTALK_WEBHOOK) {
19223
19213
  dingdingReportMessage = `### 📖 ${title}\n\n**共计**:${issues.length}个问题\n\n${risks.length > 0 ? "**主要风险**:\n\n" + risks.join("\n\n") + "\n\n" : "\n\n"}-----\n\n**项目名**:${CI_PROJECT_NAME}`;
19224
19214
  if (type) {
@@ -19226,35 +19216,39 @@ function distReports(input) {
19226
19216
  let { id: note = "" } = value || {};
19227
19217
  note = note ? `#note_${note}` : "";
19228
19218
  const commit = note ? "&评论" : "";
19229
- dingdingReportMessage += `${type === "merge_request" ? `\n\n**合并${commit}**:[${CI_MERGE_REQUEST_IID}](${url}${note})` : `\n\n**提交${commit}**:[${CI_COMMIT_SHA.slice(0, 8)}](${url}${note})`}`;
19230
- }
19231
- dingdingReportMessage += `\n\n含问题的commits:${[...commitsMap.keys()].map((v) => `[${v.slice(0, 8)}](${linkBase}/${v})`).join(", ")}\n\n-----\n`;
19232
- dingdingReportMessage += "\n#### 🐞 问题列表\n";
19233
- let bugLength = 0;
19234
- const maxBugLength = 5;
19235
- for (const [severity, severityIssues] of severityMap) {
19236
- if (bugLength > maxBugLength) break;
19237
- dingdingReportMessage += `\n\n**${severity}**`;
19238
- for (const issue of severityIssues) {
19239
- if (bugLength > maxBugLength) {
19240
- dingdingReportMessage += `\n\n\n...以及其他 ${issues.length - bugLength} 个问题,[详见报告](${url})`;
19241
- break;
19219
+ url += note;
19220
+ dingdingReportMessage += `${type === "merge_request" ? `\n\n**合并${commit}**:[${CI_MERGE_REQUEST_IID}](${url})` : `\n\n**提交${commit}**:[${CI_COMMIT_SHA.slice(0, 8)}](${url})`}`;
19221
+ }
19222
+ if (severityMap.size > 0) {
19223
+ dingdingReportMessage += `${commitsMap.size > 0 ? `\n\n含问题的commits:${[...commitsMap.keys()].map((v) => `[${v.slice(0, 8)}](${linkBase}/${v})`).join(", ")}` : ""}\n\n-----\n\n#### 🐞 Issues\n\n`;
19224
+ let bugLength = 0;
19225
+ const maxBugLength = 5;
19226
+ for (const [severity, severityIssues] of severityMap) {
19227
+ if (bugLength > maxBugLength) break;
19228
+ dingdingReportMessage += `\n\n**${severity}**`;
19229
+ for (const issue of severityIssues) {
19230
+ if (bugLength > maxBugLength) {
19231
+ dingdingReportMessage += `\n\n\n...以及其他 ${issues.length - bugLength} 个问题,[详见报告](${url})`;
19232
+ break;
19233
+ }
19234
+ const { title: issueTitle = "NON", commitSha = "", file = "NON", line = "NON", commitAuthor = "", score = "60" } = issue;
19235
+ const shortSha = (commitSha || "").slice(0, 8);
19236
+ const commitLink = linkBase && commitSha ? `${linkBase}/${commitSha}` : void 0;
19237
+ dingdingReportMessage += `\n- ${issueTitle}\n\n - score: ${score}\n\n - hash: ${commitLink ? `[${shortSha}](${commitLink}) ` : shortSha}\n\n - author: ${commitAuthor}\n\n - file: ${file}\n\n - line: ${line}`;
19238
+ bugLength++;
19242
19239
  }
19243
- const { title: issueTitle = "NON", commitSha = "", file = "NON", line = "NON", commitAuthor = "" } = issue;
19244
- const shortSha = (commitSha || "").slice(0, 8);
19245
- const commitLink = linkBase && commitSha ? `${linkBase}/${commitSha}` : void 0;
19246
- dingdingReportMessage += `\n- ${issueTitle}\n\n - hash: ${commitLink ? `[${shortSha}](${commitLink}) ` : shortSha}\n\n - author: ${commitAuthor}\n\n - file: ${file}\n\n - line: ${line}`;
19247
- bugLength++;
19248
19240
  }
19241
+ } else {
19242
+ const { value = {} } = lastComment;
19243
+ let { id = "" } = value || {};
19244
+ dingdingReportMessage += `\n\n-----\n\n#### [**改进建议请查看**](${url}#note_${id})\n`;
19249
19245
  }
19250
- if (jiras.length > 0) dingdingReportMessage += `\n\n\n\n#### 🔗 关联 JIRA\n ${jiras.map((v) => `[${v.key}](${JIRA_BASE_URL}/browse/${v.key}): ${v.summary}`).join("\n\n")}`;
19246
+ if (jiras.length > 0) dingdingReportMessage += `\n\n#### 🔗 JIRA \n\n\n\n${jiras.map((v) => `[${v.key}](${JIRA_BASE_URL}/browse/${v.key}): ${v.summary}`).join("\n\n")}`;
19251
19247
  }
19252
19248
  if (commitsURL) gitlabCommitReport.report = commitComments.map(({ sha, file, line, note }) => () => {
19253
19249
  const { value = {} } = lastComment;
19254
19250
  let { id = "" } = value || {};
19255
- if (id) note += `
19256
-
19257
- [**完整评论请查看**](${url}#note_${id})`;
19251
+ if (id) note += `\n\n[**完整评论请查看**](${subCommitUrl}#note_${id})`;
19258
19252
  return fetch(`${commitsURL}/${sha}/comments`, {
19259
19253
  method: "POST",
19260
19254
  headers: buildHeaders(),
@@ -19275,13 +19269,58 @@ async function runReport(input) {
19275
19269
  error: error.message || "未知错误"
19276
19270
  })));
19277
19271
  const error = results.find((v) => v.error);
19278
- return error ? `error: ${error.title}\n${error.error}` : "✅ GitLab MCP Report 执行完成,无问题";
19272
+ return error ? `error: ${error.title}\n${error.error}` : "✅ Report Done";
19279
19273
  }
19280
19274
  function toCode(code) {
19281
19275
  const ct = code.trim();
19282
- return ct.startsWith("```") && ct.endsWith("```") ? code : `\`\`\`\n${code}\n\`\`\``;
19276
+ return ct.startsWith("```") && ct.endsWith("```") ? code.endsWith("\n```") ? code : code.slice(0, -3) + "\n```" : `\`\`\`\n${code}\n\`\`\``;
19283
19277
  }
19284
19278
 
19279
+ //#endregion
19280
+ //#region packages/message/schema.ts
19281
+ const code = {
19282
+ file: string().optional().describe("The file path where the issue is found"),
19283
+ line: string().optional().describe("Line number, e.g., '1-345' pr '205' or '17,35', **must** provide the line of final file"),
19284
+ codeExample: string().optional().describe(`Code modification suggestions, recommended to use code in diff format, like: \`\`\`
19285
+ while (condition) {
19286
+ unchanged line;
19287
+ - remove this;
19288
+ + replace it with this;
19289
+ + and this;
19290
+ but keep this the same;
19291
+ }\`\`\`.`)
19292
+ };
19293
+ const severity = "such as CRITICAL, HIGH, MEDIUM, LOW";
19294
+ const nonInfo = "When the current change no longer exists in the latest code, please take the relevant information from the most recent change.";
19295
+ const reportSchema = {
19296
+ title: string().describe("Describe the problem in the shortest possible way."),
19297
+ summary: union([string(), array(string())]).optional().describe("Regarding the description of the current review, please summarize the main logic of the submission as concisely as possible. If you need to split the summary into multiple points, please use Markdown's splitting syntax such as <br> to do so."),
19298
+ issues: array(object({
19299
+ severity: string().optional().describe(`Issue severity levels, ${severity}.`),
19300
+ score: string().optional().describe(`Issue credibility score, from 0-100`),
19301
+ commitTitle: string().describe(`The commit title associated with the issue, ${nonInfo}`),
19302
+ commitAuthor: string().describe(`The commit latest author associated with the issue, ${nonInfo}`),
19303
+ commitSha: string().describe(`The commit SHA associated with the issue, ${nonInfo}`),
19304
+ title: string().optional().describe("A short title for the issue"),
19305
+ details: array(string()).optional().describe("Details about the issue"),
19306
+ suggestions: array(string()).optional().describe("Improvement suggestion"),
19307
+ ...code
19308
+ })).optional().describe(`List all bugs involved in the modified code. **Must** only list the issues related to the modified parts. **Must** order by 'severity' from heaviest to lightest, ${severity}`),
19309
+ jiras: array(object({
19310
+ key: string().describe("JIRA issue key, e.g., 'FUS-123'"),
19311
+ summary: string().describe("Summary of the JIRA issue")
19312
+ }).describe("Related JIRA issues")).optional().describe("List JIRA issues in review"),
19313
+ risks: union([string(), array(string())]).optional().describe("After summarizing all the bugs, identify the main risks that could potentially impact the business."),
19314
+ suggestions: union([
19315
+ string(),
19316
+ array(string()),
19317
+ array(object({
19318
+ details: string().describe("Suggestions with the same meaning should be stated in one sentence; please do not increase the array length."),
19319
+ ...code
19320
+ })).describe("For other issues in the code, and for issues with a score below 50, please post the bugs and suggested fixes here.")
19321
+ ]).optional().describe("Please provide other suggestions for modifying the code or related code.")
19322
+ };
19323
+
19285
19324
  //#endregion
19286
19325
  //#region packages/message/index.ts
19287
19326
  function install(server) {
@@ -19295,7 +19334,7 @@ function install(server) {
19295
19334
  }
19296
19335
 
19297
19336
  //#endregion
19298
- //#region copilot/server/index.ts
19337
+ //#region packages/server/index.ts
19299
19338
  const server = new McpServer({
19300
19339
  name,
19301
19340
  version: "1.0.0"
package/package.json CHANGED
@@ -1,36 +1,40 @@
1
1
  {
2
2
  "name": "@d5render/cli",
3
- "type": "module",
3
+ "version": "0.1.61",
4
4
  "license": "MIT",
5
5
  "author": "jasirou",
6
- "main": "./bin/d5cli",
7
- "version": "0.1.60",
8
- "devDependencies": {
9
- "@modelcontextprotocol/sdk": "^1.25.1",
10
- "@types/node": "^25.0.3",
11
- "@types/vscode": "^1.107.0",
12
- "@vscode/vsce": "^3.7.1",
13
- "json5": "^2.2.3",
14
- "oxfmt": "^0.21.0",
15
- "oxlint": "^1.37.0",
16
- "rolldown": "1.0.0-beta.58",
17
- "vitest": "^4.0.17",
18
- "zod": "^4.3.5"
6
+ "bin": {
7
+ "d5cli": "bin/d5cli"
19
8
  },
20
9
  "files": [
21
- ".github/instructions/severity.instructions.md",
22
- ".skills/devops",
10
+ "CHANGELOG.md",
23
11
  ".skills/code-review",
24
- "bin/copilot.js",
12
+ ".skills/devops",
13
+ "bin/mcpServer.js",
25
14
  "bin/d5cli",
26
- "CHANGELOG.md"
15
+ ".github/instructions/severity.instructions.md"
27
16
  ],
28
- "bin": {
29
- "d5cli": "bin/d5cli"
17
+ "type": "module",
18
+ "main": "./bin/d5cli",
19
+ "dependencies": {
20
+ "vscode-languageserver-protocol": "^3.17.5"
21
+ },
22
+ "devDependencies": {
23
+ "@modelcontextprotocol/sdk": "^1.25.3",
24
+ "@types/node": "^25.1.0",
25
+ "@types/vscode": "^1.108.1",
26
+ "@vscode/vsce": "^3.7.1",
27
+ "json5": "^2.2.3",
28
+ "oxfmt": "^0.21.0",
29
+ "oxlint": "^1.42.0",
30
+ "rolldown": "1.0.0-rc.2",
31
+ "vitest": "^4.0.18",
32
+ "zod": "^4.3.6"
30
33
  },
31
34
  "scripts": {
32
- "build:copilot": "node ./setup.js build",
35
+ "build": "node ./setup.js build",
33
36
  "release": "node ./setup.js publish",
34
- "setup": "node ./setup.js"
37
+ "setup": "node ./setup.js",
38
+ "test": "node ./setup.js build:development"
35
39
  }
36
40
  }