@contextrail/code-review-agent 0.1.1-alpha.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 (84) hide show
  1. package/LICENSE +26 -0
  2. package/MODEL_RECOMMENDATIONS.md +178 -0
  3. package/README.md +177 -0
  4. package/dist/config/defaults.d.ts +72 -0
  5. package/dist/config/defaults.js +113 -0
  6. package/dist/config/index.d.ts +34 -0
  7. package/dist/config/index.js +89 -0
  8. package/dist/index.d.ts +2 -0
  9. package/dist/index.js +603 -0
  10. package/dist/llm/factory.d.ts +21 -0
  11. package/dist/llm/factory.js +50 -0
  12. package/dist/llm/index.d.ts +3 -0
  13. package/dist/llm/index.js +2 -0
  14. package/dist/llm/service.d.ts +38 -0
  15. package/dist/llm/service.js +191 -0
  16. package/dist/llm/types.d.ts +119 -0
  17. package/dist/llm/types.js +1 -0
  18. package/dist/logging/logger.d.ts +9 -0
  19. package/dist/logging/logger.js +52 -0
  20. package/dist/mcp/client.d.ts +429 -0
  21. package/dist/mcp/client.js +173 -0
  22. package/dist/mcp/mcp-tools.d.ts +292 -0
  23. package/dist/mcp/mcp-tools.js +40 -0
  24. package/dist/mcp/token-validation.d.ts +31 -0
  25. package/dist/mcp/token-validation.js +57 -0
  26. package/dist/mcp/tools-provider.d.ts +18 -0
  27. package/dist/mcp/tools-provider.js +24 -0
  28. package/dist/observability/index.d.ts +2 -0
  29. package/dist/observability/index.js +1 -0
  30. package/dist/observability/metrics.d.ts +48 -0
  31. package/dist/observability/metrics.js +86 -0
  32. package/dist/orchestrator/agentic-orchestrator.d.ts +29 -0
  33. package/dist/orchestrator/agentic-orchestrator.js +136 -0
  34. package/dist/orchestrator/prompts.d.ts +25 -0
  35. package/dist/orchestrator/prompts.js +98 -0
  36. package/dist/orchestrator/validation.d.ts +2 -0
  37. package/dist/orchestrator/validation.js +7 -0
  38. package/dist/orchestrator/writer.d.ts +4 -0
  39. package/dist/orchestrator/writer.js +17 -0
  40. package/dist/output/aggregator.d.ts +30 -0
  41. package/dist/output/aggregator.js +132 -0
  42. package/dist/output/prompts.d.ts +32 -0
  43. package/dist/output/prompts.js +153 -0
  44. package/dist/output/schema.d.ts +1515 -0
  45. package/dist/output/schema.js +224 -0
  46. package/dist/output/writer.d.ts +31 -0
  47. package/dist/output/writer.js +120 -0
  48. package/dist/review-inputs/chunking.d.ts +29 -0
  49. package/dist/review-inputs/chunking.js +113 -0
  50. package/dist/review-inputs/diff-summary.d.ts +52 -0
  51. package/dist/review-inputs/diff-summary.js +83 -0
  52. package/dist/review-inputs/file-patterns.d.ts +40 -0
  53. package/dist/review-inputs/file-patterns.js +182 -0
  54. package/dist/review-inputs/filtering.d.ts +31 -0
  55. package/dist/review-inputs/filtering.js +53 -0
  56. package/dist/review-inputs/git-diff-provider.d.ts +2 -0
  57. package/dist/review-inputs/git-diff-provider.js +42 -0
  58. package/dist/review-inputs/index.d.ts +46 -0
  59. package/dist/review-inputs/index.js +122 -0
  60. package/dist/review-inputs/path-validation.d.ts +10 -0
  61. package/dist/review-inputs/path-validation.js +37 -0
  62. package/dist/review-inputs/surrounding-context.d.ts +35 -0
  63. package/dist/review-inputs/surrounding-context.js +180 -0
  64. package/dist/review-inputs/triage.d.ts +57 -0
  65. package/dist/review-inputs/triage.js +81 -0
  66. package/dist/reviewers/executor.d.ts +41 -0
  67. package/dist/reviewers/executor.js +357 -0
  68. package/dist/reviewers/findings-merge.d.ts +9 -0
  69. package/dist/reviewers/findings-merge.js +131 -0
  70. package/dist/reviewers/iteration.d.ts +17 -0
  71. package/dist/reviewers/iteration.js +95 -0
  72. package/dist/reviewers/persistence.d.ts +17 -0
  73. package/dist/reviewers/persistence.js +55 -0
  74. package/dist/reviewers/progress-tracker.d.ts +115 -0
  75. package/dist/reviewers/progress-tracker.js +194 -0
  76. package/dist/reviewers/prompt.d.ts +42 -0
  77. package/dist/reviewers/prompt.js +246 -0
  78. package/dist/reviewers/tool-call-tracker.d.ts +18 -0
  79. package/dist/reviewers/tool-call-tracker.js +40 -0
  80. package/dist/reviewers/types.d.ts +12 -0
  81. package/dist/reviewers/types.js +1 -0
  82. package/dist/reviewers/validation-rules.d.ts +27 -0
  83. package/dist/reviewers/validation-rules.js +189 -0
  84. package/package.json +79 -0
package/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+ Copyright (c) 2026 ContextRail. All rights reserved.
2
+
3
+ Source-Available License
4
+
5
+ You may:
6
+ - Use the Software for any purpose.
7
+ - Modify the Software for your own internal use.
8
+
9
+ You may not, without prior written consent from ContextRail:
10
+ - Redistribute the Software (original or modified), in source or binary form.
11
+ - Use the Software to provide a competing product or service.
12
+ - Use the Software (including its source code, outputs, or documentation) to
13
+ train, fine-tune, or improve machine learning models (including large
14
+ language models or other AI systems), or allow third parties to do so.
15
+ - Use automated systems (including LLMs or other AI) to scrape, replicate, or
16
+ redistribute the Software or to create derivative works for distribution.
17
+
18
+ Contact ContextRail contextrail@gmail.com for redistribution, commercial licensing, or ML/LLM use terms.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. IN NO EVENT SHALL
23
+ CONTEXTRAIL OR ITS CONTRIBUTORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
@@ -0,0 +1,178 @@
1
+ # Model Recommendations for Code Review Agent
2
+
3
+ This guide helps you choose cost-effective models that work well with structured output for code reviews.
4
+
5
+ ## Quick Reference: Low-Cost Models
6
+
7
+ ### ✅ Recommended Low-Cost Models (Structured Output Compatible)
8
+
9
+ | Model | Cost (per 1M tokens) | Speed | Quality | Best For |
10
+ | ------------------------------------ | -------------------- | --------- | --------- | --------------------------------- |
11
+ | **google/gemini-2.0-flash-exp** | ~$0.075 | Very Fast | Good | Orchestrator, Synthesis, Decision |
12
+ | **google/gemini-3-flash-preview** | ~$0.075 | Very Fast | Good | Orchestrator, Synthesis, Decision |
13
+ | **anthropic/claude-haiku-4.5** | ~$0.25 | Fast | Excellent | Reviewers, Orchestrator (default) |
14
+ | **anthropic/claude-sonnet-4.5** | ~$3.00 | Medium | Excellent | Critic, Complex Reviews |
15
+ | **meta-llama/llama-3.1-8b-instruct** | ~$0.05 | Fast | Good | Budget Reviews |
16
+
17
+ ### ⚠️ Models to Avoid (Structured Output Issues)
18
+
19
+ - `deepseek/deepseek-v3.2` - Known to return empty responses with structured output
20
+ - Models without explicit structured output support
21
+ - Very old model versions
22
+
23
+ ## Cost Optimization Strategies
24
+
25
+ ### Strategy 1: Tiered Model Approach (Recommended)
26
+
27
+ Use cheaper models for simpler tasks, more capable models for complex analysis:
28
+
29
+ ```bash
30
+ # Orchestrator: Fast, cheap model
31
+ export LLM_MODEL_ORCHESTRATOR="google/gemini-3-flash-preview"
32
+
33
+ # Reviewers: Balanced cost/quality
34
+ export LLM_MODEL_REVIEWER="anthropic/claude-haiku-4.5"
35
+
36
+ # Critic: Higher quality for validation
37
+ export LLM_MODEL_CRITIC="anthropic/claude-sonnet-4.5"
38
+ ```
39
+
40
+ **Estimated cost per review**: ~$0.01-0.05 (depending on PR size)
41
+
42
+ ### Strategy 2: Ultra-Low-Cost (Budget)
43
+
44
+ Use cheapest models throughout:
45
+
46
+ ```bash
47
+ export LLM_MODEL_ORCHESTRATOR="google/gemini-2.0-flash-exp"
48
+ export LLM_MODEL_REVIEWER="google/gemini-2.0-flash-exp"
49
+ export LLM_MODEL_CRITIC="google/gemini-3-flash-preview"
50
+ ```
51
+
52
+ **Estimated cost per review**: ~$0.005-0.02
53
+
54
+ ### Strategy 3: Quality-Focused (Higher Cost)
55
+
56
+ Use Claude models throughout for best quality:
57
+
58
+ ```bash
59
+ export LLM_MODEL_ORCHESTRATOR="anthropic/claude-haiku-4.5"
60
+ export LLM_MODEL_REVIEWER="anthropic/claude-haiku-4.5"
61
+ export LLM_MODEL_CRITIC="anthropic/claude-sonnet-4.5"
62
+ ```
63
+
64
+ **Estimated cost per review**: ~$0.02-0.10
65
+
66
+ ## Model Selection Guide
67
+
68
+ ### For Orchestrator
69
+
70
+ **Purpose**: Select reviewers, understand changes
71
+ **Requirements**: Fast, reliable structured output
72
+ **Recommendations**:
73
+
74
+ - ✅ `google/gemini-3-flash-preview` (cheapest, fast)
75
+ - ✅ `anthropic/claude-haiku-4.5` (default, reliable)
76
+ - ⚠️ Avoid: Very slow models, models without structured output
77
+
78
+ ### For Reviewers
79
+
80
+ **Purpose**: Analyze code, find issues
81
+ **Requirements**: Good code understanding, structured output
82
+ **Recommendations**:
83
+
84
+ - ✅ `anthropic/claude-haiku-4.5` (default, excellent quality)
85
+ - ✅ `google/gemini-3-flash-preview` (cheaper alternative)
86
+ - ⚠️ Avoid: Models that struggle with code analysis
87
+
88
+ ### For Critic
89
+
90
+ **Purpose**: Validate findings, reduce false positives
91
+ **Requirements**: High quality reasoning, structured output
92
+ **Recommendations**:
93
+
94
+ - ✅ `anthropic/claude-sonnet-4.5` (default, best quality)
95
+ - ✅ `anthropic/claude-haiku-4.5` (if cost is concern)
96
+ - ⚠️ Avoid: Low-quality models (defeats purpose of critic)
97
+
98
+ ## Testing Model Compatibility
99
+
100
+ If you want to try a new model, test it first:
101
+
102
+ ```bash
103
+ # Test with a small PR
104
+ export LLM_MODEL_REVIEWER="your-model-name"
105
+ export DEBUG=1 # Enable debug logging
106
+
107
+ # Run a review and check logs for:
108
+ # - "[LLM] No structured output received" warnings
109
+ # - Empty responses
110
+ # - JSON parsing errors
111
+ ```
112
+
113
+ ## Cost Estimation
114
+
115
+ Based on typical PR sizes:
116
+
117
+ | PR Size | Input Tokens | Output Tokens | Cost (Gemini Flash) | Cost (Claude Haiku) |
118
+ | ------------------- | ------------ | ------------- | ------------------- | ------------------- |
119
+ | Small (1-3 files) | ~5K | ~2K | ~$0.0005 | ~$0.0018 |
120
+ | Medium (5-10 files) | ~15K | ~5K | ~$0.0015 | ~$0.005 |
121
+ | Large (20+ files) | ~50K | ~15K | ~$0.005 | ~$0.016 |
122
+
123
+ **Note**: Costs vary based on:
124
+
125
+ - Number of reviewers selected
126
+ - Number of iterations (if findings need validation)
127
+ - Amount of context retrieved from ContextRail
128
+ - Model pricing (check OpenRouter for current rates)
129
+
130
+ ## Finding Current Pricing
131
+
132
+ 1. Visit [OpenRouter Models](https://openrouter.ai/models)
133
+ 2. Filter by:
134
+ - `supported_parameters=structured_outputs`
135
+ - Sort by pricing (low to high)
136
+ 3. Check the model card for:
137
+ - Input/output token pricing
138
+ - Structured output support
139
+ - Speed/latency information
140
+
141
+ ## Troubleshooting Model Issues
142
+
143
+ ### Problem: Empty responses / "No object generated"
144
+
145
+ **Symptoms**: Model consumes tokens but returns empty text
146
+ **Solution**:
147
+
148
+ - Try a different model (Gemini Flash or Claude Haiku)
149
+ - Check model compatibility with structured output
150
+ - Verify model name is correct
151
+
152
+ ### Problem: JSON parsing errors
153
+
154
+ **Symptoms**: Model returns text but not valid JSON
155
+ **Solution**:
156
+
157
+ - Use a model with better structured output support
158
+ - Check if model requires special formatting
159
+ - Review debug logs for actual response
160
+
161
+ ### Problem: High costs
162
+
163
+ **Solution**:
164
+
165
+ - Switch to Gemini Flash models
166
+ - Reduce `maxSteps` or `maxIterations`
167
+ - Use fewer reviewers
168
+ - Enable token caching if available
169
+
170
+ ## Default Configuration
171
+
172
+ The agent defaults to:
173
+
174
+ - **Orchestrator**: `anthropic/claude-haiku-4.5` (~$0.25/1M tokens)
175
+ - **Reviewer**: `anthropic/claude-haiku-4.5` (~$0.25/1M tokens)
176
+ - **Critic**: `anthropic/claude-sonnet-4.5` (~$3.00/1M tokens)
177
+
178
+ These defaults balance cost and quality. For lower costs, switch to Gemini Flash models.
package/README.md ADDED
@@ -0,0 +1,177 @@
1
+ ---
2
+ title: 'Code Review Agent Client Integration Guide'
3
+ owner: platform-eng
4
+ status: draft
5
+ last_reviewed: 2026-02-10
6
+ audience: developers integrating code-review-agent in client repositories
7
+ purpose: Provide user-facing installation and execution guidance for npm-distributed code-review-agent.
8
+ user_need: do
9
+ doc_form: how-to-guide
10
+ location: packages/code-review-agent/README.md
11
+ ---
12
+
13
+ # [Context Rail](https://contextrail.app): Code Review Agent Client Integration Guide
14
+
15
+ ## Summary
16
+
17
+ `@contextrail/code-review-agent` is a CLI for running structured, AI-assisted PR/code reviews in your repository.
18
+
19
+ Use it to:
20
+
21
+ - review a git diff (`--from` / `--to`)
22
+ - review explicit files (`--files` / `--file`)
23
+ - emit machine-readable review artifacts (`result.json`, reviewer logs, token metrics)
24
+
25
+ ## Install and Run
26
+
27
+ Choose one:
28
+
29
+ - **No install (recommended to start):**
30
+
31
+ ```bash
32
+ npx -y @contextrail/code-review-agent review --help
33
+ ```
34
+
35
+ - **Project dependency:**
36
+
37
+ ```bash
38
+ npm i -D @contextrail/code-review-agent
39
+ npx code-review-agent review --help
40
+ ```
41
+
42
+ - **Global install:**
43
+
44
+ ```bash
45
+ npm i -g @contextrail/code-review-agent
46
+ code-review-agent review --help
47
+ ```
48
+
49
+ ## Required Environment Variables
50
+
51
+ ```bash
52
+ export CONTEXTRAIL_MCP_SERVER_URL="https://<your-mcp-host>"
53
+ export CONTEXTRAIL_MCP_JWT_TOKEN="<your-contextrail-jwt-token>"
54
+ export OPENROUTER_API_KEY="<your-openrouter-key>"
55
+ ```
56
+
57
+ ### Getting Your ContextRail MCP Token
58
+
59
+ To get your `CONTEXTRAIL_MCP_JWT_TOKEN`:
60
+
61
+ 1. **Sign up** at [https://contextrail.app](https://contextrail.app) (if you don't have an account)
62
+ 2. **Get your token** at [https://contextrail.app/settings/profile](https://contextrail.app/settings/profile)
63
+
64
+ The token is used to authenticate with the ContextRail MCP server to retrieve your organization's review standards and contexts.
65
+
66
+ Optional:
67
+
68
+ ```bash
69
+ export LLM_MODEL_ORCHESTRATOR="google/gemini-3-flash-preview"
70
+ export LLM_MODEL_REVIEWER="qwen/qwen3-coder-next"
71
+ export LLM_MODEL_CRITIC="qwen/qwen3-coder-next"
72
+ export REVIEW_DOMAINS="security,architecture"
73
+ export PR_DESCRIPTION="Optional PR context"
74
+ ```
75
+
76
+ ## Run Against a PR Diff
77
+
78
+ ```bash
79
+ git fetch origin
80
+ BASE_SHA="$(git merge-base origin/main HEAD)"
81
+ HEAD_SHA="$(git rev-parse HEAD)"
82
+
83
+ npx -y @contextrail/code-review-agent review \
84
+ --repo . \
85
+ --from "$BASE_SHA" \
86
+ --to "$HEAD_SHA" \
87
+ --output ./.review
88
+ ```
89
+
90
+ With optional domain focus:
91
+
92
+ ```bash
93
+ npx -y @contextrail/code-review-agent review \
94
+ --repo . \
95
+ --from "$BASE_SHA" \
96
+ --to "$HEAD_SHA" \
97
+ --domains "security,architecture" \
98
+ --output ./.review
99
+ ```
100
+
101
+ ## Run Against Explicit Files
102
+
103
+ ```bash
104
+ npx -y @contextrail/code-review-agent review \
105
+ --repo . \
106
+ --files "src/a.ts,src/b.ts" \
107
+ --output ./.review
108
+ ```
109
+
110
+ or:
111
+
112
+ ```bash
113
+ npx -y @contextrail/code-review-agent review \
114
+ --repo . \
115
+ --file src/a.ts \
116
+ --file src/b.ts \
117
+ --output ./.review
118
+ ```
119
+
120
+ ## Local Change Recipes
121
+
122
+ Staged files:
123
+
124
+ ```bash
125
+ FILES_CSV="$(git diff --name-only --cached | paste -sd, -)"
126
+ [ -z "$FILES_CSV" ] && echo "No staged tracked files to review." && exit 1
127
+ npx -y @contextrail/code-review-agent review --repo . --files "$FILES_CSV" --output ./.review
128
+ ```
129
+
130
+ Unstaged files:
131
+
132
+ ```bash
133
+ FILES_CSV="$(git diff --name-only | paste -sd, -)"
134
+ [ -z "$FILES_CSV" ] && echo "No unstaged tracked files to review." && exit 1
135
+ npx -y @contextrail/code-review-agent review --repo . --files "$FILES_CSV" --output ./.review
136
+ ```
137
+
138
+ Tracked changes vs `HEAD`:
139
+
140
+ ```bash
141
+ FILES_CSV="$(git diff --name-only HEAD | paste -sd, -)"
142
+ [ -z "$FILES_CSV" ] && echo "No tracked local changes vs HEAD." && exit 1
143
+ npx -y @contextrail/code-review-agent review --repo . --files "$FILES_CSV" --output ./.review
144
+ ```
145
+
146
+ ## Output and Exit Behavior
147
+
148
+ Primary output:
149
+
150
+ - `./.review/result.json`
151
+
152
+ Additional artifacts:
153
+
154
+ - `./.review/orchestrator/*`
155
+ - `./.review/reviewers/<reviewer>/*`
156
+ - `./.review/token-budget.json`
157
+
158
+ Exit codes:
159
+
160
+ - `0`: all reviewers validated and final decision is approve
161
+ - `1`: reviewer validation failed and/or final decision is request-changes
162
+
163
+ ## Troubleshooting
164
+
165
+ - **`Command "code-review-agent" not found`**
166
+ - use `npx -y @contextrail/code-review-agent ...` or install globally
167
+ - **Missing required env vars**
168
+ - set `CONTEXTRAIL_MCP_SERVER_URL`, `CONTEXTRAIL_MCP_JWT_TOKEN`, and `OPENROUTER_API_KEY`
169
+ - **One reviewer failed with structured-output/schema errors**
170
+ - inspect `./.review/reviewers/<reviewer>/failures.md`
171
+ - inspect `./.review/reviewers/<reviewer>/progress.json`
172
+
173
+ ## Related
174
+
175
+ - contributor guide: `packages/code-review-agent/CONTRIBUTORS.md`
176
+ - npm publishing guide: `packages/code-review-agent/NPM_PUBLISHING.md`
177
+ - model cost guide: `packages/code-review-agent/MODEL_RECOMMENDATIONS.md`
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Default model for orchestrator calls.
3
+ * Chosen for fast planning/synthesis while preserving structured-output reliability.
4
+ */
5
+ export declare const DEFAULT_ORCHESTRATOR_MODEL = "google/gemini-3-flash-preview";
6
+ /**
7
+ * Default model for reviewer iterations.
8
+ * Tuned for code-centric reasoning with acceptable latency/cost.
9
+ */
10
+ export declare const DEFAULT_REVIEWER_MODEL = "qwen/qwen3-coder-next";
11
+ /**
12
+ * Default critic model used when no critic model is explicitly configured.
13
+ */
14
+ export declare const DEFAULT_CRITIC_MODEL = "google/gemini-3-flash-preview";
15
+ /**
16
+ * Maximum tool/LLM steps per call for orchestrator/reviewer operations.
17
+ */
18
+ export declare const DEFAULT_MAX_STEPS = 10;
19
+ /**
20
+ * Maximum validation loops per reviewer (initial pass + critic pass).
21
+ */
22
+ export declare const DEFAULT_MAX_ITERATIONS = 2;
23
+ /**
24
+ * Maximum tool/LLM steps for synthesis and final decision generation.
25
+ */
26
+ export declare const DEFAULT_AGGREGATION_MAX_STEPS = 5;
27
+ /**
28
+ * Default temperature for structured output generation.
29
+ * Lower temperature (0-0.3) improves reliability and consistency for structured output.
30
+ */
31
+ export declare const DEFAULT_TEMPERATURE = 0.2;
32
+ /**
33
+ * Default timeout for LLM calls in milliseconds (2 minutes).
34
+ * Prevents hanging on slow or unresponsive models.
35
+ */
36
+ export declare const DEFAULT_LLM_TIMEOUT_MS = 120000;
37
+ /**
38
+ * Default max tokens for structured output generation.
39
+ * Ensures enough tokens for complete structured responses.
40
+ * Set to undefined to use model default (typically 4096-8192).
41
+ */
42
+ export declare const DEFAULT_MAX_TOKENS: undefined;
43
+ /**
44
+ * Get default critic model based on reviewer model.
45
+ * If reviewer uses haiku, critic uses sonnet (and vice versa).
46
+ * This ensures structural independence between review and critique.
47
+ */
48
+ export declare const getDefaultCriticModel: (reviewerModel: string | undefined) => string;
49
+ /**
50
+ * Default configuration for surrounding context extraction.
51
+ */
52
+ export declare const DEFAULT_SURROUNDING_CONTEXT_CONFIG: {
53
+ readonly enabled: true;
54
+ readonly maxTokensPerFile: 20000;
55
+ readonly contextLines: 10;
56
+ };
57
+ /**
58
+ * Default file patterns to exclude from code review.
59
+ * These patterns match common build artifacts, lockfiles, and generated code.
60
+ * Uses glob patterns (minimatch) instead of regex to avoid ReDoS vulnerabilities.
61
+ */
62
+ export declare const DEFAULT_EXCLUDE_PATTERNS: readonly ["**/*.lock", "**/package-lock.json", "**/pnpm-lock.yaml", "**/yarn.lock", "**/dist/**", "**/build/**", "**/out/**", "**/.next/**", "**/.turbo/**", "**/*.generated.*", "**/*.gen.*", "**/node_modules/**", "**/.vscode/**", "**/.idea/**", ".DS_Store", "**/coverage/**", "**/*.tmp", "**/*.temp"];
63
+ /**
64
+ * Default thresholds for trivial PR triage.
65
+ * PRs meeting these criteria may skip full reviewer flow or use lightweight review.
66
+ */
67
+ export declare const DEFAULT_TRIAGE_MAX_FILES = 3;
68
+ export declare const DEFAULT_TRIAGE_MAX_TOTAL_LINES = 50;
69
+ /**
70
+ * File extensions considered documentation-only for triage purposes.
71
+ */
72
+ export declare const DEFAULT_TRIAGE_DOCS_ONLY_EXTENSIONS: readonly [".md", ".txt", ".rst", ".adoc", ".org"];
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Default model for orchestrator calls.
3
+ * Chosen for fast planning/synthesis while preserving structured-output reliability.
4
+ */
5
+ export const DEFAULT_ORCHESTRATOR_MODEL = 'google/gemini-3-flash-preview';
6
+ /**
7
+ * Default model for reviewer iterations.
8
+ * Tuned for code-centric reasoning with acceptable latency/cost.
9
+ */
10
+ export const DEFAULT_REVIEWER_MODEL = 'qwen/qwen3-coder-next';
11
+ /**
12
+ * Default critic model used when no critic model is explicitly configured.
13
+ */
14
+ export const DEFAULT_CRITIC_MODEL = 'google/gemini-3-flash-preview';
15
+ /**
16
+ * Maximum tool/LLM steps per call for orchestrator/reviewer operations.
17
+ */
18
+ export const DEFAULT_MAX_STEPS = 10;
19
+ /**
20
+ * Maximum validation loops per reviewer (initial pass + critic pass).
21
+ */
22
+ export const DEFAULT_MAX_ITERATIONS = 2;
23
+ /**
24
+ * Maximum tool/LLM steps for synthesis and final decision generation.
25
+ */
26
+ export const DEFAULT_AGGREGATION_MAX_STEPS = 5;
27
+ /**
28
+ * Default temperature for structured output generation.
29
+ * Lower temperature (0-0.3) improves reliability and consistency for structured output.
30
+ */
31
+ export const DEFAULT_TEMPERATURE = 0.2;
32
+ /**
33
+ * Default timeout for LLM calls in milliseconds (2 minutes).
34
+ * Prevents hanging on slow or unresponsive models.
35
+ */
36
+ export const DEFAULT_LLM_TIMEOUT_MS = 120_000;
37
+ /**
38
+ * Default max tokens for structured output generation.
39
+ * Ensures enough tokens for complete structured responses.
40
+ * Set to undefined to use model default (typically 4096-8192).
41
+ */
42
+ export const DEFAULT_MAX_TOKENS = undefined; // Use model default
43
+ /**
44
+ * Get default critic model based on reviewer model.
45
+ * If reviewer uses haiku, critic uses sonnet (and vice versa).
46
+ * This ensures structural independence between review and critique.
47
+ */
48
+ export const getDefaultCriticModel = (reviewerModel) => {
49
+ if (!reviewerModel) {
50
+ return DEFAULT_CRITIC_MODEL;
51
+ }
52
+ // If reviewer uses haiku, critic uses sonnet
53
+ if (reviewerModel.includes('haiku')) {
54
+ return reviewerModel.replace('haiku', 'sonnet');
55
+ }
56
+ // If reviewer uses sonnet, critic uses haiku
57
+ if (reviewerModel.includes('sonnet')) {
58
+ return reviewerModel.replace('sonnet', 'haiku');
59
+ }
60
+ // Default to sonnet for other models
61
+ return DEFAULT_CRITIC_MODEL;
62
+ };
63
+ /**
64
+ * Default configuration for surrounding context extraction.
65
+ */
66
+ export const DEFAULT_SURROUNDING_CONTEXT_CONFIG = {
67
+ enabled: true,
68
+ maxTokensPerFile: 20_000,
69
+ contextLines: 10,
70
+ };
71
+ /**
72
+ * Default file patterns to exclude from code review.
73
+ * These patterns match common build artifacts, lockfiles, and generated code.
74
+ * Uses glob patterns (minimatch) instead of regex to avoid ReDoS vulnerabilities.
75
+ */
76
+ export const DEFAULT_EXCLUDE_PATTERNS = [
77
+ // Lockfiles
78
+ '**/*.lock',
79
+ '**/package-lock.json',
80
+ '**/pnpm-lock.yaml',
81
+ '**/yarn.lock',
82
+ // Build artifacts
83
+ '**/dist/**',
84
+ '**/build/**',
85
+ '**/out/**',
86
+ '**/.next/**',
87
+ '**/.turbo/**',
88
+ // Generated code
89
+ '**/*.generated.*',
90
+ '**/*.gen.*',
91
+ // Dependencies
92
+ '**/node_modules/**',
93
+ // IDE/Editor files
94
+ '**/.vscode/**',
95
+ '**/.idea/**',
96
+ // OS files
97
+ '.DS_Store',
98
+ // Coverage reports
99
+ '**/coverage/**',
100
+ // Temporary files
101
+ '**/*.tmp',
102
+ '**/*.temp',
103
+ ];
104
+ /**
105
+ * Default thresholds for trivial PR triage.
106
+ * PRs meeting these criteria may skip full reviewer flow or use lightweight review.
107
+ */
108
+ export const DEFAULT_TRIAGE_MAX_FILES = 3;
109
+ export const DEFAULT_TRIAGE_MAX_TOTAL_LINES = 50;
110
+ /**
111
+ * File extensions considered documentation-only for triage purposes.
112
+ */
113
+ export const DEFAULT_TRIAGE_DOCS_ONLY_EXTENSIONS = ['.md', '.txt', '.rst', '.adoc', '.org'];
@@ -0,0 +1,34 @@
1
+ import { type LogLevel } from '../logging/logger.js';
2
+ export type ReviewAgentConfig = {
3
+ mcpServerUrl?: string;
4
+ mcpAuthToken?: string;
5
+ openRouterApiKey?: string;
6
+ orchestratorModel?: string;
7
+ reviewerModel?: string;
8
+ criticModel?: string;
9
+ logLevel: LogLevel;
10
+ maxSteps?: number;
11
+ maxIterations?: number;
12
+ aggregationMaxSteps?: number;
13
+ maxTokensPerFile?: number;
14
+ contextLines?: number;
15
+ prDescription?: string;
16
+ reviewDomains?: string[];
17
+ };
18
+ export type ValidatedReviewAgentConfig = {
19
+ mcpServerUrl: string;
20
+ mcpAuthToken: string;
21
+ openRouterApiKey: string;
22
+ orchestratorModel?: string;
23
+ reviewerModel?: string;
24
+ criticModel?: string;
25
+ logLevel: LogLevel;
26
+ maxSteps: number;
27
+ maxIterations: number;
28
+ aggregationMaxSteps: number;
29
+ maxTokensPerFile: number;
30
+ contextLines: number;
31
+ reviewDomains?: string[];
32
+ };
33
+ export declare const loadConfig: () => ReviewAgentConfig;
34
+ export declare const validateConfig: (config: ReviewAgentConfig) => ValidatedReviewAgentConfig;
@@ -0,0 +1,89 @@
1
+ import path from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ import dotenv from 'dotenv';
4
+ import { parseLogLevel } from '../logging/logger.js';
5
+ import { DEFAULT_AGGREGATION_MAX_STEPS, DEFAULT_MAX_ITERATIONS, DEFAULT_MAX_STEPS, DEFAULT_SURROUNDING_CONTEXT_CONFIG, getDefaultCriticModel, } from './defaults.js';
6
+ // Only load .env file if not in test environment
7
+ // Tests should use explicit env vars or test setup files
8
+ const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
9
+ if (process.env.NODE_ENV !== 'test' && !process.env.VITEST) {
10
+ dotenv.config({ path: path.join(packageRoot, '.env') });
11
+ }
12
+ const getMissingRequiredEnvVars = (config) => {
13
+ const missing = [];
14
+ if (!config.mcpServerUrl?.trim()) {
15
+ missing.push('CONTEXTRAIL_MCP_SERVER_URL');
16
+ }
17
+ if (!config.mcpAuthToken?.trim()) {
18
+ missing.push('CONTEXTRAIL_MCP_JWT_TOKEN');
19
+ }
20
+ if (!config.openRouterApiKey?.trim()) {
21
+ missing.push('OPENROUTER_API_KEY');
22
+ }
23
+ return missing;
24
+ };
25
+ const normalizeOptionalString = (value) => {
26
+ const trimmed = value?.trim();
27
+ return trimmed ? trimmed : undefined;
28
+ };
29
+ const parseOptionalInt = (value, defaultValue) => {
30
+ if (!value) {
31
+ return defaultValue;
32
+ }
33
+ const parsed = parseInt(value, 10);
34
+ return Number.isNaN(parsed) ? defaultValue : parsed;
35
+ };
36
+ export const loadConfig = () => {
37
+ const reviewDomains = process.env.REVIEW_DOMAINS
38
+ ? process.env.REVIEW_DOMAINS.split(',')
39
+ .map((domain) => domain.trim())
40
+ .filter(Boolean)
41
+ : undefined;
42
+ const config = {
43
+ mcpServerUrl: normalizeOptionalString(process.env.CONTEXTRAIL_MCP_SERVER_URL),
44
+ mcpAuthToken: normalizeOptionalString(process.env.CONTEXTRAIL_MCP_JWT_TOKEN),
45
+ openRouterApiKey: normalizeOptionalString(process.env.OPENROUTER_API_KEY),
46
+ orchestratorModel: normalizeOptionalString(process.env.LLM_MODEL_ORCHESTRATOR),
47
+ reviewerModel: normalizeOptionalString(process.env.LLM_MODEL_REVIEWER),
48
+ criticModel: normalizeOptionalString(process.env.LLM_MODEL_CRITIC),
49
+ logLevel: parseLogLevel(normalizeOptionalString(process.env.DEBUG)),
50
+ maxSteps: parseOptionalInt(process.env.MAX_STEPS, DEFAULT_MAX_STEPS),
51
+ maxIterations: parseOptionalInt(process.env.MAX_ITERATIONS, DEFAULT_MAX_ITERATIONS),
52
+ aggregationMaxSteps: parseOptionalInt(process.env.AGGREGATION_MAX_STEPS, DEFAULT_AGGREGATION_MAX_STEPS),
53
+ maxTokensPerFile: parseOptionalInt(process.env.MAX_TOKENS_PER_FILE, DEFAULT_SURROUNDING_CONTEXT_CONFIG.maxTokensPerFile),
54
+ contextLines: parseOptionalInt(process.env.CONTEXT_LINES, DEFAULT_SURROUNDING_CONTEXT_CONFIG.contextLines),
55
+ prDescription: normalizeOptionalString(process.env.PR_DESCRIPTION),
56
+ reviewDomains,
57
+ };
58
+ // Fail fast when required environment variables are missing.
59
+ // Note: CLI --help bypasses loadConfig in src/index.ts so help remains accessible.
60
+ const missingRequired = getMissingRequiredEnvVars(config);
61
+ if (missingRequired.length > 0) {
62
+ throw new Error(`Missing required environment variables: ${missingRequired.join(', ')}`);
63
+ }
64
+ return config;
65
+ };
66
+ export const validateConfig = (config) => {
67
+ const mcpServerUrl = config.mcpServerUrl;
68
+ const mcpAuthToken = config.mcpAuthToken;
69
+ const openRouterApiKey = config.openRouterApiKey;
70
+ const missing = getMissingRequiredEnvVars(config);
71
+ if (missing.length > 0) {
72
+ throw new Error(`Missing required environment variables: ${missing.join(', ')}`);
73
+ }
74
+ return {
75
+ mcpServerUrl: mcpServerUrl,
76
+ mcpAuthToken: mcpAuthToken,
77
+ openRouterApiKey: openRouterApiKey,
78
+ orchestratorModel: config.orchestratorModel,
79
+ reviewerModel: config.reviewerModel,
80
+ criticModel: config.criticModel ?? getDefaultCriticModel(config.reviewerModel),
81
+ logLevel: config.logLevel,
82
+ maxSteps: config.maxSteps ?? DEFAULT_MAX_STEPS,
83
+ maxIterations: config.maxIterations ?? DEFAULT_MAX_ITERATIONS,
84
+ aggregationMaxSteps: config.aggregationMaxSteps ?? DEFAULT_AGGREGATION_MAX_STEPS,
85
+ maxTokensPerFile: config.maxTokensPerFile ?? DEFAULT_SURROUNDING_CONTEXT_CONFIG.maxTokensPerFile,
86
+ contextLines: config.contextLines ?? DEFAULT_SURROUNDING_CONTEXT_CONFIG.contextLines,
87
+ reviewDomains: config.reviewDomains,
88
+ };
89
+ };
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};