@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 @@
|
|
|
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,
|
|
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
|