@diff-review-system/drs 1.0.0 → 1.1.2
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/.opencode/agent/github-reviewer.md +22 -7
- package/.opencode/agent/gitlab-reviewer.md +22 -7
- package/.opencode/agent/local-reviewer.md +21 -29
- package/.opencode/agent/review/performance.md +22 -13
- package/.opencode/agent/review/quality.md +22 -13
- package/.opencode/agent/review/security.md +22 -19
- package/.opencode/agent/review/style.md +22 -10
- package/.opencode/opencode.jsonc +7 -19
- package/README.md +175 -69
- package/dist/ci/runner.d.ts.map +1 -1
- package/dist/ci/runner.js +2 -4
- package/dist/ci/runner.js.map +1 -1
- package/dist/cli/index.js +14 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +112 -23
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/review-local.d.ts.map +1 -1
- package/dist/cli/review-local.js +27 -70
- package/dist/cli/review-local.js.map +1 -1
- package/dist/cli/review-mr.d.ts +1 -0
- package/dist/cli/review-mr.d.ts.map +1 -1
- package/dist/cli/review-mr.js +34 -119
- package/dist/cli/review-mr.js.map +1 -1
- package/dist/cli/review-pr.d.ts.map +1 -1
- package/dist/cli/review-pr.js +74 -114
- package/dist/cli/review-pr.js.map +1 -1
- package/dist/github/client.d.ts +199 -4
- package/dist/github/client.d.ts.map +1 -1
- package/dist/github/client.js +37 -2
- package/dist/github/client.js.map +1 -1
- package/dist/github/client.test.d.ts +2 -0
- package/dist/github/client.test.d.ts.map +1 -0
- package/dist/github/client.test.js +206 -0
- package/dist/github/client.test.js.map +1 -0
- package/dist/github/platform-adapter.d.ts +31 -0
- package/dist/github/platform-adapter.d.ts.map +1 -0
- package/dist/github/platform-adapter.js +127 -0
- package/dist/github/platform-adapter.js.map +1 -0
- package/dist/github/platform-adapter.test.d.ts +2 -0
- package/dist/github/platform-adapter.test.d.ts.map +1 -0
- package/dist/github/platform-adapter.test.js +40 -0
- package/dist/github/platform-adapter.test.js.map +1 -0
- package/dist/gitlab/client.d.ts +12 -0
- package/dist/gitlab/client.d.ts.map +1 -1
- package/dist/gitlab/client.js +18 -0
- package/dist/gitlab/client.js.map +1 -1
- package/dist/gitlab/diff-parser.test.d.ts +2 -0
- package/dist/gitlab/diff-parser.test.d.ts.map +1 -0
- package/dist/gitlab/diff-parser.test.js +315 -0
- package/dist/gitlab/diff-parser.test.js.map +1 -0
- package/dist/gitlab/platform-adapter.d.ts +27 -0
- package/dist/gitlab/platform-adapter.d.ts.map +1 -0
- package/dist/gitlab/platform-adapter.js +120 -0
- package/dist/gitlab/platform-adapter.js.map +1 -0
- package/dist/gitlab/platform-adapter.test.d.ts +2 -0
- package/dist/gitlab/platform-adapter.test.d.ts.map +1 -0
- package/dist/gitlab/platform-adapter.test.js +21 -0
- package/dist/gitlab/platform-adapter.test.js.map +1 -0
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +7 -0
- package/dist/index.test.js.map +1 -0
- package/dist/lib/code-quality-report.d.ts +44 -0
- package/dist/lib/code-quality-report.d.ts.map +1 -0
- package/dist/lib/code-quality-report.js +62 -0
- package/dist/lib/code-quality-report.js.map +1 -0
- package/dist/lib/code-quality-report.test.d.ts +2 -0
- package/dist/lib/code-quality-report.test.d.ts.map +1 -0
- package/dist/lib/code-quality-report.test.js +327 -0
- package/dist/lib/code-quality-report.test.js.map +1 -0
- package/dist/{gitlab → lib}/comment-formatter.d.ts +4 -2
- package/dist/lib/comment-formatter.d.ts.map +1 -0
- package/dist/{gitlab → lib}/comment-formatter.js +48 -15
- package/dist/lib/comment-formatter.js.map +1 -0
- package/dist/lib/comment-manager.d.ts +61 -0
- package/dist/lib/comment-manager.d.ts.map +1 -0
- package/dist/lib/comment-manager.js +91 -0
- package/dist/lib/comment-manager.js.map +1 -0
- package/dist/lib/config-model-overrides.test.d.ts +12 -0
- package/dist/lib/config-model-overrides.test.d.ts.map +1 -0
- package/dist/lib/config-model-overrides.test.js +224 -0
- package/dist/lib/config-model-overrides.test.js.map +1 -0
- package/dist/lib/config.d.ts +30 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +70 -11
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/config.test.d.ts +2 -0
- package/dist/lib/config.test.d.ts.map +1 -0
- package/dist/lib/config.test.js +28 -0
- package/dist/lib/config.test.js.map +1 -0
- package/dist/lib/context-loader.d.ts +29 -0
- package/dist/lib/context-loader.d.ts.map +1 -0
- package/dist/lib/context-loader.js +68 -0
- package/dist/lib/context-loader.js.map +1 -0
- package/dist/lib/diff-parser.d.ts.map +1 -0
- package/dist/{gitlab → lib}/diff-parser.js +3 -3
- package/dist/lib/diff-parser.js.map +1 -0
- package/dist/lib/issue-parser.d.ts +29 -0
- package/dist/lib/issue-parser.d.ts.map +1 -0
- package/dist/lib/issue-parser.js +151 -0
- package/dist/lib/issue-parser.js.map +1 -0
- package/dist/lib/issue-parser.test.d.ts +2 -0
- package/dist/lib/issue-parser.test.d.ts.map +1 -0
- package/dist/lib/issue-parser.test.js +281 -0
- package/dist/lib/issue-parser.test.js.map +1 -0
- package/dist/lib/platform-client.d.ts +130 -0
- package/dist/lib/platform-client.d.ts.map +1 -0
- package/dist/lib/platform-client.js +8 -0
- package/dist/lib/platform-client.js.map +1 -0
- package/dist/lib/position-validator.d.ts +36 -0
- package/dist/lib/position-validator.d.ts.map +1 -0
- package/dist/lib/position-validator.js +43 -0
- package/dist/lib/position-validator.js.map +1 -0
- package/dist/lib/review-orchestrator.d.ts +60 -0
- package/dist/lib/review-orchestrator.d.ts.map +1 -0
- package/dist/lib/review-orchestrator.js +183 -0
- package/dist/lib/review-orchestrator.js.map +1 -0
- package/dist/lib/unified-review-executor.d.ts +32 -0
- package/dist/lib/unified-review-executor.d.ts.map +1 -0
- package/dist/lib/unified-review-executor.js +228 -0
- package/dist/lib/unified-review-executor.js.map +1 -0
- package/dist/opencode/agent-loader.d.ts.map +1 -1
- package/dist/opencode/agent-loader.js +5 -10
- package/dist/opencode/agent-loader.js.map +1 -1
- package/dist/opencode/client.d.ts +3 -2
- package/dist/opencode/client.d.ts.map +1 -1
- package/dist/opencode/client.js +141 -28
- package/dist/opencode/client.js.map +1 -1
- package/package.json +28 -19
- package/dist/gitlab/comment-formatter.d.ts.map +0 -1
- package/dist/gitlab/comment-formatter.js.map +0 -1
- package/dist/gitlab/diff-parser.d.ts.map +0 -1
- package/dist/gitlab/diff-parser.js.map +0 -1
- /package/dist/{gitlab → lib}/diff-parser.d.ts +0 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ReviewIssue } from './comment-formatter.js';
|
|
2
|
+
/**
|
|
3
|
+
* Parse review issues from agent response messages
|
|
4
|
+
*
|
|
5
|
+
* Agents should output JSON in the following format:
|
|
6
|
+
* ```json
|
|
7
|
+
* {
|
|
8
|
+
* "issues": [
|
|
9
|
+
* {
|
|
10
|
+
* "category": "SECURITY" | "QUALITY" | "STYLE" | "PERFORMANCE",
|
|
11
|
+
* "severity": "CRITICAL" | "HIGH" | "MEDIUM" | "LOW",
|
|
12
|
+
* "title": "Issue title",
|
|
13
|
+
* "file": "path/to/file.ts",
|
|
14
|
+
* "line": 42,
|
|
15
|
+
* "problem": "Description of the problem",
|
|
16
|
+
* "solution": "Suggested fix",
|
|
17
|
+
* "references": ["https://link1", "https://link2"],
|
|
18
|
+
* "agent": "security"
|
|
19
|
+
* }
|
|
20
|
+
* ]
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare function parseReviewIssues(content: string, agentName?: string): ReviewIssue[];
|
|
25
|
+
/**
|
|
26
|
+
* Extract agent name from session context or message
|
|
27
|
+
*/
|
|
28
|
+
export declare function extractAgentName(message: string): string;
|
|
29
|
+
//# sourceMappingURL=issue-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issue-parser.d.ts","sourceRoot":"","sources":["../../src/lib/issue-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,GAAE,MAAkB,GAAG,WAAW,EAAE,CAuE/F;AAqDD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAOxD"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse review issues from agent response messages
|
|
3
|
+
*
|
|
4
|
+
* Agents should output JSON in the following format:
|
|
5
|
+
* ```json
|
|
6
|
+
* {
|
|
7
|
+
* "issues": [
|
|
8
|
+
* {
|
|
9
|
+
* "category": "SECURITY" | "QUALITY" | "STYLE" | "PERFORMANCE",
|
|
10
|
+
* "severity": "CRITICAL" | "HIGH" | "MEDIUM" | "LOW",
|
|
11
|
+
* "title": "Issue title",
|
|
12
|
+
* "file": "path/to/file.ts",
|
|
13
|
+
* "line": 42,
|
|
14
|
+
* "problem": "Description of the problem",
|
|
15
|
+
* "solution": "Suggested fix",
|
|
16
|
+
* "references": ["https://link1", "https://link2"],
|
|
17
|
+
* "agent": "security"
|
|
18
|
+
* }
|
|
19
|
+
* ]
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export function parseReviewIssues(content, agentName = 'unknown') {
|
|
24
|
+
const issues = [];
|
|
25
|
+
try {
|
|
26
|
+
// Try to find JSON blocks in the content
|
|
27
|
+
// Look for code blocks with ```json or raw JSON objects
|
|
28
|
+
const jsonBlockRegex = /```json\s*([\s\S]*?)\s*```/g;
|
|
29
|
+
let match;
|
|
30
|
+
// First try to find JSON code blocks
|
|
31
|
+
while ((match = jsonBlockRegex.exec(content)) !== null) {
|
|
32
|
+
try {
|
|
33
|
+
const parsed = JSON.parse(match[1]);
|
|
34
|
+
if (parsed.issues && Array.isArray(parsed.issues)) {
|
|
35
|
+
for (const issue of parsed.issues) {
|
|
36
|
+
if (isValidIssue(issue)) {
|
|
37
|
+
issues.push({
|
|
38
|
+
...issue,
|
|
39
|
+
agent: issue.agent || agentName,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
// Continue to next match
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// If no code blocks found, try to find raw JSON objects
|
|
50
|
+
if (issues.length === 0) {
|
|
51
|
+
// Try to parse the entire content as JSON
|
|
52
|
+
try {
|
|
53
|
+
const parsed = JSON.parse(content);
|
|
54
|
+
if (parsed.issues && Array.isArray(parsed.issues)) {
|
|
55
|
+
for (const issue of parsed.issues) {
|
|
56
|
+
if (isValidIssue(issue)) {
|
|
57
|
+
issues.push({
|
|
58
|
+
...issue,
|
|
59
|
+
agent: issue.agent || agentName,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
// Not valid JSON, try to find JSON objects with better bracket matching
|
|
67
|
+
const jsonObjects = extractJsonObjects(content);
|
|
68
|
+
for (const jsonStr of jsonObjects) {
|
|
69
|
+
try {
|
|
70
|
+
const parsed = JSON.parse(jsonStr);
|
|
71
|
+
if (parsed.issues && Array.isArray(parsed.issues)) {
|
|
72
|
+
for (const issue of parsed.issues) {
|
|
73
|
+
if (isValidIssue(issue)) {
|
|
74
|
+
issues.push({
|
|
75
|
+
...issue,
|
|
76
|
+
agent: issue.agent || agentName,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch (e) {
|
|
83
|
+
// Continue to next object
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
console.warn('Failed to parse review issues from content:', error);
|
|
91
|
+
}
|
|
92
|
+
return issues;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Extract JSON objects from text by matching brackets
|
|
96
|
+
*/
|
|
97
|
+
function extractJsonObjects(text) {
|
|
98
|
+
const objects = [];
|
|
99
|
+
let depth = 0;
|
|
100
|
+
let start = -1;
|
|
101
|
+
for (let i = 0; i < text.length; i++) {
|
|
102
|
+
if (text[i] === '{') {
|
|
103
|
+
if (depth === 0) {
|
|
104
|
+
start = i;
|
|
105
|
+
}
|
|
106
|
+
depth++;
|
|
107
|
+
}
|
|
108
|
+
else if (text[i] === '}') {
|
|
109
|
+
depth--;
|
|
110
|
+
if (depth === 0 && start !== -1) {
|
|
111
|
+
const obj = text.substring(start, i + 1);
|
|
112
|
+
// Only consider objects that contain "issues"
|
|
113
|
+
if (obj.includes('"issues"')) {
|
|
114
|
+
objects.push(obj);
|
|
115
|
+
}
|
|
116
|
+
start = -1;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return objects;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Validate that an object has the required ReviewIssue fields
|
|
124
|
+
*/
|
|
125
|
+
function isValidIssue(obj) {
|
|
126
|
+
return (obj &&
|
|
127
|
+
typeof obj === 'object' &&
|
|
128
|
+
typeof obj.category === 'string' &&
|
|
129
|
+
['SECURITY', 'QUALITY', 'STYLE', 'PERFORMANCE'].includes(obj.category) &&
|
|
130
|
+
typeof obj.severity === 'string' &&
|
|
131
|
+
['CRITICAL', 'HIGH', 'MEDIUM', 'LOW'].includes(obj.severity) &&
|
|
132
|
+
typeof obj.title === 'string' &&
|
|
133
|
+
typeof obj.file === 'string' &&
|
|
134
|
+
typeof obj.problem === 'string' &&
|
|
135
|
+
typeof obj.solution === 'string' &&
|
|
136
|
+
(obj.line === undefined || typeof obj.line === 'number') &&
|
|
137
|
+
(obj.references === undefined || Array.isArray(obj.references)) &&
|
|
138
|
+
(obj.agent === undefined || typeof obj.agent === 'string'));
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Extract agent name from session context or message
|
|
142
|
+
*/
|
|
143
|
+
export function extractAgentName(message) {
|
|
144
|
+
// Try to extract from common patterns like "Agent: security" or "Reviewer: quality"
|
|
145
|
+
const agentMatch = message.match(/(?:agent|reviewer):\s*(\w+)/i);
|
|
146
|
+
if (agentMatch) {
|
|
147
|
+
return agentMatch[1];
|
|
148
|
+
}
|
|
149
|
+
return 'unknown';
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=issue-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issue-parser.js","sourceRoot":"","sources":["../../src/lib/issue-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issue-parser.test.d.ts","sourceRoot":"","sources":["../../src/lib/issue-parser.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { parseReviewIssues } from './issue-parser.js';
|
|
3
|
+
describe('parseReviewIssues', () => {
|
|
4
|
+
it('should parse valid JSON code block with issues', () => {
|
|
5
|
+
const content = `Here are my findings:
|
|
6
|
+
|
|
7
|
+
\`\`\`json
|
|
8
|
+
{
|
|
9
|
+
"issues": [
|
|
10
|
+
{
|
|
11
|
+
"category": "SECURITY",
|
|
12
|
+
"severity": "CRITICAL",
|
|
13
|
+
"title": "SQL Injection vulnerability",
|
|
14
|
+
"file": "src/api/users.ts",
|
|
15
|
+
"line": 42,
|
|
16
|
+
"problem": "Query uses string concatenation",
|
|
17
|
+
"solution": "Use parameterized queries",
|
|
18
|
+
"references": ["https://owasp.org/sql-injection"],
|
|
19
|
+
"agent": "security"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
\`\`\``;
|
|
24
|
+
const issues = parseReviewIssues(content, 'security');
|
|
25
|
+
expect(issues).toHaveLength(1);
|
|
26
|
+
expect(issues[0]).toEqual({
|
|
27
|
+
category: 'SECURITY',
|
|
28
|
+
severity: 'CRITICAL',
|
|
29
|
+
title: 'SQL Injection vulnerability',
|
|
30
|
+
file: 'src/api/users.ts',
|
|
31
|
+
line: 42,
|
|
32
|
+
problem: 'Query uses string concatenation',
|
|
33
|
+
solution: 'Use parameterized queries',
|
|
34
|
+
references: ['https://owasp.org/sql-injection'],
|
|
35
|
+
agent: 'security',
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
it('should parse multiple issues in a single JSON block', () => {
|
|
39
|
+
const content = `\`\`\`json
|
|
40
|
+
{
|
|
41
|
+
"issues": [
|
|
42
|
+
{
|
|
43
|
+
"category": "QUALITY",
|
|
44
|
+
"severity": "HIGH",
|
|
45
|
+
"title": "High complexity function",
|
|
46
|
+
"file": "src/utils/helper.ts",
|
|
47
|
+
"line": 10,
|
|
48
|
+
"problem": "Function has cyclomatic complexity of 15",
|
|
49
|
+
"solution": "Break into smaller functions",
|
|
50
|
+
"agent": "quality"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"category": "QUALITY",
|
|
54
|
+
"severity": "MEDIUM",
|
|
55
|
+
"title": "Code duplication",
|
|
56
|
+
"file": "src/utils/helper.ts",
|
|
57
|
+
"line": 50,
|
|
58
|
+
"problem": "Duplicated validation logic",
|
|
59
|
+
"solution": "Extract to shared validator function"
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
\`\`\``;
|
|
64
|
+
const issues = parseReviewIssues(content, 'quality');
|
|
65
|
+
expect(issues).toHaveLength(2);
|
|
66
|
+
expect(issues[0].severity).toBe('HIGH');
|
|
67
|
+
expect(issues[1].severity).toBe('MEDIUM');
|
|
68
|
+
expect(issues[1].agent).toBe('quality'); // Should use default agent name
|
|
69
|
+
});
|
|
70
|
+
it('should parse raw JSON without code block markers', () => {
|
|
71
|
+
const content = `{"issues":[{"category":"PERFORMANCE","severity":"LOW","title":"Inefficient loop","file":"src/app.ts","line":5,"problem":"Using nested loops","solution":"Use hash map"}]}`;
|
|
72
|
+
const issues = parseReviewIssues(content, 'performance');
|
|
73
|
+
expect(issues).toHaveLength(1);
|
|
74
|
+
expect(issues[0].category).toBe('PERFORMANCE');
|
|
75
|
+
expect(issues[0].file).toBe('src/app.ts');
|
|
76
|
+
});
|
|
77
|
+
it('should handle issues without line numbers', () => {
|
|
78
|
+
const content = `\`\`\`json
|
|
79
|
+
{
|
|
80
|
+
"issues": [
|
|
81
|
+
{
|
|
82
|
+
"category": "STYLE",
|
|
83
|
+
"severity": "LOW",
|
|
84
|
+
"title": "Missing file header",
|
|
85
|
+
"file": "src/main.ts",
|
|
86
|
+
"problem": "No copyright header",
|
|
87
|
+
"solution": "Add standard file header",
|
|
88
|
+
"agent": "style"
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
\`\`\``;
|
|
93
|
+
const issues = parseReviewIssues(content, 'style');
|
|
94
|
+
expect(issues).toHaveLength(1);
|
|
95
|
+
expect(issues[0].line).toBeUndefined();
|
|
96
|
+
});
|
|
97
|
+
it('should handle issues without references', () => {
|
|
98
|
+
const content = `\`\`\`json
|
|
99
|
+
{
|
|
100
|
+
"issues": [
|
|
101
|
+
{
|
|
102
|
+
"category": "QUALITY",
|
|
103
|
+
"severity": "MEDIUM",
|
|
104
|
+
"title": "Long function",
|
|
105
|
+
"file": "src/utils.ts",
|
|
106
|
+
"line": 100,
|
|
107
|
+
"problem": "Function exceeds 50 lines",
|
|
108
|
+
"solution": "Refactor into smaller functions",
|
|
109
|
+
"agent": "quality"
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
\`\`\``;
|
|
114
|
+
const issues = parseReviewIssues(content, 'quality');
|
|
115
|
+
expect(issues).toHaveLength(1);
|
|
116
|
+
expect(issues[0].references).toBeUndefined();
|
|
117
|
+
});
|
|
118
|
+
it('should return empty array for invalid JSON', () => {
|
|
119
|
+
const content = 'This is not valid JSON';
|
|
120
|
+
const issues = parseReviewIssues(content);
|
|
121
|
+
expect(issues).toEqual([]);
|
|
122
|
+
});
|
|
123
|
+
it('should return empty array for JSON without issues array', () => {
|
|
124
|
+
const content = `\`\`\`json
|
|
125
|
+
{
|
|
126
|
+
"message": "No issues found"
|
|
127
|
+
}
|
|
128
|
+
\`\`\``;
|
|
129
|
+
const issues = parseReviewIssues(content);
|
|
130
|
+
expect(issues).toEqual([]);
|
|
131
|
+
});
|
|
132
|
+
it('should skip invalid issues that are missing required fields', () => {
|
|
133
|
+
const content = `\`\`\`json
|
|
134
|
+
{
|
|
135
|
+
"issues": [
|
|
136
|
+
{
|
|
137
|
+
"category": "SECURITY",
|
|
138
|
+
"severity": "HIGH",
|
|
139
|
+
"title": "Missing problem field",
|
|
140
|
+
"file": "src/test.ts",
|
|
141
|
+
"solution": "Fix it"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"category": "QUALITY",
|
|
145
|
+
"severity": "MEDIUM",
|
|
146
|
+
"title": "Valid issue",
|
|
147
|
+
"file": "src/valid.ts",
|
|
148
|
+
"line": 10,
|
|
149
|
+
"problem": "This is valid",
|
|
150
|
+
"solution": "This has all required fields"
|
|
151
|
+
}
|
|
152
|
+
]
|
|
153
|
+
}
|
|
154
|
+
\`\`\``;
|
|
155
|
+
const issues = parseReviewIssues(content);
|
|
156
|
+
// Should only parse the valid issue
|
|
157
|
+
expect(issues).toHaveLength(1);
|
|
158
|
+
expect(issues[0].title).toBe('Valid issue');
|
|
159
|
+
});
|
|
160
|
+
it('should reject issues with invalid category', () => {
|
|
161
|
+
const content = `\`\`\`json
|
|
162
|
+
{
|
|
163
|
+
"issues": [
|
|
164
|
+
{
|
|
165
|
+
"category": "INVALID_CATEGORY",
|
|
166
|
+
"severity": "HIGH",
|
|
167
|
+
"title": "Test",
|
|
168
|
+
"file": "test.ts",
|
|
169
|
+
"problem": "Problem",
|
|
170
|
+
"solution": "Solution"
|
|
171
|
+
}
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
\`\`\``;
|
|
175
|
+
const issues = parseReviewIssues(content);
|
|
176
|
+
expect(issues).toEqual([]);
|
|
177
|
+
});
|
|
178
|
+
it('should reject issues with invalid severity', () => {
|
|
179
|
+
const content = `\`\`\`json
|
|
180
|
+
{
|
|
181
|
+
"issues": [
|
|
182
|
+
{
|
|
183
|
+
"category": "SECURITY",
|
|
184
|
+
"severity": "SUPER_CRITICAL",
|
|
185
|
+
"title": "Test",
|
|
186
|
+
"file": "test.ts",
|
|
187
|
+
"problem": "Problem",
|
|
188
|
+
"solution": "Solution"
|
|
189
|
+
}
|
|
190
|
+
]
|
|
191
|
+
}
|
|
192
|
+
\`\`\``;
|
|
193
|
+
const issues = parseReviewIssues(content);
|
|
194
|
+
expect(issues).toEqual([]);
|
|
195
|
+
});
|
|
196
|
+
it('should handle multiple JSON blocks in same content', () => {
|
|
197
|
+
const content = `First agent findings:
|
|
198
|
+
|
|
199
|
+
\`\`\`json
|
|
200
|
+
{
|
|
201
|
+
"issues": [
|
|
202
|
+
{
|
|
203
|
+
"category": "SECURITY",
|
|
204
|
+
"severity": "HIGH",
|
|
205
|
+
"title": "Issue 1",
|
|
206
|
+
"file": "src/a.ts",
|
|
207
|
+
"line": 1,
|
|
208
|
+
"problem": "Problem 1",
|
|
209
|
+
"solution": "Solution 1",
|
|
210
|
+
"agent": "security"
|
|
211
|
+
}
|
|
212
|
+
]
|
|
213
|
+
}
|
|
214
|
+
\`\`\`
|
|
215
|
+
|
|
216
|
+
Second agent findings:
|
|
217
|
+
|
|
218
|
+
\`\`\`json
|
|
219
|
+
{
|
|
220
|
+
"issues": [
|
|
221
|
+
{
|
|
222
|
+
"category": "QUALITY",
|
|
223
|
+
"severity": "MEDIUM",
|
|
224
|
+
"title": "Issue 2",
|
|
225
|
+
"file": "src/b.ts",
|
|
226
|
+
"line": 2,
|
|
227
|
+
"problem": "Problem 2",
|
|
228
|
+
"solution": "Solution 2",
|
|
229
|
+
"agent": "quality"
|
|
230
|
+
}
|
|
231
|
+
]
|
|
232
|
+
}
|
|
233
|
+
\`\`\``;
|
|
234
|
+
const issues = parseReviewIssues(content);
|
|
235
|
+
expect(issues).toHaveLength(2);
|
|
236
|
+
expect(issues[0].agent).toBe('security');
|
|
237
|
+
expect(issues[1].agent).toBe('quality');
|
|
238
|
+
});
|
|
239
|
+
it('should use provided agent name when issue does not have agent field', () => {
|
|
240
|
+
const content = `\`\`\`json
|
|
241
|
+
{
|
|
242
|
+
"issues": [
|
|
243
|
+
{
|
|
244
|
+
"category": "PERFORMANCE",
|
|
245
|
+
"severity": "LOW",
|
|
246
|
+
"title": "Slow operation",
|
|
247
|
+
"file": "src/perf.ts",
|
|
248
|
+
"line": 20,
|
|
249
|
+
"problem": "Inefficient algorithm",
|
|
250
|
+
"solution": "Use better algorithm"
|
|
251
|
+
}
|
|
252
|
+
]
|
|
253
|
+
}
|
|
254
|
+
\`\`\``;
|
|
255
|
+
const issues = parseReviewIssues(content, 'performance-agent');
|
|
256
|
+
expect(issues).toHaveLength(1);
|
|
257
|
+
expect(issues[0].agent).toBe('performance-agent');
|
|
258
|
+
});
|
|
259
|
+
it('should handle whitespace in JSON code blocks', () => {
|
|
260
|
+
const content = `\`\`\`json
|
|
261
|
+
|
|
262
|
+
{
|
|
263
|
+
"issues": [
|
|
264
|
+
{
|
|
265
|
+
"category": "STYLE",
|
|
266
|
+
"severity": "LOW",
|
|
267
|
+
"title": "Formatting",
|
|
268
|
+
"file": "src/style.ts",
|
|
269
|
+
"line": 1,
|
|
270
|
+
"problem": "Inconsistent formatting",
|
|
271
|
+
"solution": "Run prettier"
|
|
272
|
+
}
|
|
273
|
+
]
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
\`\`\``;
|
|
277
|
+
const issues = parseReviewIssues(content);
|
|
278
|
+
expect(issues).toHaveLength(1);
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
//# sourceMappingURL=issue-parser.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issue-parser.test.js","sourceRoot":"","sources":["../../src/lib/issue-parser.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform abstraction layer for GitHub and GitLab
|
|
3
|
+
*
|
|
4
|
+
* This module provides common interfaces for interacting with different
|
|
5
|
+
* code review platforms (GitHub, GitLab) in a unified way.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Represents a file change in a pull/merge request
|
|
9
|
+
*/
|
|
10
|
+
export interface FileChange {
|
|
11
|
+
/** Path to the file */
|
|
12
|
+
filename: string;
|
|
13
|
+
/** Type of change */
|
|
14
|
+
status: 'added' | 'removed' | 'modified' | 'renamed' | 'copied' | 'changed' | 'unchanged';
|
|
15
|
+
/** Number of lines added */
|
|
16
|
+
additions: number;
|
|
17
|
+
/** Number of lines deleted */
|
|
18
|
+
deletions: number;
|
|
19
|
+
/** Unified diff patch */
|
|
20
|
+
patch?: string;
|
|
21
|
+
/** Previous filename (for renamed files) */
|
|
22
|
+
previousFilename?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Represents a pull/merge request
|
|
26
|
+
*/
|
|
27
|
+
export interface PullRequest {
|
|
28
|
+
/** PR/MR number or ID */
|
|
29
|
+
number: number;
|
|
30
|
+
/** Title */
|
|
31
|
+
title: string;
|
|
32
|
+
/** Description/body */
|
|
33
|
+
description?: string;
|
|
34
|
+
/** Author username or name */
|
|
35
|
+
author: string;
|
|
36
|
+
/** Source branch */
|
|
37
|
+
sourceBranch: string;
|
|
38
|
+
/** Target branch */
|
|
39
|
+
targetBranch: string;
|
|
40
|
+
/** Head commit SHA */
|
|
41
|
+
headSha: string;
|
|
42
|
+
/** Additional platform-specific data */
|
|
43
|
+
platformData?: any;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Represents a comment on a PR/MR
|
|
47
|
+
*/
|
|
48
|
+
export interface Comment {
|
|
49
|
+
/** Comment ID */
|
|
50
|
+
id: number | string;
|
|
51
|
+
/** Comment body/content */
|
|
52
|
+
body: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Position data for inline comments
|
|
56
|
+
*/
|
|
57
|
+
export interface InlineCommentPosition {
|
|
58
|
+
/** File path */
|
|
59
|
+
path: string;
|
|
60
|
+
/** Line number in the new version */
|
|
61
|
+
line: number;
|
|
62
|
+
/** Commit SHA (GitHub) or diff refs (GitLab) */
|
|
63
|
+
commitSha?: string;
|
|
64
|
+
baseSha?: string;
|
|
65
|
+
headSha?: string;
|
|
66
|
+
startSha?: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Common interface for platform clients (GitHub, GitLab, etc.)
|
|
70
|
+
*/
|
|
71
|
+
export interface PlatformClient {
|
|
72
|
+
/**
|
|
73
|
+
* Get pull/merge request details
|
|
74
|
+
*/
|
|
75
|
+
getPullRequest(projectId: string, prNumber: number): Promise<PullRequest>;
|
|
76
|
+
/**
|
|
77
|
+
* Get list of changed files in a PR/MR
|
|
78
|
+
*/
|
|
79
|
+
getChangedFiles(projectId: string, prNumber: number): Promise<FileChange[]>;
|
|
80
|
+
/**
|
|
81
|
+
* Get existing comments on the PR/MR
|
|
82
|
+
*/
|
|
83
|
+
getComments(projectId: string, prNumber: number): Promise<Comment[]>;
|
|
84
|
+
/**
|
|
85
|
+
* Get existing inline/review comments
|
|
86
|
+
*/
|
|
87
|
+
getInlineComments(projectId: string, prNumber: number): Promise<Comment[]>;
|
|
88
|
+
/**
|
|
89
|
+
* Create a general comment on the PR/MR
|
|
90
|
+
*/
|
|
91
|
+
createComment(projectId: string, prNumber: number, body: string): Promise<void>;
|
|
92
|
+
/**
|
|
93
|
+
* Update an existing comment
|
|
94
|
+
*/
|
|
95
|
+
updateComment(projectId: string, prNumber: number, commentId: number | string, body: string): Promise<void>;
|
|
96
|
+
/**
|
|
97
|
+
* Create an inline comment at a specific line
|
|
98
|
+
*/
|
|
99
|
+
createInlineComment(projectId: string, prNumber: number, body: string, position: InlineCommentPosition): Promise<void>;
|
|
100
|
+
/**
|
|
101
|
+
* Create multiple inline comments in bulk (if supported)
|
|
102
|
+
* Falls back to individual comments if not supported
|
|
103
|
+
*/
|
|
104
|
+
createBulkInlineComments(projectId: string, prNumber: number, comments: Array<{
|
|
105
|
+
body: string;
|
|
106
|
+
position: InlineCommentPosition;
|
|
107
|
+
}>): Promise<void>;
|
|
108
|
+
/**
|
|
109
|
+
* Add labels to the PR/MR
|
|
110
|
+
*/
|
|
111
|
+
addLabels(projectId: string, prNumber: number, labels: string[]): Promise<void>;
|
|
112
|
+
/**
|
|
113
|
+
* Check if PR/MR has a specific label
|
|
114
|
+
*/
|
|
115
|
+
hasLabel(projectId: string, prNumber: number, label: string): Promise<boolean>;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Validator for checking if a line can be commented on
|
|
119
|
+
*/
|
|
120
|
+
export interface LineValidator {
|
|
121
|
+
/**
|
|
122
|
+
* Check if a line number is valid for commenting
|
|
123
|
+
*/
|
|
124
|
+
isValidLine(file: string, line: number): boolean;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Factory function type for creating platform clients
|
|
128
|
+
*/
|
|
129
|
+
export type PlatformClientFactory = () => PlatformClient;
|
|
130
|
+
//# sourceMappingURL=platform-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-client.d.ts","sourceRoot":"","sources":["../../src/lib/platform-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-client.js","sourceRoot":"","sources":["../../src/lib/platform-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Position validation utilities for platform-specific inline comment requirements
|
|
3
|
+
*/
|
|
4
|
+
import type { InlineCommentPosition } from './platform-client.js';
|
|
5
|
+
/**
|
|
6
|
+
* Result of position validation
|
|
7
|
+
*/
|
|
8
|
+
export interface PositionValidationResult {
|
|
9
|
+
isValid: boolean;
|
|
10
|
+
error?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Base interface for position validators
|
|
14
|
+
*/
|
|
15
|
+
export interface PositionValidator {
|
|
16
|
+
validate(position: InlineCommentPosition): PositionValidationResult;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* GitHub position validator
|
|
20
|
+
* Requires: commitSha
|
|
21
|
+
*/
|
|
22
|
+
export declare class GitHubPositionValidator implements PositionValidator {
|
|
23
|
+
validate(position: InlineCommentPosition): PositionValidationResult;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* GitLab position validator
|
|
27
|
+
* Requires: baseSha, headSha, startSha
|
|
28
|
+
*/
|
|
29
|
+
export declare class GitLabPositionValidator implements PositionValidator {
|
|
30
|
+
validate(position: InlineCommentPosition): PositionValidationResult;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Helper to validate and throw if invalid
|
|
34
|
+
*/
|
|
35
|
+
export declare function validatePositionOrThrow(position: InlineCommentPosition, validator: PositionValidator): void;
|
|
36
|
+
//# sourceMappingURL=position-validator.d.ts.map
|