@diff-review-system/drs 1.0.0

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 (63) hide show
  1. package/.opencode/agent/github-reviewer.md +62 -0
  2. package/.opencode/agent/gitlab-reviewer.md +62 -0
  3. package/.opencode/agent/local-reviewer.md +71 -0
  4. package/.opencode/agent/review/performance.md +151 -0
  5. package/.opencode/agent/review/quality.md +127 -0
  6. package/.opencode/agent/review/security.md +115 -0
  7. package/.opencode/agent/review/style.md +116 -0
  8. package/.opencode/opencode.jsonc +52 -0
  9. package/LICENSE +201 -0
  10. package/README.md +361 -0
  11. package/dist/ci/runner.d.ts +21 -0
  12. package/dist/ci/runner.d.ts.map +1 -0
  13. package/dist/ci/runner.js +82 -0
  14. package/dist/ci/runner.js.map +1 -0
  15. package/dist/cli/index.d.ts +3 -0
  16. package/dist/cli/index.d.ts.map +1 -0
  17. package/dist/cli/index.js +137 -0
  18. package/dist/cli/index.js.map +1 -0
  19. package/dist/cli/init.d.ts +5 -0
  20. package/dist/cli/init.d.ts.map +1 -0
  21. package/dist/cli/init.js +166 -0
  22. package/dist/cli/init.js.map +1 -0
  23. package/dist/cli/review-local.d.ts +9 -0
  24. package/dist/cli/review-local.d.ts.map +1 -0
  25. package/dist/cli/review-local.js +105 -0
  26. package/dist/cli/review-local.js.map +1 -0
  27. package/dist/cli/review-mr.d.ts +11 -0
  28. package/dist/cli/review-mr.d.ts.map +1 -0
  29. package/dist/cli/review-mr.js +128 -0
  30. package/dist/cli/review-mr.js.map +1 -0
  31. package/dist/cli/review-pr.d.ts +12 -0
  32. package/dist/cli/review-pr.d.ts.map +1 -0
  33. package/dist/cli/review-pr.js +125 -0
  34. package/dist/cli/review-pr.js.map +1 -0
  35. package/dist/github/client.d.ts +1346 -0
  36. package/dist/github/client.d.ts.map +1 -0
  37. package/dist/github/client.js +137 -0
  38. package/dist/github/client.js.map +1 -0
  39. package/dist/gitlab/client.d.ts +55 -0
  40. package/dist/gitlab/client.d.ts.map +1 -0
  41. package/dist/gitlab/client.js +86 -0
  42. package/dist/gitlab/client.js.map +1 -0
  43. package/dist/gitlab/comment-formatter.d.ts +36 -0
  44. package/dist/gitlab/comment-formatter.d.ts.map +1 -0
  45. package/dist/gitlab/comment-formatter.js +118 -0
  46. package/dist/gitlab/comment-formatter.js.map +1 -0
  47. package/dist/gitlab/diff-parser.d.ts +41 -0
  48. package/dist/gitlab/diff-parser.d.ts.map +1 -0
  49. package/dist/gitlab/diff-parser.js +147 -0
  50. package/dist/gitlab/diff-parser.js.map +1 -0
  51. package/dist/lib/config.d.ts +42 -0
  52. package/dist/lib/config.d.ts.map +1 -0
  53. package/dist/lib/config.js +144 -0
  54. package/dist/lib/config.js.map +1 -0
  55. package/dist/opencode/agent-loader.d.ts +31 -0
  56. package/dist/opencode/agent-loader.d.ts.map +1 -0
  57. package/dist/opencode/agent-loader.js +115 -0
  58. package/dist/opencode/agent-loader.js.map +1 -0
  59. package/dist/opencode/client.d.ts +82 -0
  60. package/dist/opencode/client.d.ts.map +1 -0
  61. package/dist/opencode/client.js +184 -0
  62. package/dist/opencode/client.js.map +1 -0
  63. package/package.json +70 -0
@@ -0,0 +1,82 @@
1
+ import chalk from 'chalk';
2
+ import { loadConfig, validateConfig } from '../lib/config.js';
3
+ import { reviewMR } from '../cli/review-mr.js';
4
+ /**
5
+ * Detect CI environment from environment variables
6
+ */
7
+ export function detectCIEnvironment() {
8
+ // GitLab CI detection
9
+ if (process.env.GITLAB_CI === 'true') {
10
+ return {
11
+ platform: 'gitlab',
12
+ projectId: process.env.CI_PROJECT_ID,
13
+ mrIid: process.env.CI_MERGE_REQUEST_IID
14
+ ? parseInt(process.env.CI_MERGE_REQUEST_IID, 10)
15
+ : undefined,
16
+ targetBranch: process.env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME,
17
+ sourceBranch: process.env.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME,
18
+ commitSha: process.env.CI_COMMIT_SHA,
19
+ };
20
+ }
21
+ return { platform: 'unknown' };
22
+ }
23
+ /**
24
+ * Run review in CI/CD environment
25
+ */
26
+ export async function runCIReview() {
27
+ console.log(chalk.bold.cyan('\nšŸ¤– DRS CI/CD Review Runner\n'));
28
+ // Detect environment
29
+ const env = detectCIEnvironment();
30
+ if (env.platform === 'unknown') {
31
+ console.error(chalk.red('Error: Unknown CI environment'));
32
+ console.error(chalk.gray('Currently supported: GitLab CI'));
33
+ process.exit(1);
34
+ }
35
+ console.log(chalk.gray(`Detected CI platform: ${env.platform}\n`));
36
+ // Validate required environment variables
37
+ if (!env.projectId) {
38
+ console.error(chalk.red('Error: CI_PROJECT_ID not found'));
39
+ process.exit(1);
40
+ }
41
+ if (!env.mrIid) {
42
+ console.error(chalk.red('Error: CI_MERGE_REQUEST_IID not found'));
43
+ console.error(chalk.gray('This job should only run on merge requests'));
44
+ process.exit(1);
45
+ }
46
+ // Load configuration
47
+ const projectDir = process.env.CI_PROJECT_DIR || process.cwd();
48
+ const config = loadConfig(projectDir);
49
+ try {
50
+ validateConfig(config);
51
+ }
52
+ catch (error) {
53
+ console.error(chalk.red('Configuration error:'), error instanceof Error ? error.message : String(error));
54
+ process.exit(1);
55
+ }
56
+ console.log(chalk.gray(`Project: ${env.projectId}`));
57
+ console.log(chalk.gray(`MR: !${env.mrIid}`));
58
+ console.log(chalk.gray(`Branch: ${env.sourceBranch} → ${env.targetBranch}\n`));
59
+ // Run review
60
+ try {
61
+ await reviewMR(config, {
62
+ projectId: env.projectId,
63
+ mrIid: env.mrIid,
64
+ postComments: true, // Always post comments in CI
65
+ });
66
+ console.log(chalk.green.bold('\nāœ“ Review complete\n'));
67
+ }
68
+ catch (error) {
69
+ console.error(chalk.red('\nāœ— Review failed\n'));
70
+ console.error(error);
71
+ process.exit(1);
72
+ }
73
+ }
74
+ /**
75
+ * Check if running in CI environment
76
+ */
77
+ export function isCI() {
78
+ return !!(process.env.CI ||
79
+ process.env.GITLAB_CI ||
80
+ process.env.GITHUB_ACTIONS);
81
+ }
82
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/ci/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,137 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import chalk from 'chalk';
4
+ import { reviewLocal } from './review-local.js';
5
+ import { reviewMR } from './review-mr.js';
6
+ import { reviewPR } from './review-pr.js';
7
+ import { loadConfig } from '../lib/config.js';
8
+ const program = new Command();
9
+ program
10
+ .name('drs')
11
+ .description('AI-powered code review bot for GitLab MRs and GitHub PRs using OpenCode SDK')
12
+ .version('1.0.0');
13
+ program
14
+ .command('review-local')
15
+ .description('Review local git diff before pushing')
16
+ .option('--staged', 'Review staged changes only (git diff --cached)')
17
+ .option('--agents <agents>', 'Comma-separated list of review agents (default: security,quality)')
18
+ .option('--format <format>', 'Output format: terminal, json, markdown', 'terminal')
19
+ .option('--verbose', 'Verbose output')
20
+ .action(async (options) => {
21
+ try {
22
+ const config = loadConfig(process.cwd(), {
23
+ review: {
24
+ agents: options.agents ? options.agents.split(',').map((a) => a.trim()) : undefined,
25
+ },
26
+ output: {
27
+ format: options.format,
28
+ verbosity: options.verbose ? 'detailed' : 'normal',
29
+ },
30
+ });
31
+ await reviewLocal(config, {
32
+ staged: options.staged || false,
33
+ });
34
+ }
35
+ catch (error) {
36
+ console.error(chalk.red('Error:'), error instanceof Error ? error.message : String(error));
37
+ process.exit(1);
38
+ }
39
+ });
40
+ program
41
+ .command('review-mr')
42
+ .description('Review a GitLab merge request')
43
+ .requiredOption('--mr <iid>', 'Merge request IID (number)')
44
+ .requiredOption('--project <id>', 'Project ID or path (e.g., "my-org/my-repo" or "123")')
45
+ .option('--agents <agents>', 'Comma-separated list of review agents')
46
+ .option('--post-comments', 'Post review comments to the MR (requires GITLAB_TOKEN)')
47
+ .option('--verbose', 'Verbose output')
48
+ .action(async (options) => {
49
+ try {
50
+ const config = loadConfig(process.cwd(), {
51
+ review: {
52
+ agents: options.agents ? options.agents.split(',').map((a) => a.trim()) : undefined,
53
+ },
54
+ output: {
55
+ verbosity: options.verbose ? 'detailed' : 'normal',
56
+ },
57
+ });
58
+ await reviewMR(config, {
59
+ projectId: options.project,
60
+ mrIid: parseInt(options.mr, 10),
61
+ postComments: options.postComments || false,
62
+ });
63
+ }
64
+ catch (error) {
65
+ console.error(chalk.red('Error:'), error instanceof Error ? error.message : String(error));
66
+ process.exit(1);
67
+ }
68
+ });
69
+ program
70
+ .command('review-pr')
71
+ .description('Review a GitHub pull request')
72
+ .requiredOption('--pr <number>', 'Pull request number')
73
+ .requiredOption('--owner <owner>', 'Repository owner (e.g., "octocat")')
74
+ .requiredOption('--repo <repo>', 'Repository name (e.g., "hello-world")')
75
+ .option('--agents <agents>', 'Comma-separated list of review agents')
76
+ .option('--post-comments', 'Post review comments to the PR (requires GITHUB_TOKEN)')
77
+ .option('--verbose', 'Verbose output')
78
+ .action(async (options) => {
79
+ try {
80
+ const config = loadConfig(process.cwd(), {
81
+ review: {
82
+ agents: options.agents ? options.agents.split(',').map((a) => a.trim()) : undefined,
83
+ },
84
+ output: {
85
+ verbosity: options.verbose ? 'detailed' : 'normal',
86
+ },
87
+ });
88
+ await reviewPR(config, {
89
+ owner: options.owner,
90
+ repo: options.repo,
91
+ prNumber: parseInt(options.pr, 10),
92
+ postComments: options.postComments || false,
93
+ });
94
+ }
95
+ catch (error) {
96
+ console.error(chalk.red('Error:'), error instanceof Error ? error.message : String(error));
97
+ process.exit(1);
98
+ }
99
+ });
100
+ program
101
+ .command('list-agents')
102
+ .description('List available review agents')
103
+ .action(async () => {
104
+ try {
105
+ const { listAgents } = await import('../opencode/agent-loader.js');
106
+ const agents = listAgents(process.cwd());
107
+ console.log(chalk.bold('\nšŸ“‹ Available Review Agents:\n'));
108
+ for (const agent of agents) {
109
+ console.log(chalk.cyan(` • ${agent}`));
110
+ }
111
+ console.log('');
112
+ }
113
+ catch (error) {
114
+ console.error(chalk.red('Error:'), error instanceof Error ? error.message : String(error));
115
+ process.exit(1);
116
+ }
117
+ });
118
+ program
119
+ .command('init')
120
+ .description('Initialize DRS configuration in current project')
121
+ .action(async () => {
122
+ try {
123
+ const { initProject } = await import('./init.js');
124
+ await initProject(process.cwd());
125
+ }
126
+ catch (error) {
127
+ console.error(chalk.red('Error:'), error instanceof Error ? error.message : String(error));
128
+ process.exit(1);
129
+ }
130
+ });
131
+ // Parse arguments
132
+ program.parse(process.argv);
133
+ // Show help if no command provided
134
+ if (!process.argv.slice(2).length) {
135
+ program.outputHelp();
136
+ }
137
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Initialize DRS configuration in a project
3
+ */
4
+ export declare function initProject(projectPath: string): Promise<void>;
5
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AA8EA;;GAEG;AACH,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwGpE"}
@@ -0,0 +1,166 @@
1
+ import { existsSync, mkdirSync, writeFileSync } from 'fs';
2
+ import { join } from 'path';
3
+ import chalk from 'chalk';
4
+ const DEFAULT_DRS_CONFIG = `# DRS Configuration
5
+ # Documentation: https://github.com/your-org/drs
6
+
7
+ review:
8
+ # Review agents to use
9
+ agents:
10
+ - security
11
+ - quality
12
+ - style
13
+ - performance
14
+
15
+ # Automatically review new MRs
16
+ autoReview: true
17
+
18
+ # Review when bot is mentioned
19
+ reviewOnMention: true
20
+
21
+ # Review when these labels are added
22
+ reviewOnLabel:
23
+ - needs-review
24
+ - security-review
25
+
26
+ # Files to ignore during review
27
+ ignorePatterns:
28
+ - "*.test.ts"
29
+ - "*.spec.ts"
30
+ - "**/__tests__/**"
31
+ - "**/__mocks__/**"
32
+ - "*.md"
33
+ - "package-lock.json"
34
+ - "yarn.lock"
35
+ - "pnpm-lock.yaml"
36
+
37
+ output:
38
+ format: terminal
39
+ verbosity: normal
40
+ `;
41
+ const EXAMPLE_GITLAB_CI = `# Example GitLab CI configuration for DRS
42
+ # Add this to your .gitlab-ci.yml file
43
+
44
+ stages:
45
+ - review
46
+ - test
47
+ - deploy
48
+
49
+ # AI Code Review
50
+ ai_review:
51
+ stage: review
52
+ image: node:20
53
+ only:
54
+ - merge_requests
55
+ script:
56
+ - npm install -g @diff-review-system/drs
57
+ - drs review-mr --mr $CI_MERGE_REQUEST_IID --project $CI_PROJECT_ID --post-comments
58
+ variables:
59
+ OPENCODE_SERVER: "http://opencode.internal:3000"
60
+ GITLAB_TOKEN: $CI_JOB_TOKEN
61
+ allow_failure: true
62
+ `;
63
+ const EXAMPLE_ENV = `# DRS Environment Variables
64
+
65
+ # OpenCode Server URL
66
+ OPENCODE_SERVER=http://localhost:3000
67
+
68
+ # GitLab Configuration
69
+ GITLAB_URL=https://gitlab.com
70
+ GITLAB_TOKEN=your-gitlab-token-here
71
+
72
+ # Review Configuration (optional, overrides .drs/drs.config.yaml)
73
+ REVIEW_AGENTS=security,quality,style,performance
74
+ `;
75
+ /**
76
+ * Initialize DRS configuration in a project
77
+ */
78
+ export async function initProject(projectPath) {
79
+ console.log(chalk.bold.cyan('\nšŸš€ Initializing DRS Configuration\n'));
80
+ // Create .drs directory
81
+ const drsDir = join(projectPath, '.drs');
82
+ if (!existsSync(drsDir)) {
83
+ mkdirSync(drsDir, { recursive: true });
84
+ console.log(chalk.green('āœ“'), 'Created', chalk.cyan('.drs/'), 'directory');
85
+ }
86
+ else {
87
+ console.log(chalk.yellow('⚠'), chalk.cyan('.drs/'), 'directory already exists');
88
+ }
89
+ // Create .drs/agents directory
90
+ const agentsDir = join(drsDir, 'agents');
91
+ if (!existsSync(agentsDir)) {
92
+ mkdirSync(agentsDir, { recursive: true });
93
+ console.log(chalk.green('āœ“'), 'Created', chalk.cyan('.drs/agents/'), 'directory');
94
+ }
95
+ // Create drs.config.yaml
96
+ const configPath = join(drsDir, 'drs.config.yaml');
97
+ if (!existsSync(configPath)) {
98
+ writeFileSync(configPath, DEFAULT_DRS_CONFIG, 'utf-8');
99
+ console.log(chalk.green('āœ“'), 'Created', chalk.cyan('.drs/drs.config.yaml'));
100
+ }
101
+ else {
102
+ console.log(chalk.yellow('⚠'), chalk.cyan('.drs/drs.config.yaml'), 'already exists');
103
+ }
104
+ // Create examples directory
105
+ const examplesDir = join(drsDir, 'examples');
106
+ if (!existsSync(examplesDir)) {
107
+ mkdirSync(examplesDir, { recursive: true });
108
+ // Write example GitLab CI config
109
+ writeFileSync(join(examplesDir, 'gitlab-ci.example.yml'), EXAMPLE_GITLAB_CI, 'utf-8');
110
+ // Write example .env file
111
+ writeFileSync(join(examplesDir, '.env.example'), EXAMPLE_ENV, 'utf-8');
112
+ console.log(chalk.green('āœ“'), 'Created example configurations in', chalk.cyan('.drs/examples/'));
113
+ }
114
+ // Create custom agents info
115
+ const customAgentReadme = `# Custom Review Agents
116
+
117
+ Place your custom review agent definitions (markdown files) in this directory.
118
+
119
+ ## Example: Custom Security Agent
120
+
121
+ Create a file \`.drs/agents/security.md\` to override the default security agent:
122
+
123
+ \`\`\`markdown
124
+ ---
125
+ description: Custom security reviewer with project-specific rules
126
+ color: "#E53E3E"
127
+ model: opencode/claude-sonnet-4-5
128
+ tools:
129
+ Read: true
130
+ Glob: true
131
+ Grep: true
132
+ ---
133
+
134
+ You are a security expert for this specific application.
135
+
136
+ ## Project-Specific Security Rules
137
+
138
+ [Add your custom security rules here]
139
+ \`\`\`
140
+
141
+ ## Priority Order
142
+
143
+ DRS loads agents in this order:
144
+ 1. \`.drs/agents/\` (highest priority - project-specific)
145
+ 2. \`.opencode/agent/\` (standard OpenCode location)
146
+ 3. Built-in DRS agents (fallback)
147
+
148
+ ## Learn More
149
+
150
+ - [DRS Documentation](https://github.com/your-org/drs)
151
+ - [OpenCode Agent Guide](https://opencode.ai/docs/agents)
152
+ `;
153
+ const agentsReadmePath = join(agentsDir, 'README.md');
154
+ if (!existsSync(agentsReadmePath)) {
155
+ writeFileSync(agentsReadmePath, customAgentReadme, 'utf-8');
156
+ console.log(chalk.green('āœ“'), 'Created', chalk.cyan('.drs/agents/README.md'));
157
+ }
158
+ // Summary
159
+ console.log(chalk.bold.green('\nāœ“ DRS initialization complete!\n'));
160
+ console.log(chalk.bold('Next steps:\n'));
161
+ console.log(' 1. Edit', chalk.cyan('.drs/drs.config.yaml'), 'to customize review behavior');
162
+ console.log(' 2. Set environment variables (see', chalk.cyan('.drs/examples/.env.example') + ')');
163
+ console.log(' 3. Run', chalk.cyan('drs review-local'), 'to review local changes');
164
+ console.log(' 4. See', chalk.cyan('.drs/examples/gitlab-ci.example.yml'), 'for CI/CD setup\n');
165
+ }
166
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { DRSConfig } from '../lib/config.js';
2
+ export interface ReviewLocalOptions {
3
+ staged: boolean;
4
+ }
5
+ /**
6
+ * Review local git diff before pushing
7
+ */
8
+ export declare function reviewLocal(config: DRSConfig, options: ReviewLocalOptions): Promise<void>;
9
+ //# sourceMappingURL=review-local.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-local.d.ts","sourceRoot":"","sources":["../../src/cli/review-local.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAKlD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmH/F"}
@@ -0,0 +1,105 @@
1
+ import simpleGit from 'simple-git';
2
+ import chalk from 'chalk';
3
+ import { createOpencodeClientInstance } from '../opencode/client.js';
4
+ import { parseDiff, getChangedFiles } from '../gitlab/diff-parser.js';
5
+ import { formatTerminalIssue, calculateSummary } from '../gitlab/comment-formatter.js';
6
+ /**
7
+ * Review local git diff before pushing
8
+ */
9
+ export async function reviewLocal(config, options) {
10
+ console.log(chalk.bold.cyan('\nšŸ” DRS Local Diff Review\n'));
11
+ const git = simpleGit();
12
+ const cwd = process.cwd();
13
+ // Check if we're in a git repository
14
+ const isRepo = await git.checkIsRepo();
15
+ if (!isRepo) {
16
+ throw new Error('Not a git repository. Run this command from within a git repository.');
17
+ }
18
+ // Get diff
19
+ console.log(chalk.gray(`Getting ${options.staged ? 'staged' : 'unstaged'} changes...\n`));
20
+ const diffText = options.staged
21
+ ? await git.diff(['--cached'])
22
+ : await git.diff();
23
+ if (!diffText || diffText.trim().length === 0) {
24
+ console.log(chalk.yellow('āœ“ No changes to review\n'));
25
+ return;
26
+ }
27
+ // Parse diff
28
+ const diffs = parseDiff(diffText);
29
+ const changedFiles = getChangedFiles(diffs);
30
+ if (changedFiles.length === 0) {
31
+ console.log(chalk.yellow('āœ“ No files to review\n'));
32
+ return;
33
+ }
34
+ console.log(chalk.gray(`Found ${changedFiles.length} changed file(s)\n`));
35
+ // Connect to OpenCode (or start in-process if serverUrl is empty)
36
+ console.log(chalk.gray('Connecting to OpenCode server...\n'));
37
+ const opencode = await createOpencodeClientInstance({
38
+ baseUrl: config.opencode.serverUrl || undefined,
39
+ directory: cwd,
40
+ });
41
+ // Create review session
42
+ console.log(chalk.gray('Starting AI review...\n'));
43
+ const agentsList = config.review.agents.join(',');
44
+ const session = await opencode.createSession({
45
+ agent: 'local-reviewer',
46
+ message: `Review local diff with agents: ${agentsList}. Files: ${changedFiles.join(', ')}`,
47
+ context: {
48
+ files: changedFiles,
49
+ agents: config.review.agents,
50
+ staged: options.staged,
51
+ },
52
+ });
53
+ // Stream and display results
54
+ const issues = [];
55
+ try {
56
+ for await (const message of opencode.streamMessages(session.id)) {
57
+ if (message.role === 'assistant') {
58
+ // Parse issues from assistant messages
59
+ // TODO: Implement structured output parsing once OpenCode SDK supports it
60
+ console.log(message.content);
61
+ // For now, we'll display raw output
62
+ // In production, parse structured JSON responses from agents
63
+ }
64
+ }
65
+ // Display summary
66
+ if (issues.length > 0) {
67
+ console.log(chalk.bold('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
68
+ console.log(chalk.bold('šŸ“Š Review Summary'));
69
+ console.log(chalk.bold('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
70
+ const summary = calculateSummary(changedFiles.length, issues);
71
+ console.log(` Files reviewed: ${chalk.cyan(summary.filesReviewed)}`);
72
+ console.log(` Issues found: ${chalk.yellow(summary.issuesFound)}`);
73
+ if (summary.issuesFound > 0) {
74
+ console.log(` šŸ”“ Critical: ${chalk.red(summary.bySeverity.CRITICAL)}`);
75
+ console.log(` 🟔 High: ${chalk.yellow(summary.bySeverity.HIGH)}`);
76
+ console.log(` 🟠 Medium: ${chalk.hex('#FFA500')(summary.bySeverity.MEDIUM)}`);
77
+ console.log(` ⚪ Low: ${chalk.gray(summary.bySeverity.LOW)}`);
78
+ }
79
+ console.log('');
80
+ // Display issues
81
+ for (const issue of issues) {
82
+ console.log(formatTerminalIssue(issue));
83
+ }
84
+ // Recommendation
85
+ const hasCritical = summary.bySeverity.CRITICAL > 0;
86
+ const hasHigh = summary.bySeverity.HIGH > 0;
87
+ if (hasCritical || hasHigh) {
88
+ console.log(chalk.red.bold('\nāš ļø Recommendation: Fix critical/high issues before pushing\n'));
89
+ process.exit(1);
90
+ }
91
+ else {
92
+ console.log(chalk.green('\nāœ“ No critical issues found. Safe to push.\n'));
93
+ }
94
+ }
95
+ else {
96
+ console.log(chalk.green('\nāœ“ No issues found! Code looks good.\n'));
97
+ }
98
+ }
99
+ finally {
100
+ // Clean up session and shutdown in-process server if applicable
101
+ await opencode.closeSession(session.id);
102
+ await opencode.shutdown();
103
+ }
104
+ }
105
+ //# sourceMappingURL=review-local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-local.js","sourceRoot":"","sources":["../../src/cli/review-local.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { DRSConfig } from '../lib/config.js';
2
+ export interface ReviewMROptions {
3
+ projectId: string;
4
+ mrIid: number;
5
+ postComments: boolean;
6
+ }
7
+ /**
8
+ * Review a GitLab merge request
9
+ */
10
+ export declare function reviewMR(config: DRSConfig, options: ReviewMROptions): Promise<void>;
11
+ //# sourceMappingURL=review-mr.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-mr.d.ts","sourceRoot":"","sources":["../../src/cli/review-mr.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAWlD,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAuJzF"}