@wuyanbin/ai-code-review-cli-remote 1.0.12-canary.0 → 1.0.12

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.
Files changed (80) hide show
  1. package/dist/config.d.ts.map +1 -1
  2. package/dist/config.js +0 -6
  3. package/dist/config.js.map +1 -1
  4. package/dist/core/context.d.ts.map +1 -0
  5. package/dist/core/context.js.map +1 -0
  6. package/dist/core/diff.d.ts +14 -0
  7. package/dist/core/diff.d.ts.map +1 -0
  8. package/dist/core/diff.js +179 -0
  9. package/dist/core/diff.js.map +1 -0
  10. package/dist/core/model.d.ts +6 -0
  11. package/dist/core/model.d.ts.map +1 -0
  12. package/dist/core/model.js +120 -0
  13. package/dist/core/model.js.map +1 -0
  14. package/dist/core/output.d.ts +4 -0
  15. package/dist/core/output.d.ts.map +1 -0
  16. package/dist/core/output.js +31 -0
  17. package/dist/core/output.js.map +1 -0
  18. package/dist/core/prompt.d.ts +17 -0
  19. package/dist/core/prompt.d.ts.map +1 -0
  20. package/dist/core/prompt.js +92 -0
  21. package/dist/core/prompt.js.map +1 -0
  22. package/dist/core/reviewer.d.ts +6 -0
  23. package/dist/core/reviewer.d.ts.map +1 -0
  24. package/dist/core/reviewer.js +123 -0
  25. package/dist/core/reviewer.js.map +1 -0
  26. package/dist/core/summarizer.d.ts +3 -0
  27. package/dist/core/summarizer.d.ts.map +1 -0
  28. package/dist/core/summarizer.js +48 -0
  29. package/dist/core/summarizer.js.map +1 -0
  30. package/dist/diff.d.ts +0 -10
  31. package/dist/diff.d.ts.map +1 -1
  32. package/dist/diff.js +0 -54
  33. package/dist/diff.js.map +1 -1
  34. package/dist/gitlab/api.d.ts +13 -0
  35. package/dist/gitlab/api.d.ts.map +1 -0
  36. package/dist/gitlab/api.js +317 -0
  37. package/dist/gitlab/api.js.map +1 -0
  38. package/dist/gitlab.d.ts +0 -5
  39. package/dist/gitlab.d.ts.map +1 -1
  40. package/dist/gitlab.js +34 -155
  41. package/dist/gitlab.js.map +1 -1
  42. package/dist/http.d.ts +1 -0
  43. package/dist/http.d.ts.map +1 -1
  44. package/dist/http.js +13 -0
  45. package/dist/http.js.map +1 -1
  46. package/dist/index.js +1 -1
  47. package/dist/index.js.map +1 -1
  48. package/dist/platform/config.d.ts +10 -0
  49. package/dist/platform/config.d.ts.map +1 -0
  50. package/dist/platform/config.js +156 -0
  51. package/dist/platform/config.js.map +1 -0
  52. package/dist/platform/report.d.ts +9 -0
  53. package/dist/platform/report.d.ts.map +1 -0
  54. package/dist/platform/report.js +32 -0
  55. package/dist/platform/report.js.map +1 -0
  56. package/dist/reviewer.d.ts +1 -4
  57. package/dist/reviewer.d.ts.map +1 -1
  58. package/dist/reviewer.js +14 -61
  59. package/dist/reviewer.js.map +1 -1
  60. package/dist/runner.d.ts +1 -3
  61. package/dist/runner.d.ts.map +1 -1
  62. package/dist/runner.js +2 -9
  63. package/dist/runner.js.map +1 -1
  64. package/dist/shared/http.d.ts +3 -0
  65. package/dist/shared/http.d.ts.map +1 -0
  66. package/dist/shared/http.js +18 -0
  67. package/dist/shared/http.js.map +1 -0
  68. package/dist/{identity.d.ts → shared/identity.d.ts} +1 -1
  69. package/dist/shared/identity.d.ts.map +1 -0
  70. package/dist/{identity.js → shared/identity.js} +1 -1
  71. package/dist/shared/identity.js.map +1 -0
  72. package/dist/types.d.ts +0 -1
  73. package/dist/types.d.ts.map +1 -1
  74. package/package.json +1 -1
  75. package/dist/context.d.ts.map +0 -1
  76. package/dist/context.js.map +0 -1
  77. package/dist/identity.d.ts.map +0 -1
  78. package/dist/identity.js.map +0 -1
  79. /package/dist/{context.d.ts → core/context.d.ts} +0 -0
  80. /package/dist/{context.js → core/context.js} +0 -0
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.reviewCode = reviewCode;
4
+ const jsonrepair_1 = require("jsonrepair");
5
+ const zod_1 = require("zod");
6
+ const context_1 = require("./context");
7
+ const diff_1 = require("./diff");
8
+ const identity_1 = require("../shared/identity");
9
+ const model_1 = require("./model");
10
+ const prompt_1 = require("./prompt");
11
+ const SEVERITY_ORDER = { info: 0, warning: 1, error: 2 };
12
+ const SHARD_CONCURRENCY = 3;
13
+ const aiCommentSchema = zod_1.z.object({
14
+ file: zod_1.z.string().trim().min(1),
15
+ line: zod_1.z.number().int().positive(),
16
+ code: zod_1.z.string().optional(),
17
+ severity: zod_1.z.enum(["info", "warning", "error"]),
18
+ message: zod_1.z.string().trim().min(1),
19
+ suggestion: zod_1.z.string().optional(),
20
+ });
21
+ const aiResponseSchema = zod_1.z.object({
22
+ comments: zod_1.z.array(zod_1.z.unknown()).default([]),
23
+ });
24
+ function stripFences(text) {
25
+ return (text ?? "")
26
+ .replace(/^```(?:json)?\s*/i, "")
27
+ .replace(/```$/i, "")
28
+ .trim();
29
+ }
30
+ function extractJsonObject(content) {
31
+ const text = stripFences(content);
32
+ const start = text.indexOf("{");
33
+ const end = text.lastIndexOf("}");
34
+ if (start >= 0 && end > start)
35
+ return text.slice(start, end + 1);
36
+ return text;
37
+ }
38
+ function parseAIResponse(content) {
39
+ const jsonText = extractJsonObject(content);
40
+ try {
41
+ const parsed = JSON.parse((0, jsonrepair_1.jsonrepair)(jsonText));
42
+ const response = aiResponseSchema.safeParse(parsed);
43
+ if (!response.success)
44
+ return { comments: [] };
45
+ const comments = [];
46
+ for (const rawComment of response.data.comments) {
47
+ const comment = aiCommentSchema.safeParse(rawComment);
48
+ if (comment.success)
49
+ comments.push(comment.data);
50
+ }
51
+ return { comments };
52
+ }
53
+ catch (error) {
54
+ console.error("[reviewer] AI 返回 JSON 解析失败");
55
+ console.error(error);
56
+ return null;
57
+ }
58
+ }
59
+ async function runWithConcurrency(tasks, concurrency) {
60
+ const results = new Array(tasks.length);
61
+ let next = 0;
62
+ async function worker() {
63
+ while (next < tasks.length) {
64
+ const index = next++;
65
+ results[index] = await tasks[index]();
66
+ }
67
+ }
68
+ await Promise.all(Array.from({ length: Math.min(concurrency, tasks.length) }, () => worker()));
69
+ return results;
70
+ }
71
+ async function reviewCode(diff, config, options = {}) {
72
+ const effectiveDiff = (0, diff_1.filterDiffByIgnore)(diff, config.review.ignore);
73
+ if (!effectiveDiff.trim())
74
+ return { comments: [] };
75
+ if (!config.ai.apiKey || !config.ai.endpoint)
76
+ return null;
77
+ const adapter = (0, model_1.createModelAdapter)(config.ai.endpoint, config.ai.apiKey, config.ai.apiFormat);
78
+ const shards = (0, diff_1.splitDiffByMaxBytes)(effectiveDiff, config.review.shardMaxBytes);
79
+ const minSeverity = SEVERITY_ORDER[config.review.severity];
80
+ console.error(`[reviewer] diff shards=${shards.length} shardMaxBytes=${config.review.shardMaxBytes} concurrency=${SHARD_CONCURRENCY}`);
81
+ const tasks = shards.map((shard, index) => async () => {
82
+ const context = await (0, context_1.collectReviewContext)(shard, options);
83
+ const prompt = new prompt_1.PromptBuilder()
84
+ .setDiff(shard)
85
+ .setRules(config.rules.custom)
86
+ .setContext(context);
87
+ const raw = await adapter.call(config.ai.model, prompt.buildSystem(), prompt.buildUser());
88
+ if (!raw) {
89
+ console.error(`[reviewer] shard ${index + 1}/${shards.length} returned empty`);
90
+ return { index, comments: [], success: false };
91
+ }
92
+ const parsed = parseAIResponse(raw);
93
+ if (!parsed) {
94
+ console.error(`[reviewer] shard ${index + 1}/${shards.length} parse failed`);
95
+ return { index, comments: [], success: false };
96
+ }
97
+ return {
98
+ index,
99
+ comments: (0, diff_1.alignCommentsToDiffAddedLines)(shard, parsed.comments).filter((c) => SEVERITY_ORDER[c.severity] >= minSeverity),
100
+ success: true,
101
+ };
102
+ });
103
+ const results = await runWithConcurrency(tasks, SHARD_CONCURRENCY);
104
+ const successCount = results.filter((r) => r.success).length;
105
+ if (successCount === 0)
106
+ return null;
107
+ const allComments = results.flatMap((r) => r.comments);
108
+ const seen = new Set();
109
+ let deduped = allComments
110
+ .filter((comment) => {
111
+ const fingerprint = (0, identity_1.buildContentFingerprint)(comment);
112
+ if (seen.has(fingerprint))
113
+ return false;
114
+ seen.add(fingerprint);
115
+ return true;
116
+ })
117
+ .sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line);
118
+ if (deduped.length > config.review.maxComments) {
119
+ deduped = deduped.slice(0, config.review.maxComments);
120
+ }
121
+ return { comments: deduped };
122
+ }
123
+ //# sourceMappingURL=reviewer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviewer.js","sourceRoot":"","sources":["../../src/core/reviewer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { CodeReviewConfig } from "../types";
2
+ export declare function generateSummary(diff: string, config: CodeReviewConfig): Promise<string | null>;
3
+ //# sourceMappingURL=summarizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summarizer.d.ts","sourceRoot":"","sources":["../../src/core/summarizer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AA8BjD,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiBxB"}
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateSummary = generateSummary;
4
+ const diff_1 = require("./diff");
5
+ const model_1 = require("./model");
6
+ const prompt_1 = require("./prompt");
7
+ function cleanMarkdownResponse(content) {
8
+ let text = content.trim();
9
+ if (text.startsWith("```markdown"))
10
+ text = text.slice("```markdown".length);
11
+ else if (text.startsWith("```md"))
12
+ text = text.slice("```md".length);
13
+ else if (text.startsWith("```json"))
14
+ text = text.slice("```json".length);
15
+ else if (text.startsWith("```"))
16
+ text = text.slice(3);
17
+ if (text.endsWith("```"))
18
+ text = text.slice(0, -3);
19
+ text = text.trim();
20
+ if (text.startsWith("{") || text.startsWith('"')) {
21
+ try {
22
+ const parsed = JSON.parse(text);
23
+ if (typeof parsed === "string")
24
+ return parsed.trim();
25
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
26
+ const first = Object.values(parsed).find((value) => typeof value === "string");
27
+ if (first)
28
+ return first.trim();
29
+ }
30
+ }
31
+ catch {
32
+ // keep text as-is
33
+ }
34
+ }
35
+ return text.replace(/\\n/g, "\n").trim();
36
+ }
37
+ async function generateSummary(diff, config) {
38
+ const effectiveDiff = (0, diff_1.filterDiffByIgnore)(diff, config.review.ignore);
39
+ if (!effectiveDiff.trim())
40
+ return null;
41
+ if (!config.ai.apiKey || !config.ai.endpoint)
42
+ return null;
43
+ const adapter = (0, model_1.createModelAdapter)(config.ai.endpoint, config.ai.apiKey, config.ai.apiFormat);
44
+ const prompt = new prompt_1.SummaryPromptBuilder().setDiff(effectiveDiff);
45
+ const raw = await adapter.call(config.ai.model, prompt.buildSystem(), prompt.buildUser());
46
+ return raw ? cleanMarkdownResponse(raw) : null;
47
+ }
48
+ //# sourceMappingURL=summarizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summarizer.js","sourceRoot":"","sources":["../../src/core/summarizer.ts"],"names":[],"mappings":"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"}
package/dist/diff.d.ts CHANGED
@@ -1,16 +1,6 @@
1
1
  import type { AIComment } from "./types";
2
2
  export declare function globToRegExp(pattern: string): RegExp;
3
3
  export declare function filterDiffByIgnore(diff: string, ignorePatterns?: string[]): string;
4
- export interface AddedLine {
5
- file: string;
6
- line: number;
7
- content: string;
8
- }
9
- export declare function normalizePath(path: string): string;
10
- export declare function collectAddedLines(diff: string): Map<string, AddedLine[]>;
11
- export declare function getChangedFiles(diff: string): string[];
12
- export declare function splitDiffByFile(diff: string): string[];
13
- export declare function splitDiffByMaxBytes(diff: string, maxBytes: number): string[];
14
4
  export declare function buildAddedLinesIndexText(diff: string, maxLines?: number): string;
15
5
  export declare function alignCommentsToDiffAddedLines(diff: string, comments: AIComment[]): AIComment[];
16
6
  //# sourceMappingURL=diff.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAgBpD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAmBlF;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CA8CxE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAatD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAgBtD;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAmB5E;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAO,GAAG,MAAM,CAU9E;AAED,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,SAAS,EAAE,GACpB,SAAS,EAAE,CAqBb"}
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAgBpD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAmBlF;AA4DD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAO,GAAG,MAAM,CAU9E;AAED,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,SAAS,EAAE,GACpB,SAAS,EAAE,CAqBb"}
package/dist/diff.js CHANGED
@@ -2,11 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.globToRegExp = globToRegExp;
4
4
  exports.filterDiffByIgnore = filterDiffByIgnore;
5
- exports.normalizePath = normalizePath;
6
- exports.collectAddedLines = collectAddedLines;
7
- exports.getChangedFiles = getChangedFiles;
8
- exports.splitDiffByFile = splitDiffByFile;
9
- exports.splitDiffByMaxBytes = splitDiffByMaxBytes;
10
5
  exports.buildAddedLinesIndexText = buildAddedLinesIndexText;
11
6
  exports.alignCommentsToDiffAddedLines = alignCommentsToDiffAddedLines;
12
7
  function globToRegExp(pattern) {
@@ -97,55 +92,6 @@ function collectAddedLines(diff) {
97
92
  }
98
93
  return files;
99
94
  }
100
- function getChangedFiles(diff) {
101
- const files = new Set();
102
- for (const raw of diff.split("\n")) {
103
- if (raw.startsWith("diff --git ")) {
104
- const match = /^diff --git a\/(.+?) b\/(.+)$/.exec(raw);
105
- if (match)
106
- files.add(normalizePath(match[2]));
107
- continue;
108
- }
109
- if (raw.startsWith("+++ b/")) {
110
- files.add(normalizePath(raw.slice("+++ b/".length)));
111
- }
112
- }
113
- return [...files];
114
- }
115
- function splitDiffByFile(diff) {
116
- const sections = [];
117
- let current = [];
118
- for (const line of diff.split("\n")) {
119
- if (line.startsWith("diff --git ") && current.length > 0) {
120
- sections.push(current.join("\n"));
121
- current = [];
122
- }
123
- current.push(line);
124
- }
125
- if (current.some((line) => line.trim())) {
126
- sections.push(current.join("\n"));
127
- }
128
- return sections.length ? sections : [diff];
129
- }
130
- function splitDiffByMaxBytes(diff, maxBytes) {
131
- const files = splitDiffByFile(diff);
132
- const shards = [];
133
- let current = [];
134
- let currentBytes = 0;
135
- for (const fileDiff of files) {
136
- const fileBytes = Buffer.byteLength(fileDiff);
137
- if (current.length > 0 && currentBytes + fileBytes > maxBytes) {
138
- shards.push(current.join("\n"));
139
- current = [];
140
- currentBytes = 0;
141
- }
142
- current.push(fileDiff);
143
- currentBytes += fileBytes;
144
- }
145
- if (current.length > 0)
146
- shards.push(current.join("\n"));
147
- return shards;
148
- }
149
95
  function buildAddedLinesIndexText(diff, maxLines = 5000) {
150
96
  const rows = [];
151
97
  for (const [file, lines] of collectAddedLines(diff)) {
package/dist/diff.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"diff.js","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { AIComment } from "../types";
2
+ export declare function postGitlabDiscussions(options: {
3
+ comments: AIComment[];
4
+ diff?: string;
5
+ token?: string;
6
+ env?: NodeJS.ProcessEnv;
7
+ }): Promise<boolean>;
8
+ export declare function postGitlabSummary(options: {
9
+ markdown: string;
10
+ token?: string;
11
+ env?: NodeJS.ProcessEnv;
12
+ }): Promise<boolean>;
13
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/gitlab/api.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AA2O1C,wBAAsB,qBAAqB,CAAC,OAAO,EAAE;IACnD,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB,GAAG,OAAO,CAAC,OAAO,CAAC,CAkHnB;AAED,wBAAsB,iBAAiB,CAAC,OAAO,EAAE;IAC/C,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB,GAAG,OAAO,CAAC,OAAO,CAAC,CAgDnB"}
@@ -0,0 +1,317 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.postGitlabDiscussions = postGitlabDiscussions;
4
+ exports.postGitlabSummary = postGitlabSummary;
5
+ const constants_1 = require("../constants");
6
+ const diff_1 = require("../core/diff");
7
+ const http_1 = require("../shared/http");
8
+ const identity_1 = require("../shared/identity");
9
+ /**
10
+ * Facade: encapsulates all low-level GitLab REST API interactions.
11
+ * Consumers use high-level methods without knowing pagination, URL construction, or auth headers.
12
+ */
13
+ class GitlabApiFacade {
14
+ constructor(token, env) {
15
+ this.token = token;
16
+ this.env = env;
17
+ }
18
+ buildApiUrl(suffix) {
19
+ if (!this.env.CI_API_V4_URL || !this.env.CI_PROJECT_ID || !this.env.CI_MERGE_REQUEST_IID) {
20
+ return null;
21
+ }
22
+ const apiBase = this.env.CI_API_V4_URL.replace(/\/+$/, "");
23
+ const projectId = encodeURIComponent(this.env.CI_PROJECT_ID);
24
+ const mrIid = encodeURIComponent(this.env.CI_MERGE_REQUEST_IID);
25
+ return `${apiBase}/projects/${projectId}/merge_requests/${mrIid}${suffix}`;
26
+ }
27
+ fetch(url, init = {}) {
28
+ return (0, http_1.fetchWithTimeout)(url, init, constants_1.API_TIMEOUT_MS);
29
+ }
30
+ authHeaders() {
31
+ return { Authorization: `Bearer ${this.token}` };
32
+ }
33
+ get discussionUrl() {
34
+ return this.buildApiUrl("/discussions");
35
+ }
36
+ get noteUrl() {
37
+ return this.buildApiUrl("/notes");
38
+ }
39
+ async fetchCurrentUser() {
40
+ const apiBase = this.env.CI_API_V4_URL?.replace(/\/+$/, "");
41
+ if (!apiBase)
42
+ return null;
43
+ try {
44
+ const resp = await this.fetch(`${apiBase}/user`, {
45
+ headers: this.authHeaders(),
46
+ });
47
+ if (!resp.ok) {
48
+ console.error(`[gitlab] fetch current user failed status=${resp.status}`);
49
+ return null;
50
+ }
51
+ return await (0, http_1.parseJsonSafe)(resp);
52
+ }
53
+ catch (err) {
54
+ console.error(`[gitlab] fetch current user error: ${err instanceof Error ? err.message : err}`);
55
+ return null;
56
+ }
57
+ }
58
+ async fetchMergeRequest() {
59
+ const url = this.buildApiUrl("");
60
+ if (!url)
61
+ return null;
62
+ try {
63
+ const resp = await this.fetch(url, {
64
+ headers: this.authHeaders(),
65
+ });
66
+ if (!resp.ok) {
67
+ console.error(`[gitlab] merge request fetch failed status=${resp.status}`);
68
+ return null;
69
+ }
70
+ return await (0, http_1.parseJsonSafe)(resp);
71
+ }
72
+ catch (err) {
73
+ console.error(`[gitlab] merge request fetch error: ${err instanceof Error ? err.message : err}`);
74
+ return null;
75
+ }
76
+ }
77
+ async fetchAllPages(url) {
78
+ const results = [];
79
+ let page = 1;
80
+ while (page <= constants_1.MAX_PAGINATION_PAGES) {
81
+ const sep = url.includes("?") ? "&" : "?";
82
+ let resp;
83
+ try {
84
+ resp = await this.fetch(`${url}${sep}per_page=100&page=${page}`, { headers: this.authHeaders() });
85
+ }
86
+ catch {
87
+ console.error(`[gitlab] pagination request failed page=${page}`);
88
+ break;
89
+ }
90
+ if (!resp.ok)
91
+ break;
92
+ const items = await (0, http_1.parseJsonSafe)(resp);
93
+ if (!items?.length)
94
+ break;
95
+ results.push(...items);
96
+ if (items.length < 100)
97
+ break;
98
+ page += 1;
99
+ }
100
+ return results;
101
+ }
102
+ async postDiscussion(body) {
103
+ const url = this.discussionUrl;
104
+ if (!url)
105
+ return null;
106
+ return this.fetch(url, {
107
+ method: "POST",
108
+ headers: { "Content-Type": "application/json", ...this.authHeaders() },
109
+ body: JSON.stringify(body),
110
+ });
111
+ }
112
+ async postNote(body) {
113
+ const url = this.noteUrl;
114
+ if (!url)
115
+ return null;
116
+ return this.fetch(url, {
117
+ method: "POST",
118
+ headers: { "Content-Type": "application/json", ...this.authHeaders() },
119
+ body: JSON.stringify(body),
120
+ });
121
+ }
122
+ async updateNote(discussionId, noteId, body) {
123
+ const baseUrl = this.discussionUrl;
124
+ if (!baseUrl)
125
+ return false;
126
+ const resp = await this.fetch(`${baseUrl}/${discussionId}/notes/${noteId}`, {
127
+ method: "PUT",
128
+ headers: { "Content-Type": "application/json", ...this.authHeaders() },
129
+ body: JSON.stringify({ body }),
130
+ });
131
+ return resp.ok;
132
+ }
133
+ async deleteNote(discussionId, noteId) {
134
+ const baseUrl = this.discussionUrl;
135
+ if (!baseUrl)
136
+ return false;
137
+ const resp = await this.fetch(`${baseUrl}/${discussionId}/notes/${noteId}`, {
138
+ method: "DELETE",
139
+ headers: this.authHeaders(),
140
+ });
141
+ return resp.ok || resp.status === 204;
142
+ }
143
+ }
144
+ function buildCommentBody(comment) {
145
+ const message = comment.message || constants_1.DEFAULT_COMMENT_MESSAGE;
146
+ const body = comment.suggestion
147
+ ? `${message}\n\n建议:${comment.suggestion}`
148
+ : message;
149
+ return `${body}\n\n${(0, identity_1.buildHiddenMarker)(identity_1.COMMENT_MARKER_PREFIX, (0, identity_1.buildCommentFingerprint)(comment))}`;
150
+ }
151
+ function collectBotNotesByMarker(discussions, userId, markerKind) {
152
+ const notes = new Map();
153
+ for (const discussion of discussions) {
154
+ for (const note of discussion.notes) {
155
+ if (note.author.id !== userId || note.system || !note.body)
156
+ continue;
157
+ const fingerprint = (0, identity_1.extractHiddenMarker)(note.body, markerKind);
158
+ if (!fingerprint)
159
+ continue;
160
+ const current = notes.get(fingerprint) ?? [];
161
+ current.push({
162
+ discussionId: discussion.id,
163
+ noteId: note.id,
164
+ body: note.body,
165
+ });
166
+ notes.set(fingerprint, current);
167
+ }
168
+ }
169
+ return notes;
170
+ }
171
+ function buildValidLineSet(diff) {
172
+ const set = new Set();
173
+ for (const [file, lines] of (0, diff_1.collectAddedLines)(diff)) {
174
+ for (const { line } of lines) {
175
+ set.add(`${file}:${line}`);
176
+ }
177
+ }
178
+ return set;
179
+ }
180
+ function isLineValid(validLines, file, line) {
181
+ if (!validLines)
182
+ return true;
183
+ return validLines.has(`${(0, diff_1.normalizePath)(file)}:${line}`);
184
+ }
185
+ async function postGitlabDiscussions(options) {
186
+ const env = options.env ?? process.env;
187
+ if (!options.token) {
188
+ console.error("[gitlab] MR discussions skipped: missing GitLab token");
189
+ return false;
190
+ }
191
+ const facade = new GitlabApiFacade(options.token, env);
192
+ const discussionUrl = facade.discussionUrl;
193
+ if (!discussionUrl) {
194
+ console.error("[gitlab] MR discussions skipped: missing GitLab CI context");
195
+ return false;
196
+ }
197
+ const validLines = options.diff ? buildValidLineSet(options.diff) : null;
198
+ const user = await facade.fetchCurrentUser();
199
+ const discussions = user
200
+ ? await facade.fetchAllPages(discussionUrl)
201
+ : [];
202
+ const existing = user
203
+ ? collectBotNotesByMarker(discussions, user.id, identity_1.COMMENT_MARKER_PREFIX)
204
+ : new Map();
205
+ const activeFingerprints = new Set();
206
+ const mr = options.comments.length
207
+ ? await facade.fetchMergeRequest()
208
+ : null;
209
+ const refs = mr?.diff_refs;
210
+ if (options.comments.length && (!refs?.base_sha || !refs.start_sha || !refs.head_sha)) {
211
+ console.error("[gitlab] MR discussions skipped: missing diff refs");
212
+ return false;
213
+ }
214
+ let posted = 0;
215
+ let updated = 0;
216
+ let skippedInvalid = 0;
217
+ for (const comment of options.comments) {
218
+ if (!comment.file || !comment.line)
219
+ continue;
220
+ if (!isLineValid(validLines, comment.file, comment.line)) {
221
+ skippedInvalid += 1;
222
+ continue;
223
+ }
224
+ const fingerprint = (0, identity_1.buildCommentFingerprint)(comment);
225
+ const body = buildCommentBody(comment);
226
+ activeFingerprints.add(fingerprint);
227
+ const old = existing.get(fingerprint)?.[0];
228
+ try {
229
+ if (old) {
230
+ const ok = await facade.updateNote(old.discussionId, old.noteId, body);
231
+ if (ok) {
232
+ updated += 1;
233
+ }
234
+ else {
235
+ console.error(`[gitlab] MR discussion update failed file=${comment.file} line=${comment.line}`);
236
+ }
237
+ continue;
238
+ }
239
+ const resp = await facade.postDiscussion({
240
+ body,
241
+ position: {
242
+ base_sha: refs.base_sha,
243
+ start_sha: refs.start_sha,
244
+ head_sha: refs.head_sha,
245
+ position_type: "text",
246
+ new_path: comment.file,
247
+ new_line: Number(comment.line),
248
+ },
249
+ });
250
+ if (!resp || !resp.ok) {
251
+ console.error(`[gitlab] MR discussion failed file=${comment.file} line=${comment.line} status=${resp?.status}`);
252
+ continue;
253
+ }
254
+ posted += 1;
255
+ }
256
+ catch (err) {
257
+ console.error(`[gitlab] MR discussion error file=${comment.file} line=${comment.line}: ${err instanceof Error ? err.message : err}`);
258
+ }
259
+ }
260
+ let deleted = 0;
261
+ for (const [fingerprint, oldNotes] of existing) {
262
+ const staleNotes = activeFingerprints.has(fingerprint)
263
+ ? oldNotes.slice(1)
264
+ : oldNotes;
265
+ for (const old of staleNotes) {
266
+ try {
267
+ if (await facade.deleteNote(old.discussionId, old.noteId)) {
268
+ deleted += 1;
269
+ }
270
+ }
271
+ catch (err) {
272
+ console.error(`[gitlab] stale discussion delete error discussion=${old.discussionId} note=${old.noteId}: ${err instanceof Error ? err.message : err}`);
273
+ }
274
+ }
275
+ }
276
+ console.error(`[gitlab] MR discussions lifecycle posted=${posted} updated=${updated} deleted=${deleted} skippedInvalid=${skippedInvalid}`);
277
+ return posted + updated + deleted > 0;
278
+ }
279
+ async function postGitlabSummary(options) {
280
+ const env = options.env ?? process.env;
281
+ const markdown = options.markdown.trim();
282
+ if (!markdown) {
283
+ console.error("[gitlab] summary skipped: empty markdown");
284
+ return false;
285
+ }
286
+ if (!options.token) {
287
+ console.error("[gitlab] summary skipped: missing GitLab token");
288
+ return false;
289
+ }
290
+ const facade = new GitlabApiFacade(options.token, env);
291
+ const discussionUrl = facade.discussionUrl;
292
+ const noteUrl = facade.noteUrl;
293
+ if (!discussionUrl || !noteUrl) {
294
+ console.error("[gitlab] summary skipped: missing GitLab CI context");
295
+ return false;
296
+ }
297
+ const user = await facade.fetchCurrentUser();
298
+ const summaryFingerprint = (0, identity_1.stableHash)(identity_1.SUMMARY_MARKER);
299
+ const body = `${markdown}\n\n${(0, identity_1.buildHiddenMarker)(identity_1.SUMMARY_MARKER, summaryFingerprint)}`;
300
+ if (user) {
301
+ const discussions = await facade.fetchAllPages(discussionUrl);
302
+ const existing = collectBotNotesByMarker(discussions, user.id, identity_1.SUMMARY_MARKER).get(summaryFingerprint)?.[0];
303
+ if (existing) {
304
+ const ok = await facade.updateNote(existing.discussionId, existing.noteId, body);
305
+ console.error(ok ? "[gitlab] summary note updated" : "[gitlab] summary note update failed");
306
+ return ok;
307
+ }
308
+ }
309
+ const resp = await facade.postNote({ body });
310
+ if (!resp || !resp.ok) {
311
+ console.error(`[gitlab] summary note post failed status=${resp?.status}`);
312
+ return false;
313
+ }
314
+ console.error("[gitlab] summary note posted");
315
+ return true;
316
+ }
317
+ //# sourceMappingURL=api.js.map