@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.
Files changed (135) hide show
  1. package/.opencode/agent/github-reviewer.md +22 -7
  2. package/.opencode/agent/gitlab-reviewer.md +22 -7
  3. package/.opencode/agent/local-reviewer.md +21 -29
  4. package/.opencode/agent/review/performance.md +22 -13
  5. package/.opencode/agent/review/quality.md +22 -13
  6. package/.opencode/agent/review/security.md +22 -19
  7. package/.opencode/agent/review/style.md +22 -10
  8. package/.opencode/opencode.jsonc +7 -19
  9. package/README.md +175 -69
  10. package/dist/ci/runner.d.ts.map +1 -1
  11. package/dist/ci/runner.js +2 -4
  12. package/dist/ci/runner.js.map +1 -1
  13. package/dist/cli/index.js +14 -4
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/cli/init.d.ts.map +1 -1
  16. package/dist/cli/init.js +112 -23
  17. package/dist/cli/init.js.map +1 -1
  18. package/dist/cli/review-local.d.ts.map +1 -1
  19. package/dist/cli/review-local.js +27 -70
  20. package/dist/cli/review-local.js.map +1 -1
  21. package/dist/cli/review-mr.d.ts +1 -0
  22. package/dist/cli/review-mr.d.ts.map +1 -1
  23. package/dist/cli/review-mr.js +34 -119
  24. package/dist/cli/review-mr.js.map +1 -1
  25. package/dist/cli/review-pr.d.ts.map +1 -1
  26. package/dist/cli/review-pr.js +74 -114
  27. package/dist/cli/review-pr.js.map +1 -1
  28. package/dist/github/client.d.ts +199 -4
  29. package/dist/github/client.d.ts.map +1 -1
  30. package/dist/github/client.js +37 -2
  31. package/dist/github/client.js.map +1 -1
  32. package/dist/github/client.test.d.ts +2 -0
  33. package/dist/github/client.test.d.ts.map +1 -0
  34. package/dist/github/client.test.js +206 -0
  35. package/dist/github/client.test.js.map +1 -0
  36. package/dist/github/platform-adapter.d.ts +31 -0
  37. package/dist/github/platform-adapter.d.ts.map +1 -0
  38. package/dist/github/platform-adapter.js +127 -0
  39. package/dist/github/platform-adapter.js.map +1 -0
  40. package/dist/github/platform-adapter.test.d.ts +2 -0
  41. package/dist/github/platform-adapter.test.d.ts.map +1 -0
  42. package/dist/github/platform-adapter.test.js +40 -0
  43. package/dist/github/platform-adapter.test.js.map +1 -0
  44. package/dist/gitlab/client.d.ts +12 -0
  45. package/dist/gitlab/client.d.ts.map +1 -1
  46. package/dist/gitlab/client.js +18 -0
  47. package/dist/gitlab/client.js.map +1 -1
  48. package/dist/gitlab/diff-parser.test.d.ts +2 -0
  49. package/dist/gitlab/diff-parser.test.d.ts.map +1 -0
  50. package/dist/gitlab/diff-parser.test.js +315 -0
  51. package/dist/gitlab/diff-parser.test.js.map +1 -0
  52. package/dist/gitlab/platform-adapter.d.ts +27 -0
  53. package/dist/gitlab/platform-adapter.d.ts.map +1 -0
  54. package/dist/gitlab/platform-adapter.js +120 -0
  55. package/dist/gitlab/platform-adapter.js.map +1 -0
  56. package/dist/gitlab/platform-adapter.test.d.ts +2 -0
  57. package/dist/gitlab/platform-adapter.test.d.ts.map +1 -0
  58. package/dist/gitlab/platform-adapter.test.js +21 -0
  59. package/dist/gitlab/platform-adapter.test.js.map +1 -0
  60. package/dist/index.test.d.ts +2 -0
  61. package/dist/index.test.d.ts.map +1 -0
  62. package/dist/index.test.js +7 -0
  63. package/dist/index.test.js.map +1 -0
  64. package/dist/lib/code-quality-report.d.ts +44 -0
  65. package/dist/lib/code-quality-report.d.ts.map +1 -0
  66. package/dist/lib/code-quality-report.js +62 -0
  67. package/dist/lib/code-quality-report.js.map +1 -0
  68. package/dist/lib/code-quality-report.test.d.ts +2 -0
  69. package/dist/lib/code-quality-report.test.d.ts.map +1 -0
  70. package/dist/lib/code-quality-report.test.js +327 -0
  71. package/dist/lib/code-quality-report.test.js.map +1 -0
  72. package/dist/{gitlab → lib}/comment-formatter.d.ts +4 -2
  73. package/dist/lib/comment-formatter.d.ts.map +1 -0
  74. package/dist/{gitlab → lib}/comment-formatter.js +48 -15
  75. package/dist/lib/comment-formatter.js.map +1 -0
  76. package/dist/lib/comment-manager.d.ts +61 -0
  77. package/dist/lib/comment-manager.d.ts.map +1 -0
  78. package/dist/lib/comment-manager.js +91 -0
  79. package/dist/lib/comment-manager.js.map +1 -0
  80. package/dist/lib/config-model-overrides.test.d.ts +12 -0
  81. package/dist/lib/config-model-overrides.test.d.ts.map +1 -0
  82. package/dist/lib/config-model-overrides.test.js +224 -0
  83. package/dist/lib/config-model-overrides.test.js.map +1 -0
  84. package/dist/lib/config.d.ts +30 -1
  85. package/dist/lib/config.d.ts.map +1 -1
  86. package/dist/lib/config.js +70 -11
  87. package/dist/lib/config.js.map +1 -1
  88. package/dist/lib/config.test.d.ts +2 -0
  89. package/dist/lib/config.test.d.ts.map +1 -0
  90. package/dist/lib/config.test.js +28 -0
  91. package/dist/lib/config.test.js.map +1 -0
  92. package/dist/lib/context-loader.d.ts +29 -0
  93. package/dist/lib/context-loader.d.ts.map +1 -0
  94. package/dist/lib/context-loader.js +68 -0
  95. package/dist/lib/context-loader.js.map +1 -0
  96. package/dist/lib/diff-parser.d.ts.map +1 -0
  97. package/dist/{gitlab → lib}/diff-parser.js +3 -3
  98. package/dist/lib/diff-parser.js.map +1 -0
  99. package/dist/lib/issue-parser.d.ts +29 -0
  100. package/dist/lib/issue-parser.d.ts.map +1 -0
  101. package/dist/lib/issue-parser.js +151 -0
  102. package/dist/lib/issue-parser.js.map +1 -0
  103. package/dist/lib/issue-parser.test.d.ts +2 -0
  104. package/dist/lib/issue-parser.test.d.ts.map +1 -0
  105. package/dist/lib/issue-parser.test.js +281 -0
  106. package/dist/lib/issue-parser.test.js.map +1 -0
  107. package/dist/lib/platform-client.d.ts +130 -0
  108. package/dist/lib/platform-client.d.ts.map +1 -0
  109. package/dist/lib/platform-client.js +8 -0
  110. package/dist/lib/platform-client.js.map +1 -0
  111. package/dist/lib/position-validator.d.ts +36 -0
  112. package/dist/lib/position-validator.d.ts.map +1 -0
  113. package/dist/lib/position-validator.js +43 -0
  114. package/dist/lib/position-validator.js.map +1 -0
  115. package/dist/lib/review-orchestrator.d.ts +60 -0
  116. package/dist/lib/review-orchestrator.d.ts.map +1 -0
  117. package/dist/lib/review-orchestrator.js +183 -0
  118. package/dist/lib/review-orchestrator.js.map +1 -0
  119. package/dist/lib/unified-review-executor.d.ts +32 -0
  120. package/dist/lib/unified-review-executor.d.ts.map +1 -0
  121. package/dist/lib/unified-review-executor.js +228 -0
  122. package/dist/lib/unified-review-executor.js.map +1 -0
  123. package/dist/opencode/agent-loader.d.ts.map +1 -1
  124. package/dist/opencode/agent-loader.js +5 -10
  125. package/dist/opencode/agent-loader.js.map +1 -1
  126. package/dist/opencode/client.d.ts +3 -2
  127. package/dist/opencode/client.d.ts.map +1 -1
  128. package/dist/opencode/client.js +141 -28
  129. package/dist/opencode/client.js.map +1 -1
  130. package/package.json +28 -19
  131. package/dist/gitlab/comment-formatter.d.ts.map +0 -1
  132. package/dist/gitlab/comment-formatter.js.map +0 -1
  133. package/dist/gitlab/diff-parser.d.ts.map +0 -1
  134. package/dist/gitlab/diff-parser.js.map +0 -1
  135. /package/dist/{gitlab → lib}/diff-parser.d.ts +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"position-validator.d.ts","sourceRoot":"","sources":["../../src/lib/position-validator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAElE;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,GAAG,wBAAwB,CAAC;CACrE;AAED;;;GAGG;AACH,qBAAa,uBAAwB,YAAW,iBAAiB;IAC/D,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,GAAG,wBAAwB;CASpE;AAED;;;GAGG;AACH,qBAAa,uBAAwB,YAAW,iBAAiB;IAC/D,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,GAAG,wBAAwB;CASpE;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,qBAAqB,EAC/B,SAAS,EAAE,iBAAiB,GAC3B,IAAI,CAKN"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Position validation utilities for platform-specific inline comment requirements
3
+ */
4
+ /**
5
+ * GitHub position validator
6
+ * Requires: commitSha
7
+ */
8
+ export class GitHubPositionValidator {
9
+ validate(position) {
10
+ if (!position.commitSha) {
11
+ return {
12
+ isValid: false,
13
+ error: 'GitHub requires commitSha for inline comments',
14
+ };
15
+ }
16
+ return { isValid: true };
17
+ }
18
+ }
19
+ /**
20
+ * GitLab position validator
21
+ * Requires: baseSha, headSha, startSha
22
+ */
23
+ export class GitLabPositionValidator {
24
+ validate(position) {
25
+ if (!position.baseSha || !position.headSha || !position.startSha) {
26
+ return {
27
+ isValid: false,
28
+ error: 'GitLab requires baseSha, headSha, and startSha for inline comments',
29
+ };
30
+ }
31
+ return { isValid: true };
32
+ }
33
+ }
34
+ /**
35
+ * Helper to validate and throw if invalid
36
+ */
37
+ export function validatePositionOrThrow(position, validator) {
38
+ const result = validator.validate(position);
39
+ if (!result.isValid) {
40
+ throw new Error(result.error);
41
+ }
42
+ }
43
+ //# sourceMappingURL=position-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"position-validator.js","sourceRoot":"","sources":["../../src/lib/position-validator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAmBH;;;GAGG;AACH,MAAM,OAAO,uBAAuB;IAClC,QAAQ,CAAC,QAA+B;QACtC,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;YACxB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,+CAA+C;aACvD,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,uBAAuB;IAClC,QAAQ,CAAC,QAA+B;QACtC,IAAI,CAAC,QAAQ,CAAC,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;YACjE,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,oEAAoE;aAC5E,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB,CACrC,QAA+B,EAC/B,SAA4B;IAE5B,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC5C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;AACH,CAAC"}
@@ -0,0 +1,60 @@
1
+ import type { DRSConfig } from './config.js';
2
+ import { type OpencodeClient } from '../opencode/client.js';
3
+ import { calculateSummary, type ReviewIssue } from './comment-formatter.js';
4
+ /**
5
+ * Source information for a review (platform-agnostic)
6
+ */
7
+ export interface ReviewSource {
8
+ /** Human-readable name for logging (e.g., "PR #123", "MR !456", "Local diff") */
9
+ name: string;
10
+ /** List of changed file paths */
11
+ files: string[];
12
+ /** Additional context to pass to review agents */
13
+ context: Record<string, any>;
14
+ /** Working directory for the review (defaults to process.cwd()) */
15
+ workingDir?: string;
16
+ }
17
+ /**
18
+ * Result of a review execution
19
+ */
20
+ export interface ReviewResult {
21
+ /** All issues found by review agents */
22
+ issues: ReviewIssue[];
23
+ /** Calculated summary statistics */
24
+ summary: ReturnType<typeof calculateSummary>;
25
+ /** Number of files actually reviewed (after filtering) */
26
+ filesReviewed: number;
27
+ }
28
+ /**
29
+ * Filter files based on ignore patterns in config
30
+ */
31
+ export declare function filterIgnoredFiles(files: string[], config: DRSConfig): string[];
32
+ /**
33
+ * Connect to OpenCode server (or start in-process)
34
+ */
35
+ export declare function connectToOpenCode(config: DRSConfig, workingDir?: string): Promise<OpencodeClient>;
36
+ /**
37
+ * Execute a code review using OpenCode agents
38
+ *
39
+ * This is the core review orchestrator that handles:
40
+ * - File filtering (ignore patterns)
41
+ * - OpenCode connection
42
+ * - Agent execution and streaming
43
+ * - Issue parsing and collection
44
+ * - Summary calculation
45
+ *
46
+ * Platform-specific logic (GitHub/GitLab/local) should:
47
+ * 1. Fetch changed files from their source
48
+ * 2. Call this function with a ReviewSource
49
+ * 3. Handle posting results to their platform
50
+ */
51
+ export declare function executeReview(config: DRSConfig, source: ReviewSource): Promise<ReviewResult>;
52
+ /**
53
+ * Display review summary to terminal (common formatting)
54
+ */
55
+ export declare function displayReviewSummary(result: ReviewResult): void;
56
+ /**
57
+ * Check if review has blocking issues (CRITICAL or HIGH)
58
+ */
59
+ export declare function hasBlockingIssues(result: ReviewResult): boolean;
60
+ //# sourceMappingURL=review-orchestrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-orchestrator.d.ts","sourceRoot":"","sources":["../../src/lib/review-orchestrator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,OAAO,EAAgC,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE1F,OAAO,EAAE,gBAAgB,EAAE,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAG5E;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,wCAAwC;IACxC,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,oCAAoC;IACpC,OAAO,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;IAC7C,0DAA0D;IAC1D,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,SAAS,GAAG,MAAM,EAAE,CAE/E;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,SAAS,EACjB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,cAAc,CAAC,CAoBzB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,YAAY,CAAC,CA8IvB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAgB/D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAE/D"}
@@ -0,0 +1,183 @@
1
+ import chalk from 'chalk';
2
+ import { shouldIgnoreFile, getModelOverrides, getAgentNames } from './config.js';
3
+ import { createOpencodeClientInstance } from '../opencode/client.js';
4
+ import { parseReviewIssues } from './issue-parser.js';
5
+ import { calculateSummary } from './comment-formatter.js';
6
+ import { buildReviewPrompt } from './context-loader.js';
7
+ /**
8
+ * Filter files based on ignore patterns in config
9
+ */
10
+ export function filterIgnoredFiles(files, config) {
11
+ return files.filter((file) => !shouldIgnoreFile(file, config));
12
+ }
13
+ /**
14
+ * Connect to OpenCode server (or start in-process)
15
+ */
16
+ export async function connectToOpenCode(config, workingDir) {
17
+ console.log(chalk.gray('Connecting to OpenCode server...\n'));
18
+ try {
19
+ // Get model overrides from DRS config
20
+ const modelOverrides = getModelOverrides(config);
21
+ return await createOpencodeClientInstance({
22
+ baseUrl: config.opencode.serverUrl || undefined,
23
+ directory: workingDir || process.cwd(),
24
+ modelOverrides,
25
+ });
26
+ }
27
+ catch (error) {
28
+ console.error(chalk.red('✗ Failed to connect to OpenCode server'));
29
+ console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}\n`));
30
+ console.log(chalk.yellow('Please ensure OpenCode server is running or check your configuration.\n'));
31
+ throw error;
32
+ }
33
+ }
34
+ /**
35
+ * Execute a code review using OpenCode agents
36
+ *
37
+ * This is the core review orchestrator that handles:
38
+ * - File filtering (ignore patterns)
39
+ * - OpenCode connection
40
+ * - Agent execution and streaming
41
+ * - Issue parsing and collection
42
+ * - Summary calculation
43
+ *
44
+ * Platform-specific logic (GitHub/GitLab/local) should:
45
+ * 1. Fetch changed files from their source
46
+ * 2. Call this function with a ReviewSource
47
+ * 3. Handle posting results to their platform
48
+ */
49
+ export async function executeReview(config, source) {
50
+ console.log(chalk.gray(`Found ${source.files.length} changed file(s)\n`));
51
+ // Filter files based on ignore patterns
52
+ const filteredFiles = filterIgnoredFiles(source.files, config);
53
+ const ignoredCount = source.files.length - filteredFiles.length;
54
+ if (ignoredCount > 0) {
55
+ console.log(chalk.gray(`Ignoring ${ignoredCount} file(s) based on patterns\n`));
56
+ }
57
+ if (filteredFiles.length === 0) {
58
+ console.log(chalk.yellow('✓ No files to review after filtering\n'));
59
+ return {
60
+ issues: [],
61
+ summary: calculateSummary(0, []),
62
+ filesReviewed: 0,
63
+ };
64
+ }
65
+ console.log(chalk.gray(`Reviewing ${filteredFiles.length} file(s)\n`));
66
+ // Connect to OpenCode
67
+ const opencode = await connectToOpenCode(config, source.workingDir);
68
+ try {
69
+ // Execute review
70
+ console.log(chalk.gray('Starting code analysis...\n'));
71
+ const issues = [];
72
+ const baseInstructions = `Review the following files from ${source.name}:
73
+
74
+ ${filteredFiles.map((f) => `- ${f}`).join('\n')}
75
+
76
+ **Instructions:**
77
+ 1. Use the Read tool to examine each changed file
78
+ 2. Analyze the code for issues in your specialty area
79
+ 3. Output your findings in this JSON format:
80
+
81
+ \`\`\`json
82
+ {
83
+ "issues": [
84
+ {
85
+ "category": "SECURITY" | "QUALITY" | "STYLE" | "PERFORMANCE",
86
+ "severity": "CRITICAL" | "HIGH" | "MEDIUM" | "LOW",
87
+ "title": "Brief title",
88
+ "file": "path/to/file.ts",
89
+ "line": 42,
90
+ "problem": "Description of the problem",
91
+ "solution": "How to fix it",
92
+ "agent": "security" | "quality" | "style" | "performance"
93
+ }
94
+ ]
95
+ }
96
+ \`\`\`
97
+
98
+ Be thorough and identify all issues. Include line numbers when possible.`;
99
+ const agentNames = getAgentNames(config);
100
+ const agentPromises = agentNames.map(async (agentType) => {
101
+ const agentName = `review/${agentType}`;
102
+ console.log(chalk.gray(`Running ${agentType} review...\n`));
103
+ try {
104
+ const reviewPrompt = buildReviewPrompt(agentType, baseInstructions, source.name, filteredFiles);
105
+ const session = await opencode.createSession({
106
+ agent: agentName,
107
+ message: reviewPrompt,
108
+ context: {
109
+ ...source.context,
110
+ files: filteredFiles,
111
+ },
112
+ });
113
+ const agentIssues = [];
114
+ for await (const message of opencode.streamMessages(session.id)) {
115
+ if (message.role === 'assistant') {
116
+ const parsedIssues = parseReviewIssues(message.content);
117
+ if (parsedIssues.length > 0) {
118
+ agentIssues.push(...parsedIssues);
119
+ console.log(chalk.green(`✓ [${agentType}] Found ${parsedIssues.length} issue(s)`));
120
+ }
121
+ }
122
+ }
123
+ await opencode.closeSession(session.id);
124
+ return { agentType, success: true, issues: agentIssues };
125
+ }
126
+ catch (error) {
127
+ console.error(chalk.red(`✗ ${agentType} agent failed: ${error}`));
128
+ return { agentType, success: false, issues: [] };
129
+ }
130
+ });
131
+ const agentResults = await Promise.all(agentPromises);
132
+ const successfulAgents = agentResults.filter((r) => r.success);
133
+ const failedAgents = agentResults.filter((r) => !r.success);
134
+ if (successfulAgents.length === 0) {
135
+ console.error(chalk.red('\n✗ All review agents failed!\n'));
136
+ console.error(chalk.yellow('This usually means:\n' +
137
+ ' 1. Model configuration is incorrect or missing\n' +
138
+ ' 2. API credentials are invalid or missing\n' +
139
+ ' 3. Models are not accessible or timed out\n' +
140
+ ' 4. Agents cannot find files to review\n'));
141
+ await opencode.shutdown();
142
+ process.exit(1);
143
+ }
144
+ if (failedAgents.length > 0) {
145
+ console.log(chalk.yellow(`\n⚠️ ${failedAgents.length} of ${agentResults.length} agents failed: ${failedAgents.map((r) => r.agentType).join(', ')}\n`));
146
+ }
147
+ agentResults.forEach((result) => issues.push(...result.issues));
148
+ const summary = calculateSummary(filteredFiles.length, issues);
149
+ return {
150
+ issues,
151
+ summary,
152
+ filesReviewed: filteredFiles.length,
153
+ };
154
+ }
155
+ finally {
156
+ // Always shut down OpenCode client
157
+ await opencode.shutdown();
158
+ }
159
+ }
160
+ /**
161
+ * Display review summary to terminal (common formatting)
162
+ */
163
+ export function displayReviewSummary(result) {
164
+ console.log(chalk.bold('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
165
+ console.log(chalk.bold('📊 Review Summary'));
166
+ console.log(chalk.bold('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
167
+ console.log(` Files reviewed: ${chalk.cyan(result.summary.filesReviewed)}`);
168
+ console.log(` Issues found: ${chalk.yellow(result.summary.issuesFound)}`);
169
+ if (result.summary.issuesFound > 0) {
170
+ console.log(` 🔴 Critical: ${chalk.red(result.summary.bySeverity.CRITICAL)}`);
171
+ console.log(` 🟡 High: ${chalk.yellow(result.summary.bySeverity.HIGH)}`);
172
+ console.log(` 🟠 Medium: ${chalk.hex('#FFA500')(result.summary.bySeverity.MEDIUM)}`);
173
+ console.log(` ⚪ Low: ${chalk.gray(result.summary.bySeverity.LOW)}`);
174
+ }
175
+ console.log('');
176
+ }
177
+ /**
178
+ * Check if review has blocking issues (CRITICAL or HIGH)
179
+ */
180
+ export function hasBlockingIssues(result) {
181
+ return result.summary.bySeverity.CRITICAL > 0 || result.summary.bySeverity.HIGH > 0;
182
+ }
183
+ //# sourceMappingURL=review-orchestrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-orchestrator.js","sourceRoot":"","sources":["../../src/lib/review-orchestrator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Unified review executor for GitHub and GitLab
3
+ *
4
+ * This module provides a platform-agnostic way to execute code reviews
5
+ * by using the PlatformClient interface.
6
+ */
7
+ import type { DRSConfig } from './config.js';
8
+ import { type ReviewIssue } from './comment-formatter.js';
9
+ import type { PlatformClient, LineValidator, InlineCommentPosition } from './platform-client.js';
10
+ export interface UnifiedReviewOptions {
11
+ /** Platform client (GitHub or GitLab adapter) */
12
+ platformClient: PlatformClient;
13
+ /** Project ID (e.g., "owner/repo" for GitHub, project ID for GitLab) */
14
+ projectId: string;
15
+ /** PR/MR number */
16
+ prNumber: number;
17
+ /** Whether to post comments to the platform */
18
+ postComments: boolean;
19
+ /** Optional path to output GitLab code quality report JSON */
20
+ codeQualityReport?: string;
21
+ /** Optional line validator for checking which lines can be commented */
22
+ lineValidator?: LineValidator;
23
+ /** Optional function to create inline comment position data */
24
+ createInlinePosition?: (issue: ReviewIssue, platformData: any) => InlineCommentPosition;
25
+ /** Working directory for file access */
26
+ workingDir?: string;
27
+ }
28
+ /**
29
+ * Execute a unified code review for any platform
30
+ */
31
+ export declare function executeUnifiedReview(config: DRSConfig, options: UnifiedReviewOptions): Promise<void>;
32
+ //# sourceMappingURL=unified-review-executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unified-review-executor.d.ts","sourceRoot":"","sources":["../../src/lib/unified-review-executor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAI7C,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,wBAAwB,CAAC;AAahC,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAGjG,MAAM,WAAW,oBAAoB;IACnC,iDAAiD;IACjD,cAAc,EAAE,cAAc,CAAC;IAC/B,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAC;IAClB,mBAAmB;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,YAAY,EAAE,OAAO,CAAC;IACtB,8DAA8D;IAC9D,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,wEAAwE;IACxE,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,+DAA+D;IAC/D,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,GAAG,KAAK,qBAAqB,CAAC;IACxF,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAuMf"}
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Unified review executor for GitHub and GitLab
3
+ *
4
+ * This module provides a platform-agnostic way to execute code reviews
5
+ * by using the PlatformClient interface.
6
+ */
7
+ import chalk from 'chalk';
8
+ import { writeFile } from 'fs/promises';
9
+ import { resolve } from 'path';
10
+ import { getAgentNames } from './config.js';
11
+ import { buildReviewPrompt } from './context-loader.js';
12
+ import { parseReviewIssues } from './issue-parser.js';
13
+ import { formatSummaryComment, formatIssueComment, calculateSummary, } from './comment-formatter.js';
14
+ import { BOT_COMMENT_ID, createIssueFingerprint, findExistingSummaryComment, prepareIssuesForPosting, } from './comment-manager.js';
15
+ import { connectToOpenCode, displayReviewSummary, filterIgnoredFiles, } from './review-orchestrator.js';
16
+ import { generateCodeQualityReport, formatCodeQualityReport } from './code-quality-report.js';
17
+ /**
18
+ * Execute a unified code review for any platform
19
+ */
20
+ export async function executeUnifiedReview(config, options) {
21
+ const { platformClient, projectId, prNumber, postComments } = options;
22
+ console.log(chalk.bold.cyan('\n📋 DRS | Code Review Analysis\n'));
23
+ // Fetch PR/MR details
24
+ console.log(chalk.gray(`Fetching PR/MR #${prNumber}...\n`));
25
+ const pr = await platformClient.getPullRequest(projectId, prNumber);
26
+ const allFiles = await platformClient.getChangedFiles(projectId, prNumber);
27
+ console.log(chalk.bold(`PR/MR: ${pr.title}`));
28
+ console.log(chalk.gray(`Author: ${pr.author}`));
29
+ console.log(chalk.gray(`Branch: ${pr.sourceBranch} → ${pr.targetBranch}`));
30
+ console.log(chalk.gray(`Files changed: ${allFiles.length}\n`));
31
+ if (allFiles.length === 0) {
32
+ console.log(chalk.yellow('✓ No changes to review\n'));
33
+ return;
34
+ }
35
+ // Get list of changed files (excluding deleted files)
36
+ const changedFiles = allFiles
37
+ .filter((file) => file.status !== 'removed')
38
+ .map((file) => file.filename);
39
+ if (changedFiles.length === 0) {
40
+ console.log(chalk.yellow('✓ No files to review after filtering\n'));
41
+ return;
42
+ }
43
+ const filteredFiles = filterIgnoredFiles(changedFiles, config);
44
+ const ignoredCount = changedFiles.length - filteredFiles.length;
45
+ if (ignoredCount > 0) {
46
+ console.log(chalk.gray(`Ignoring ${ignoredCount} file(s) based on patterns\n`));
47
+ }
48
+ if (filteredFiles.length === 0) {
49
+ console.log(chalk.yellow('✓ No files to review after filtering\n'));
50
+ return;
51
+ }
52
+ // Connect to OpenCode
53
+ const opencode = await connectToOpenCode(config, options.workingDir || process.cwd());
54
+ try {
55
+ // Execute review
56
+ console.log(chalk.gray('Starting code analysis...\n'));
57
+ const issues = [];
58
+ // Base instructions for review agents
59
+ const baseInstructions = `Review the following files from PR/MR #${prNumber}:
60
+
61
+ ${filteredFiles.map((f) => `- ${f}`).join('\n')}
62
+
63
+ **Instructions:**
64
+ 1. Use the Read tool to examine each changed file
65
+ 2. Analyze the code for issues in your specialty area
66
+ 3. Output your findings in this JSON format:
67
+
68
+ \`\`\`json
69
+ {
70
+ "issues": [
71
+ {
72
+ "category": "SECURITY" | "QUALITY" | "STYLE" | "PERFORMANCE",
73
+ "severity": "CRITICAL" | "HIGH" | "MEDIUM" | "LOW",
74
+ "title": "Brief title",
75
+ "file": "path/to/file.ts",
76
+ "line": 42,
77
+ "problem": "Description of the problem",
78
+ "solution": "How to fix it",
79
+ "agent": "security" | "quality" | "style" | "performance"
80
+ }
81
+ ]
82
+ }
83
+ \`\`\`
84
+
85
+ Be thorough and identify all issues. Include line numbers when possible.`;
86
+ // Invoke all configured review agents in parallel for faster execution
87
+ const agentNames = getAgentNames(config);
88
+ const agentPromises = agentNames.map(async (agentType) => {
89
+ const agentName = `review/${agentType}`;
90
+ console.log(chalk.gray(`Running ${agentType} review...\n`));
91
+ try {
92
+ // Build prompt with global and agent-specific context
93
+ const reviewPrompt = buildReviewPrompt(agentType, baseInstructions, `PR/MR #${prNumber}`, filteredFiles);
94
+ const session = await opencode.createSession({
95
+ agent: agentName,
96
+ message: reviewPrompt,
97
+ context: {
98
+ files: filteredFiles,
99
+ prNumber,
100
+ },
101
+ });
102
+ const agentIssues = [];
103
+ // Collect results from this agent
104
+ for await (const message of opencode.streamMessages(session.id)) {
105
+ if (message.role === 'assistant') {
106
+ // Parse issues from response
107
+ const parsedIssues = parseReviewIssues(message.content);
108
+ if (parsedIssues.length > 0) {
109
+ agentIssues.push(...parsedIssues);
110
+ console.log(chalk.green(`✓ [${agentType}] Found ${parsedIssues.length} issue(s)`));
111
+ }
112
+ }
113
+ }
114
+ await opencode.closeSession(session.id);
115
+ return { agentType, success: true, issues: agentIssues };
116
+ }
117
+ catch (error) {
118
+ console.error(chalk.red(`✗ ${agentType} agent failed: ${error}`));
119
+ return { agentType, success: false, issues: [] };
120
+ }
121
+ });
122
+ // Wait for all agents to complete in parallel
123
+ const agentResults = await Promise.all(agentPromises);
124
+ // Check if all agents failed
125
+ const successfulAgents = agentResults.filter((r) => r.success);
126
+ const failedAgents = agentResults.filter((r) => !r.success);
127
+ if (successfulAgents.length === 0) {
128
+ console.error(chalk.red('\n✗ All review agents failed!\n'));
129
+ console.error(chalk.yellow('This usually means:\n' +
130
+ ' 1. Model configuration is incorrect or missing\n' +
131
+ ' 2. API credentials are invalid or missing\n' +
132
+ ' 3. Models are not accessible or timed out\n' +
133
+ ' 4. Agents cannot find files to review\n'));
134
+ await opencode.shutdown();
135
+ process.exit(1);
136
+ }
137
+ if (failedAgents.length > 0) {
138
+ console.log(chalk.yellow(`\n⚠️ ${failedAgents.length} of ${agentResults.length} agents failed: ${failedAgents.map((r) => r.agentType).join(', ')}\n`));
139
+ }
140
+ // Flatten all issues from successful agents
141
+ agentResults.forEach((result) => issues.push(...result.issues));
142
+ // Display summary
143
+ const summary = calculateSummary(filteredFiles.length, issues);
144
+ displayReviewSummary({ issues, summary, filesReviewed: filteredFiles.length });
145
+ // Post comments to platform if requested
146
+ if (postComments) {
147
+ await postReviewComments(platformClient, projectId, prNumber, summary, issues, pr.platformData, options.lineValidator, options.createInlinePosition);
148
+ }
149
+ // Generate code quality report if requested
150
+ if (options.codeQualityReport) {
151
+ await generateAndWriteCodeQualityReport(issues, options.codeQualityReport, options.workingDir || process.cwd());
152
+ }
153
+ // Exit with error code if critical issues found
154
+ if (summary.bySeverity.CRITICAL > 0) {
155
+ console.log(chalk.red.bold('⚠️ Critical issues found!\n'));
156
+ await opencode.shutdown();
157
+ process.exit(1);
158
+ }
159
+ else if (summary.issuesFound === 0) {
160
+ console.log(chalk.green('✓ No issues found! Code looks good.\n'));
161
+ }
162
+ }
163
+ finally {
164
+ // Shutdown OpenCode
165
+ await opencode.shutdown();
166
+ }
167
+ }
168
+ /**
169
+ * Post review comments to the platform
170
+ */
171
+ async function postReviewComments(platformClient, projectId, prNumber, summary, issues, platformData, lineValidator, createInlinePosition) {
172
+ console.log(chalk.gray('Fetching existing comments...\n'));
173
+ // Fetch existing comments to prevent duplicates
174
+ const [existingComments, existingInlineComments] = await Promise.all([
175
+ platformClient.getComments(projectId, prNumber),
176
+ platformClient.getInlineComments(projectId, prNumber),
177
+ ]);
178
+ // Find our existing summary comment
179
+ const allComments = [
180
+ ...existingComments.map((c) => ({ id: c.id, body: c.body })),
181
+ ...existingInlineComments.map((c) => ({ id: c.id, body: c.body })),
182
+ ];
183
+ const existingSummary = findExistingSummaryComment(existingComments.map((c) => ({ id: c.id, body: c.body })));
184
+ // Post or update summary comment
185
+ console.log(chalk.gray('Posting review summary...\n'));
186
+ const summaryComment = formatSummaryComment(summary, issues, BOT_COMMENT_ID);
187
+ if (existingSummary) {
188
+ await platformClient.updateComment(projectId, prNumber, existingSummary.id, summaryComment);
189
+ console.log(chalk.green('✓ Updated existing review summary'));
190
+ }
191
+ else {
192
+ await platformClient.createComment(projectId, prNumber, summaryComment);
193
+ console.log(chalk.green('✓ Posted new review summary'));
194
+ }
195
+ // Prepare issues for posting: filter to CRITICAL/HIGH, deduplicate, validate lines
196
+ const prepared = prepareIssuesForPosting(issues, allComments, (issue) => {
197
+ if (!issue.line || !lineValidator)
198
+ return false;
199
+ return lineValidator.isValidLine(issue.file, issue.line);
200
+ });
201
+ if (prepared.deduplicatedCount > 0) {
202
+ console.log(chalk.gray(`Skipped ${prepared.deduplicatedCount} duplicate issue(s) already commented\n`));
203
+ }
204
+ // Post inline comments for new CRITICAL/HIGH issues
205
+ if (prepared.inlineIssues.length > 0 && createInlinePosition) {
206
+ const inlineComments = prepared.inlineIssues.map((issue) => ({
207
+ body: formatIssueComment(issue, createIssueFingerprint(issue)),
208
+ position: createInlinePosition(issue, platformData),
209
+ }));
210
+ await platformClient.createBulkInlineComments(projectId, prNumber, inlineComments);
211
+ }
212
+ // Add ai-reviewed label
213
+ await platformClient.addLabels(projectId, prNumber, ['ai-reviewed']);
214
+ console.log(chalk.green('✓ Review posted\n'));
215
+ }
216
+ /**
217
+ * Generate and write GitLab code quality report
218
+ */
219
+ async function generateAndWriteCodeQualityReport(issues, reportPath, workingDir) {
220
+ console.log(chalk.gray('Generating code quality report...\n'));
221
+ const report = generateCodeQualityReport(issues);
222
+ const jsonContent = formatCodeQualityReport(report);
223
+ const fullPath = resolve(workingDir, reportPath);
224
+ await writeFile(fullPath, jsonContent, 'utf-8');
225
+ console.log(chalk.green(`✓ Code quality report written to ${reportPath}`));
226
+ console.log(chalk.gray(` Total issues: ${report.length}\n`));
227
+ }
228
+ //# sourceMappingURL=unified-review-executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unified-review-executor.js","sourceRoot":"","sources":["../../src/lib/unified-review-executor.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"agent-loader.d.ts","sourceRoot":"","sources":["../../src/opencode/agent-loader.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,eAAe,EAAE,CA4BvE;AAuED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAGvF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,eAAe,EAAE,CAGtE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAGxD"}
1
+ {"version":3,"file":"agent-loader.d.ts","sourceRoot":"","sources":["../../src/opencode/agent-loader.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,eAAe,EAAE,CAyBvE;AAqED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAGvF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,eAAe,EAAE,CAGtE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAGxD"}
@@ -12,10 +12,7 @@ import * as yaml from 'yaml';
12
12
  export function loadReviewAgents(projectPath) {
13
13
  const agents = [];
14
14
  // Define search paths in priority order
15
- const agentPaths = [
16
- join(projectPath, '.drs/agents'),
17
- join(projectPath, '.opencode/agent'),
18
- ];
15
+ const agentPaths = [join(projectPath, '.drs/agents'), join(projectPath, '.opencode/agent')];
19
16
  const discovered = new Set();
20
17
  for (const agentPath of agentPaths) {
21
18
  if (!existsSync(agentPath)) {
@@ -73,9 +70,7 @@ function parseAgentFile(filePath, basePath) {
73
70
  const frontmatter = yaml.parse(frontmatterMatch[1]);
74
71
  // Generate agent name from relative path
75
72
  const relativePath = relative(basePath, filePath);
76
- const agentName = relativePath
77
- .replace(/\.md$/, '')
78
- .replace(/\\/g, '/');
73
+ const agentName = relativePath.replace(/\.md$/, '').replace(/\\/g, '/');
79
74
  return {
80
75
  name: agentName,
81
76
  path: filePath,
@@ -96,20 +91,20 @@ function parseAgentFile(filePath, basePath) {
96
91
  */
97
92
  export function getAgent(projectPath, agentName) {
98
93
  const agents = loadReviewAgents(projectPath);
99
- return agents.find(a => a.name === agentName) || null;
94
+ return agents.find((a) => a.name === agentName) || null;
100
95
  }
101
96
  /**
102
97
  * Get all review agents (security, quality, style, performance)
103
98
  */
104
99
  export function getReviewAgents(projectPath) {
105
100
  const agents = loadReviewAgents(projectPath);
106
- return agents.filter(a => a.name.startsWith('review/'));
101
+ return agents.filter((a) => a.name.startsWith('review/'));
107
102
  }
108
103
  /**
109
104
  * List all available agents
110
105
  */
111
106
  export function listAgents(projectPath) {
112
107
  const agents = loadReviewAgents(projectPath);
113
- return agents.map(a => a.name);
108
+ return agents.map((a) => a.name);
114
109
  }
115
110
  //# sourceMappingURL=agent-loader.js.map