@aaronshaf/ger 2.0.9 → 3.0.1

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.
@@ -1,135 +0,0 @@
1
- ## IMMEDIATE TASK: ANALYZE CODE AND GENERATE INLINE COMMENTS
2
-
3
- **YOU MUST ANALYZE THE PROVIDED CODE CHANGES RIGHT NOW AND GENERATE INLINE COMMENTS.**
4
-
5
- **CRITICAL OUTPUT REQUIREMENT:**
6
- - YOUR ENTIRE OUTPUT MUST BE WRAPPED IN <response></response> TAGS
7
- - NEVER USE BACKTICKS ANYWHERE IN YOUR RESPONSE - they cause shell execution errors
8
- - Output ONLY a JSON array wrapped in response tags
9
- - **EMPTY ARRAY IS PERFECTLY VALID** for clean code without issues
10
- - No other text before or after the tags
11
-
12
- **GERRIT FORMATTING RULES FOR YOUR MESSAGE CONTENT:**
13
- - Each message starts with "🤖 " (robot emoji and space)
14
- - Use CAPS for emphasis, NOT markdown bold or italic
15
- - Reference code using quotes: 'variable' or "function()"
16
- - NO backticks (`) in your message text
17
- - Keep explanations clear and concise
18
-
19
- **START YOUR ANALYSIS NOW. DO NOT ASK QUESTIONS. DO NOT WAIT FOR MORE INPUT.**
20
-
21
- ## JSON Structure for Inline Comments
22
-
23
- The JSON array must contain inline comment objects with these fields:
24
-
25
- ### Required Fields
26
- - "file": **Complete file path** as shown in the diff (e.g., "app/controllers/users_controller.rb", not just "users_controller.rb")
27
- - "message": Your comment text (MUST start with "🤖 ")
28
-
29
- ### Line Specification (MUST use one approach)
30
- - "line": For single-line comments (integer line number - REQUIRED for single line comments)
31
- - "range": For multi-line comments (object with):
32
- - "start_line": First line of the issue (integer)
33
- - "end_line": Last line of the issue (integer)
34
- - "start_character": Optional column start (integer)
35
- - "end_character": Optional column end (integer)
36
-
37
- **CRITICAL LINE NUMBER RULES:**
38
- 1. **ALWAYS use final file line numbers, NEVER diff line numbers**
39
- 2. Line numbers must match the NEW version of the file after all changes
40
- 3. Use `git show HEAD:path/to/file` or examine the final file to get correct line numbers
41
- 4. If you see "+50" in a diff, the actual line number is NOT 50 - check the final file
42
- 5. Every comment MUST have either "line" OR "range". Comments without valid line numbers will be rejected.
43
-
44
- ### Optional Fields
45
- - "side": "REVISION" (new code, default) or "PARENT" (original code)
46
-
47
- **VERIFICATION STEP**: Before adding any comment, verify the line number by checking the final file content to ensure your line number points to the exact code you're commenting on.
48
-
49
- ## Comment Quality Guidelines
50
-
51
- 1. **Be Specific**: Reference exact variables, functions, or patterns
52
- 2. **Explain Impact**: What could go wrong and why it matters
53
- 3. **Suggest Fixes**: Provide actionable corrections when possible
54
- 4. **Group Logically**: Use range for related lines, separate comments for distinct issues
55
- 5. **Prioritize**: Comment on significant issues, not style preferences
56
-
57
- ## Example Output Formats
58
-
59
- ### Example 1: Mixed Single and Multi-line Comments
60
- <response>
61
- [
62
- {"file": "app/controllers/auth/validator.rb", "line": 45, "message": "🤖 Missing validation for email format - accepts invalid emails like 'user@'. Use a proper email regex or validation library."},
63
- {"file": "app/controllers/auth/validator.rb", "line": 67, "message": "🤖 Password strength check allows common passwords. Consider checking against a common password list."},
64
- {"file": "lib/database/connection.rb", "range": {"start_line": 23, "end_line": 35}, "message": "🤖 Database connection retry logic has exponential backoff but no maximum retry limit. This could retry indefinitely on persistent failures. Add a max retry count."},
65
- {"file": "app/controllers/api/users_controller.rb", "line": 89, "message": "🤖 SQL injection vulnerability: Query uses string concatenation with userId. Use parameterized queries with ActiveRecord methods.", "side": "REVISION"}
66
- ]
67
- </response>
68
-
69
- ### Example 2: Critical Security Issues
70
- <response>
71
- [
72
- {"file": "app/middleware/authentication_middleware.rb", "line": 34, "message": "🤖 Authentication bypass: Debug header check allows skipping auth. This MUST be removed before production."},
73
- {"file": "lib/utils/crypto_helper.rb", "range": {"start_line": 12, "end_line": 18}, "message": "🤖 Weak encryption: MD5 is cryptographically broken. Use bcrypt for password hashing."},
74
- {"file": "app/controllers/api/files_controller.rb", "line": 156, "message": "🤖 Path traversal vulnerability: User input directly used in file path without sanitization. An attacker could access files outside intended directory using '../'."}
75
- ]
76
- </response>
77
-
78
- ## Priority Guidelines for Inline Comments
79
-
80
- ### ALWAYS Comment On (Real Problems Only)
81
- - **Bugs**: Logic errors, null pointer risks, incorrect algorithms
82
- - **Security**: Injection vulnerabilities, auth bypasses, data leaks
83
- - **Crashes**: Unhandled exceptions, resource exhaustion, infinite loops
84
- - **Data loss**: Operations that corrupt or lose user data
85
-
86
- ### SOMETIMES Comment On (If Significant)
87
- - **Performance**: N+1 queries, memory leaks, algorithmic complexity issues
88
- - **Error handling**: Missing try/catch for operations that commonly fail
89
- - **Type safety**: Dangerous casts, missing validation for external input
90
-
91
- ### NEVER Comment On (Time Wasters)
92
- - **Style/formatting**: Let automated tools handle this
93
- - **Working code**: If it functions correctly, leave it alone
94
- - **Personal preferences**: "I would have done this differently"
95
- - **Nitpicks**: Variable names, spacing, minor wording
96
- - **Compliments**: Don't waste time praising obvious competence
97
-
98
- ## GIT REPOSITORY ACCESS
99
-
100
- You are running in a git repository with full access to:
101
- - git diff, git show, git log for understanding changes and context
102
- - git blame for code ownership and history
103
- - All project files for architectural understanding
104
- - Use these commands to provide comprehensive, accurate reviews
105
-
106
- ## FINAL TASK INSTRUCTION
107
-
108
- **ANALYZE THE CODE CHANGES NOW AND OUTPUT YOUR INLINE COMMENTS IMMEDIATELY.**
109
-
110
- Your output format must be:
111
- ```
112
- <response>
113
- []
114
- </response>
115
- ```
116
- (Empty array for clean code - this is GOOD!)
117
-
118
- OR:
119
-
120
- ```
121
- <response>
122
- [{"file": "auth.js", "line": 42, "message": "🤖 SQL injection vulnerability: query uses string concatenation"}]
123
- </response>
124
- ```
125
- (Only comment on real problems)
126
-
127
- **CRITICAL REQUIREMENTS**:
128
- - Every message must start with "🤖 "
129
- - Never use backticks in your response
130
- - Empty arrays are encouraged for clean code
131
- - Focus on bugs, security, crashes - ignore style preferences
132
- - Use git commands to understand context before commenting
133
- - NO TEXT OUTSIDE THE <response></response> TAGS
134
-
135
- **DO YOUR ANALYSIS NOW. STOP ASKING QUESTIONS. GENERATE THE REVIEW.**
@@ -1,206 +0,0 @@
1
- ## Review Structure and Formatting
2
-
3
- ### Section Headers (Use Only What's Relevant)
4
-
5
- Use CAPS for section headers. Include ONLY sections where you have substantive content:
6
-
7
- - OVERALL ASSESSMENT - High-level verdict and summary
8
- - CRITICAL ISSUES - Must be fixed before merge
9
- - SIGNIFICANT CONCERNS - Should be addressed
10
- - CODE QUALITY - Improvements for maintainability
11
- - SECURITY ASSESSMENT - Security-specific findings
12
- - PERFORMANCE ANALYSIS - Performance implications
13
- - TEST COVERAGE - Testing observations
14
- - ARCHITECTURE NOTES - Design and pattern feedback
15
- - RECOMMENDATIONS - Actionable suggestions
16
-
17
- ### Gerrit Formatting Requirements
18
-
19
- Gerrit uses a LIMITED markdown subset. Follow these rules EXACTLY:
20
-
21
- - NO markdown bold (**text**) or italic (*text*) - use CAPS for emphasis
22
- - NO headers with # or ## - use CAPS section titles
23
- - NO backticks (`) for code - use quotes 'code' or "code" for inline
24
- - Code blocks: Start EACH line with exactly 4 spaces, add blank lines before and after
25
- - Bullet points: Use * or - at line start
26
- - Block quotes: Start line with >
27
- - Reference files as path/to/file.ext:123 (with line numbers)
28
- - Always add blank lines between sections for readability
29
- - Keep code blocks simple and well-spaced
30
-
31
- **CRITICAL GERRIT FORMATTING RULES:**
32
-
33
- 1. NEVER start regular text lines with spaces - this creates unintended code blocks!
34
- 2. Only use 4 leading spaces when showing actual code examples
35
- 3. Regular text should start at column 1 (no indentation)
36
- 4. When explaining something after a bullet point, don't indent - start a new line
37
- 5. Use blank lines to separate sections and improve readability
38
-
39
- WRONG (creates code blocks):
40
- * Issue with authentication
41
- This explanation will become a code block due to leading spaces
42
-
43
- CORRECT:
44
- * Issue with authentication
45
- This explanation stays as regular text
46
-
47
- ### Content Guidelines
48
-
49
- 1. Start with the most important findings
50
- 2. Group related issues together
51
- 3. Be specific with file paths and line numbers
52
- 4. Explain the "why" behind each issue
53
- 5. Provide actionable fixes or alternatives
54
- 6. Use concrete examples when helpful
55
-
56
- ## CRITICAL OUTPUT REQUIREMENT
57
-
58
- **YOUR ENTIRE OUTPUT MUST BE WRAPPED IN <response></response> TAGS.**
59
-
60
- **IMMEDIATE TASK**: Analyze the code changes provided below and write a comprehensive engineering review.
61
-
62
- Start with "🤖 [Your Tool Name] ([Your Model])" then provide a **CONCISE** engineering assessment. Examples:
63
- - If you are Claude Sonnet 4: "🤖 Claude (Sonnet 4)"
64
- - If you are Gemini: "🤖 Gemini (1.5 Pro)" or "🤖 Gemini (1.5 Flash)"
65
- - For clean code: "No significant issues found. Change is ready for merge."
66
- - For problematic code: Focus only on critical/important issues, skip minor concerns
67
-
68
- **YOU MUST ANALYZE THE PROVIDED CODE CHANGES AND WRITE A REVIEW NOW.**
69
-
70
- ## Example Output Format
71
-
72
- <response>
73
- 🤖 Claude (Sonnet 4)
74
-
75
- OVERALL ASSESSMENT
76
-
77
- This change successfully implements the new authentication flow with proper error handling and test coverage. However, there are critical security concerns and performance issues that need addressing before merge.
78
-
79
- CRITICAL ISSUES
80
-
81
- 1. SQL Injection Vulnerability - src/api/users.ts:45
82
-
83
- The query construction uses string concatenation with user input:
84
-
85
- const query = "SELECT * FROM users WHERE id = " + userId
86
-
87
- This allows SQL injection attacks. Use parameterized queries:
88
-
89
- const query = "SELECT * FROM users WHERE id = $1"
90
- const result = await db.query(query, [userId])
91
-
92
- 2. Authentication Bypass - src/middleware/auth.ts:78-82
93
-
94
- The token validation can be bypassed when 'debug' header is present:
95
-
96
- if (req.headers.debug) return next()
97
-
98
- This MUST be removed from production code.
99
-
100
- SIGNIFICANT CONCERNS
101
-
102
- Resource Leak - src/services/cache.ts:156
103
-
104
- The Redis connection is created but never closed on error:
105
-
106
- * Connection opens on line 145
107
- * Error path at line 156 doesn't call client.disconnect()
108
- * This will exhaust connection pool over time
109
-
110
- Add proper cleanup in a finally block:
111
-
112
- try {
113
- await client.connect()
114
- // ... operations
115
- } finally {
116
- await client.disconnect()
117
- }
118
-
119
- PERFORMANCE ANALYSIS
120
-
121
- - N+1 Query Pattern in src/api/posts.ts:234-248
122
- Loading comments for each post individually causes N+1 queries.
123
- Consider using a single query with JOIN or batch loading.
124
-
125
- - Unbounded Memory Usage in src/utils/processor.ts:89
126
- Loading entire dataset into memory without pagination.
127
- For large datasets, this will cause OOM errors.
128
-
129
- TEST COVERAGE
130
-
131
- - Missing error path tests for the new authentication flow
132
- - No integration tests for the rate limiting middleware
133
- - Edge cases around token expiry not covered
134
-
135
- RECOMMENDATIONS
136
-
137
- 1. Add rate limiting to authentication endpoints
138
- 2. Implement request validation using a schema library
139
- 3. Add monitoring for the new cache layer
140
- 4. Consider adding database transaction support for multi-step operations
141
-
142
- The security issues are blocking and must be fixed. The performance concerns should be addressed before this scales to production load.
143
- </response>
144
-
145
- ## Review Tone and Approach
146
-
147
- 1. **Be Direct but Constructive**
148
- - State issues clearly without hedging
149
- - Explain impact and provide solutions
150
- - Focus on the code, not the coder
151
-
152
- 2. **Prioritize Effectively**
153
- - Lead with blocking issues
154
- - Group related problems
155
- - Don't bury critical findings
156
-
157
- 3. **Provide Value**
158
- - Every comment should help improve the code
159
- - Skip trivial issues unless they indicate patterns
160
- - Include concrete fix suggestions
161
-
162
- ## GIT REPOSITORY ACCESS
163
-
164
- You are running in a git repository with full access to:
165
- - git diff, git show, git log for understanding changes and context
166
- - git blame for code ownership and history
167
- - All project files for architectural understanding
168
- - Use these commands to explore the codebase and provide comprehensive reviews
169
-
170
- ## FINAL REMINDER
171
-
172
- **CRITICAL: Your ENTIRE output must be wrapped in <response></response> tags.**
173
-
174
- Example format:
175
- ```
176
- <response>
177
- 🤖 Claude (Sonnet 4)
178
-
179
- OVERALL ASSESSMENT
180
-
181
- Your review content here...
182
- </response>
183
- ```
184
-
185
- MANDATORY REQUIREMENTS:
186
- - Start with "🤖 [Your Tool Name] ([Your Model])"
187
- - Be CONCISE - engineers value brevity over verbosity
188
- - For clean code, simply state "No significant issues found"
189
- - Focus on material problems, skip style preferences and compliments
190
- - Use Gerrit's limited markdown format - NO backticks, NO markdown bold/italic
191
- - Use git commands to understand context before writing review
192
- - NO TEXT OUTSIDE THE <response></response> TAGS
193
-
194
- CRITICAL FORMATTING RULES:
195
- - Add blank lines between sections and before/after code blocks
196
- - Use exactly 4 spaces to start each line of code blocks
197
- - Keep code blocks simple and readable
198
- - Add proper spacing for readability
199
- - NEVER indent regular text - start all non-code text at column 1
200
- - Only code examples should have leading spaces (exactly 4)
201
-
202
- ## TASK SUMMARY
203
-
204
- **ANALYZE THE CODE CHANGES PROVIDED ABOVE AND WRITE YOUR ENGINEERING REVIEW IMMEDIATELY.**
205
-
206
- Do not ask for clarification. Do not wait for more input. Analyze the provided code changes, git history, and changed files, then write your review following the format requirements above.
@@ -1,292 +0,0 @@
1
- import { Context, Data, Effect, Layer } from 'effect'
2
- import { exec } from 'node:child_process'
3
- import { promisify } from 'node:util'
4
-
5
- const execAsync = promisify(exec)
6
-
7
- // Shared response extraction logic for all AI tools
8
- const extractResponse = (stdout: string): string => {
9
- // Extract response from <response> tags or use full output
10
- const responseMatch = stdout.match(/<response>([\s\S]*?)<\/response>/i)
11
- return responseMatch ? responseMatch[1].trim() : stdout.trim()
12
- }
13
-
14
- // Simple strategy focused only on review needs
15
- export interface ReviewStrategyErrorFields {
16
- readonly message: string
17
- readonly cause?: unknown
18
- }
19
-
20
- const ReviewStrategyErrorBase = Data.TaggedError(
21
- 'ReviewStrategyError',
22
- )<ReviewStrategyErrorFields> as unknown
23
-
24
- export class ReviewStrategyError
25
- extends (ReviewStrategyErrorBase as new (
26
- args: ReviewStrategyErrorFields,
27
- ) => ReviewStrategyErrorFields & Error & { readonly _tag: 'ReviewStrategyError' })
28
- implements Error
29
- {
30
- readonly name = 'ReviewStrategyError'
31
- }
32
-
33
- // Review strategy interface - focused on specific review patterns
34
- export interface ReviewStrategy {
35
- readonly name: string
36
- readonly isAvailable: () => Effect.Effect<boolean, never>
37
- readonly executeReview: (
38
- prompt: string,
39
- options?: { cwd?: string; systemPrompt?: string },
40
- ) => Effect.Effect<string, ReviewStrategyError>
41
- }
42
-
43
- // Strategy implementations for different AI tools
44
- export const claudeCliStrategy: ReviewStrategy = {
45
- name: 'Claude CLI',
46
- isAvailable: () =>
47
- Effect.gen(function* () {
48
- const result = yield* Effect.tryPromise({
49
- try: () => execAsync('which claude'),
50
- catch: () => null,
51
- }).pipe(Effect.orElseSucceed(() => null))
52
-
53
- return Boolean(result && result.stdout.trim())
54
- }),
55
- executeReview: (prompt, options = {}) =>
56
- Effect.gen(function* () {
57
- const result = yield* Effect.tryPromise({
58
- try: async () => {
59
- const child = require('node:child_process').spawn('claude -p', {
60
- shell: true,
61
- stdio: ['pipe', 'pipe', 'pipe'],
62
- cwd: options.cwd || process.cwd(),
63
- })
64
-
65
- child.stdin.write(prompt)
66
- child.stdin.end()
67
-
68
- let stdout = ''
69
- let stderr = ''
70
-
71
- child.stdout.on('data', (data: Buffer) => {
72
- stdout += data.toString()
73
- })
74
-
75
- child.stderr.on('data', (data: Buffer) => {
76
- stderr += data.toString()
77
- })
78
-
79
- return new Promise<{ stdout: string; stderr: string }>((resolve, reject) => {
80
- child.on('close', (code: number) => {
81
- if (code !== 0) {
82
- reject(new Error(`Claude CLI exited with code ${code}: ${stderr}`))
83
- } else {
84
- resolve({ stdout, stderr })
85
- }
86
- })
87
-
88
- child.on('error', reject)
89
- })
90
- },
91
- catch: (error) =>
92
- new ReviewStrategyError({
93
- message: `Claude CLI failed: ${error instanceof Error ? error.message : String(error)}`,
94
- cause: error,
95
- }),
96
- })
97
-
98
- return extractResponse(result.stdout)
99
- }),
100
- }
101
-
102
- export const geminiCliStrategy: ReviewStrategy = {
103
- name: 'Gemini CLI',
104
- isAvailable: () =>
105
- Effect.gen(function* () {
106
- const result = yield* Effect.tryPromise({
107
- try: () => execAsync('which gemini'),
108
- catch: () => null,
109
- }).pipe(Effect.orElseSucceed(() => null))
110
-
111
- return Boolean(result && result.stdout.trim())
112
- }),
113
- executeReview: (prompt, options = {}) =>
114
- Effect.gen(function* () {
115
- const result = yield* Effect.tryPromise({
116
- try: async () => {
117
- const child = require('node:child_process').spawn('gemini -p', {
118
- shell: true,
119
- stdio: ['pipe', 'pipe', 'pipe'],
120
- cwd: options.cwd || process.cwd(),
121
- })
122
-
123
- child.stdin.write(prompt)
124
- child.stdin.end()
125
-
126
- let stdout = ''
127
- let stderr = ''
128
-
129
- child.stdout.on('data', (data: Buffer) => {
130
- stdout += data.toString()
131
- })
132
-
133
- child.stderr.on('data', (data: Buffer) => {
134
- stderr += data.toString()
135
- })
136
-
137
- return new Promise<{ stdout: string; stderr: string }>((resolve, reject) => {
138
- child.on('close', (code: number) => {
139
- if (code !== 0) {
140
- reject(new Error(`Gemini CLI exited with code ${code}: ${stderr}`))
141
- } else {
142
- resolve({ stdout, stderr })
143
- }
144
- })
145
-
146
- child.on('error', reject)
147
- })
148
- },
149
- catch: (error) =>
150
- new ReviewStrategyError({
151
- message: `Gemini CLI failed: ${error instanceof Error ? error.message : String(error)}`,
152
- cause: error,
153
- }),
154
- })
155
-
156
- return extractResponse(result.stdout)
157
- }),
158
- }
159
-
160
- export const openCodeCliStrategy: ReviewStrategy = {
161
- name: 'OpenCode CLI',
162
- isAvailable: () =>
163
- Effect.gen(function* () {
164
- const result = yield* Effect.tryPromise({
165
- try: () => execAsync('which opencode'),
166
- catch: () => null,
167
- }).pipe(Effect.orElseSucceed(() => null))
168
-
169
- return Boolean(result && result.stdout.trim())
170
- }),
171
- executeReview: (prompt, options = {}) =>
172
- Effect.gen(function* () {
173
- const result = yield* Effect.tryPromise({
174
- try: async () => {
175
- const child = require('node:child_process').spawn('opencode -p', {
176
- shell: true,
177
- stdio: ['pipe', 'pipe', 'pipe'],
178
- cwd: options.cwd || process.cwd(),
179
- })
180
-
181
- child.stdin.write(prompt)
182
- child.stdin.end()
183
-
184
- let stdout = ''
185
- let stderr = ''
186
-
187
- child.stdout.on('data', (data: Buffer) => {
188
- stdout += data.toString()
189
- })
190
-
191
- child.stderr.on('data', (data: Buffer) => {
192
- stderr += data.toString()
193
- })
194
-
195
- return new Promise<{ stdout: string; stderr: string }>((resolve, reject) => {
196
- child.on('close', (code: number) => {
197
- if (code !== 0) {
198
- reject(new Error(`OpenCode CLI exited with code ${code}: ${stderr}`))
199
- } else {
200
- resolve({ stdout, stderr })
201
- }
202
- })
203
-
204
- child.on('error', reject)
205
- })
206
- },
207
- catch: (error) =>
208
- new ReviewStrategyError({
209
- message: `OpenCode CLI failed: ${error instanceof Error ? error.message : String(error)}`,
210
- cause: error,
211
- }),
212
- })
213
-
214
- return extractResponse(result.stdout)
215
- }),
216
- }
217
-
218
- // Review service interface using strategy pattern
219
- export interface ReviewStrategyServiceImpl {
220
- readonly getAvailableStrategies: () => Effect.Effect<ReviewStrategy[], never>
221
- readonly selectStrategy: (
222
- preferredName?: string,
223
- ) => Effect.Effect<ReviewStrategy, ReviewStrategyError>
224
- readonly executeWithStrategy: (
225
- strategy: ReviewStrategy,
226
- prompt: string,
227
- options?: { cwd?: string; systemPrompt?: string },
228
- ) => Effect.Effect<string, ReviewStrategyError>
229
- }
230
-
231
- // Export the service tag with explicit type
232
- export const ReviewStrategyService: Context.Tag<
233
- ReviewStrategyServiceImpl,
234
- ReviewStrategyServiceImpl
235
- > = Context.GenericTag<ReviewStrategyServiceImpl>('ReviewStrategyService')
236
-
237
- export type ReviewStrategyService = Context.Tag.Identifier<typeof ReviewStrategyService>
238
-
239
- export const ReviewStrategyServiceLive: Layer.Layer<ReviewStrategyServiceImpl> = Layer.succeed(
240
- ReviewStrategyService,
241
- {
242
- getAvailableStrategies: () =>
243
- Effect.gen(function* () {
244
- const strategies = [claudeCliStrategy, geminiCliStrategy, openCodeCliStrategy]
245
- const available: ReviewStrategy[] = []
246
-
247
- for (const strategy of strategies) {
248
- const isAvailable = yield* strategy.isAvailable()
249
- if (isAvailable) {
250
- available.push(strategy)
251
- }
252
- }
253
-
254
- return available
255
- }),
256
-
257
- selectStrategy: (preferredName?: string) =>
258
- Effect.gen(function* () {
259
- const strategies = [claudeCliStrategy, geminiCliStrategy, openCodeCliStrategy]
260
- const available: ReviewStrategy[] = []
261
-
262
- for (const strategy of strategies) {
263
- const isAvailable = yield* strategy.isAvailable()
264
- if (isAvailable) {
265
- available.push(strategy)
266
- }
267
- }
268
-
269
- if (available.length === 0) {
270
- return yield* Effect.fail(
271
- new ReviewStrategyError({
272
- message: 'No AI tools available. Please install claude, gemini, or opencode CLI.',
273
- }),
274
- )
275
- }
276
-
277
- if (preferredName) {
278
- const preferred = available.find((s: ReviewStrategy) =>
279
- s.name.toLowerCase().includes(preferredName.toLowerCase()),
280
- )
281
- if (preferred) {
282
- return preferred
283
- }
284
- }
285
-
286
- return available[0] // Return first available
287
- }),
288
-
289
- executeWithStrategy: (strategy, prompt, options = {}) =>
290
- strategy.executeReview(prompt, options),
291
- },
292
- )