@in-the-loop-labs/pair-review 3.0.5 → 3.1.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.
- package/package.json +2 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin-code-critic/.claude-plugin/plugin.json +1 -1
- package/plugin-code-critic/skills/analyze/references/level1-balanced.md +8 -0
- package/plugin-code-critic/skills/analyze/references/level1-fast.md +7 -0
- package/plugin-code-critic/skills/analyze/references/level1-thorough.md +8 -0
- package/plugin-code-critic/skills/analyze/references/level2-balanced.md +9 -0
- package/plugin-code-critic/skills/analyze/references/level2-fast.md +8 -0
- package/plugin-code-critic/skills/analyze/references/level2-thorough.md +9 -0
- package/plugin-code-critic/skills/analyze/references/level3-balanced.md +9 -0
- package/plugin-code-critic/skills/analyze/references/level3-fast.md +8 -0
- package/plugin-code-critic/skills/analyze/references/level3-thorough.md +9 -0
- package/plugin-code-critic/skills/analyze/references/orchestration-balanced.md +9 -0
- package/plugin-code-critic/skills/analyze/references/orchestration-fast.md +5 -0
- package/plugin-code-critic/skills/analyze/references/orchestration-thorough.md +9 -0
- package/public/css/analysis-config.css +83 -0
- package/public/css/pr.css +191 -4
- package/public/index.html +20 -0
- package/public/js/components/AIPanel.js +1 -1
- package/public/js/components/AdvancedConfigTab.js +83 -8
- package/public/js/components/AnalysisConfigModal.js +155 -5
- package/public/js/components/ChatPanel.js +22 -5
- package/public/js/components/CouncilProgressModal.js +239 -22
- package/public/js/components/TimeoutSelect.js +2 -0
- package/public/js/components/VoiceCentricConfigTab.js +179 -12
- package/public/js/index.js +119 -1
- package/public/js/local.js +141 -47
- package/public/js/modules/suggestion-manager.js +2 -1
- package/public/js/pr.js +71 -12
- package/public/js/repo-settings.js +2 -2
- package/public/local.html +32 -11
- package/public/pr.html +2 -0
- package/src/ai/analyzer.js +371 -111
- package/src/ai/claude-provider.js +2 -0
- package/src/ai/codex-provider.js +1 -1
- package/src/ai/copilot-provider.js +2 -0
- package/src/ai/executable-provider.js +534 -0
- package/src/ai/gemini-provider.js +2 -0
- package/src/ai/index.js +9 -1
- package/src/ai/pi-provider.js +10 -8
- package/src/ai/prompts/baseline/consolidation/balanced.js +54 -2
- package/src/ai/prompts/baseline/consolidation/fast.js +31 -1
- package/src/ai/prompts/baseline/consolidation/thorough.js +46 -3
- package/src/ai/prompts/baseline/level1/balanced.js +12 -0
- package/src/ai/prompts/baseline/level1/fast.js +11 -0
- package/src/ai/prompts/baseline/level1/thorough.js +12 -0
- package/src/ai/prompts/baseline/level2/balanced.js +13 -0
- package/src/ai/prompts/baseline/level2/fast.js +12 -0
- package/src/ai/prompts/baseline/level2/thorough.js +13 -0
- package/src/ai/prompts/baseline/level3/balanced.js +13 -0
- package/src/ai/prompts/baseline/level3/fast.js +12 -0
- package/src/ai/prompts/baseline/level3/thorough.js +13 -0
- package/src/ai/prompts/baseline/orchestration/balanced.js +15 -0
- package/src/ai/prompts/baseline/orchestration/fast.js +11 -0
- package/src/ai/prompts/baseline/orchestration/thorough.js +15 -0
- package/src/ai/prompts/render-for-skill.js +3 -0
- package/src/ai/prompts/shared/output-schema.js +8 -0
- package/src/ai/provider.js +89 -4
- package/src/chat/prompt-builder.js +17 -1
- package/src/chat/session-manager.js +32 -28
- package/src/config.js +15 -2
- package/src/database.js +59 -15
- package/src/git/base-branch.js +133 -52
- package/src/local-review.js +15 -9
- package/src/main.js +3 -2
- package/src/routes/analyses.js +34 -8
- package/src/routes/chat.js +15 -8
- package/src/routes/config.js +3 -120
- package/src/routes/councils.js +15 -6
- package/src/routes/executable-analysis.js +494 -0
- package/src/routes/local.js +160 -26
- package/src/routes/mcp.js +9 -4
- package/src/routes/pr.js +166 -29
- package/src/routes/reviews.js +31 -5
- package/src/routes/shared.js +72 -5
- package/src/routes/worktrees.js +4 -2
- package/src/utils/comment-formatter.js +28 -11
- package/src/utils/instructions.js +22 -8
- package/src/utils/logger.js +20 -10
|
@@ -96,6 +96,14 @@ Do NOT modify files.
|
|
|
96
96
|
{{sparseCheckoutGuidance}}
|
|
97
97
|
</section>
|
|
98
98
|
|
|
99
|
+
<section name="severity-classification" required="true" tier="fast">
|
|
100
|
+
### Severity
|
|
101
|
+
Assign severity to each suggestion (omit for praise):
|
|
102
|
+
- **critical**: Production incidents, crashes, security vulnerabilities, data corruption/loss, race conditions, breaking changes, test failures
|
|
103
|
+
- **medium**: Degraded functionality, missing error handling, missing validation, missing/poor test coverage
|
|
104
|
+
- **minor**: Code quality, docs gaps, minor optimizations
|
|
105
|
+
</section>
|
|
106
|
+
|
|
99
107
|
<section name="output-schema" locked="true">
|
|
100
108
|
## Output Format
|
|
101
109
|
|
|
@@ -109,6 +117,7 @@ Output JSON with this structure:
|
|
|
109
117
|
"line": 42,
|
|
110
118
|
"old_or_new": "NEW",
|
|
111
119
|
"type": "bug|improvement|praise|suggestion|design|performance|security|code-style",
|
|
120
|
+
"severity": "critical|medium|minor (omit for praise)",
|
|
112
121
|
"title": "Brief title",
|
|
113
122
|
"description": "Detailed explanation mentioning why codebase context was needed",
|
|
114
123
|
"suggestion": "How to fix/improve based on codebase context (omit for praise items)",
|
|
@@ -117,6 +126,7 @@ Output JSON with this structure:
|
|
|
117
126
|
"fileLevelSuggestions": [{
|
|
118
127
|
"file": "path/to/file",
|
|
119
128
|
"type": "bug|improvement|praise|suggestion|design|performance|security|code-style",
|
|
129
|
+
"severity": "critical|medium|minor (omit for praise)",
|
|
120
130
|
"title": "Brief title describing file-level concern",
|
|
121
131
|
"description": "Explanation of the file-level observation from codebase perspective",
|
|
122
132
|
"suggestion": "How to address the file-level concern (omit for praise items)",
|
|
@@ -169,6 +179,7 @@ const sections = [
|
|
|
169
179
|
{ name: 'focus-areas', required: true, tier: ['fast'] },
|
|
170
180
|
{ name: 'available-commands', required: true, tier: ['fast'] },
|
|
171
181
|
{ name: 'sparse-checkout', optional: true, tier: ['fast', 'balanced', 'thorough'] },
|
|
182
|
+
{ name: 'severity-classification', required: true, tier: ['fast'] },
|
|
172
183
|
{ name: 'output-schema', locked: true },
|
|
173
184
|
{ name: 'diff-instructions', required: true, tier: ['fast'] },
|
|
174
185
|
{ name: 'guidelines', required: true, tier: ['fast'] }
|
|
@@ -191,6 +202,7 @@ const defaultOrder = [
|
|
|
191
202
|
'focus-areas',
|
|
192
203
|
'available-commands',
|
|
193
204
|
'sparse-checkout',
|
|
205
|
+
'severity-classification',
|
|
194
206
|
'output-schema',
|
|
195
207
|
'diff-instructions',
|
|
196
208
|
'guidelines'
|
|
@@ -238,6 +238,15 @@ Note: You may optionally use parallel read-only Tasks to explore different areas
|
|
|
238
238
|
{{sparseCheckoutGuidance}}
|
|
239
239
|
</section>
|
|
240
240
|
|
|
241
|
+
<section name="severity-classification" required="true">
|
|
242
|
+
### Severity Classification
|
|
243
|
+
Assign a severity to each suggestion (except praise):
|
|
244
|
+
- **critical**: Production incidents, system failures, or security vulnerabilities — runtime crashes, data corruption or loss, race conditions, deadlocks, breaking changes, changes that will cause existing tests to fail
|
|
245
|
+
- **medium**: Degraded functionality or reliability — missing error handling, N+1 queries, missing validation, missing or poor test coverage for new functionality
|
|
246
|
+
- **minor**: Code quality concerns — documentation gaps, minor optimizations, style inconsistencies
|
|
247
|
+
Omit severity for praise items.
|
|
248
|
+
</section>
|
|
249
|
+
|
|
241
250
|
<section name="output-schema" locked="true">
|
|
242
251
|
## Output Format
|
|
243
252
|
|
|
@@ -251,6 +260,7 @@ Output JSON with this structure:
|
|
|
251
260
|
"line": 42,
|
|
252
261
|
"old_or_new": "NEW",
|
|
253
262
|
"type": "bug|improvement|praise|suggestion|design|performance|security|code-style",
|
|
263
|
+
"severity": "critical|medium|minor (omit for praise)",
|
|
254
264
|
"title": "Brief title",
|
|
255
265
|
"description": "Detailed explanation mentioning why codebase context was needed",
|
|
256
266
|
"suggestion": "How to fix/improve based on codebase context (omit for praise items)",
|
|
@@ -260,6 +270,7 @@ Output JSON with this structure:
|
|
|
260
270
|
"fileLevelSuggestions": [{
|
|
261
271
|
"file": "path/to/file",
|
|
262
272
|
"type": "bug|improvement|praise|suggestion|design|performance|security|code-style",
|
|
273
|
+
"severity": "critical|medium|minor (omit for praise)",
|
|
263
274
|
"title": "Brief title describing file-level concern",
|
|
264
275
|
"description": "Explanation of the file-level observation from codebase perspective",
|
|
265
276
|
"suggestion": "How to address the file-level concern (omit for praise items)",
|
|
@@ -403,6 +414,7 @@ const sections = [
|
|
|
403
414
|
{ name: 'focus-areas', required: true, tier: ['thorough'] },
|
|
404
415
|
{ name: 'available-commands', required: true, tier: ['thorough'] },
|
|
405
416
|
{ name: 'sparse-checkout', optional: true, tier: ['fast', 'balanced', 'thorough'] },
|
|
417
|
+
{ name: 'severity-classification', required: true },
|
|
406
418
|
{ name: 'output-schema', locked: true },
|
|
407
419
|
{ name: 'diff-instructions', required: true, tier: ['thorough'] },
|
|
408
420
|
{ name: 'confidence-guidance', required: true, tier: ['thorough'] },
|
|
@@ -429,6 +441,7 @@ const defaultOrder = [
|
|
|
429
441
|
'focus-areas',
|
|
430
442
|
'available-commands',
|
|
431
443
|
'sparse-checkout',
|
|
444
|
+
'severity-classification',
|
|
432
445
|
'output-schema',
|
|
433
446
|
'diff-instructions',
|
|
434
447
|
'confidence-guidance',
|
|
@@ -25,6 +25,7 @@ const { ORCHESTRATION_INPUT_SCHEMA_DOCS } = require('../../shared/output-schema'
|
|
|
25
25
|
* - {{reviewIntro}} - Review introduction line
|
|
26
26
|
* - {{prContext}} - PR context section (optional, may be empty)
|
|
27
27
|
* - {{customInstructions}} - Custom instructions section (optional)
|
|
28
|
+
* - {{dedupInstructions}} - Dedup instructions section (optional)
|
|
28
29
|
* - {{lineNumberGuidance}} - Line number guidance section
|
|
29
30
|
* - {{level1Count}} - Number of Level 1 suggestions
|
|
30
31
|
* - {{level2Count}} - Number of Level 2 suggestions
|
|
@@ -58,6 +59,10 @@ You are helping a human reviewer by intelligently curating and merging suggestio
|
|
|
58
59
|
{{customInstructions}}
|
|
59
60
|
</section>
|
|
60
61
|
|
|
62
|
+
<section name="dedup-instructions" optional="true">
|
|
63
|
+
{{dedupInstructions}}
|
|
64
|
+
</section>
|
|
65
|
+
|
|
61
66
|
<section name="input-suggestions" locked="true">
|
|
62
67
|
## Input: Multi-Level Analysis Results
|
|
63
68
|
|
|
@@ -82,6 +87,12 @@ ${ORCHESTRATION_INPUT_SCHEMA_DOCS}
|
|
|
82
87
|
- **Preserve unique insights** that only one level discovered
|
|
83
88
|
- **Prefer preserving line-level suggestions** over file-level suggestions when curating
|
|
84
89
|
- **Do NOT mention which level found the issue** - focus on the insight itself
|
|
90
|
+
- **Assess severity** based on the evidence and reasoning across input levels. When levels assign different severities, evaluate the supporting evidence rather than defaulting to the highest. When truly uncertain, preserve the highest severity. Omit severity for praise items.
|
|
91
|
+
|
|
92
|
+
**Severity Definitions:**
|
|
93
|
+
- **critical**: Production incidents, system failures, or security vulnerabilities — runtime crashes, data corruption or loss, race conditions, deadlocks, breaking changes, changes that will cause existing tests to fail
|
|
94
|
+
- **medium**: Degraded functionality or reliability — missing error handling, N+1 queries, missing validation, missing or poor test coverage for new functionality
|
|
95
|
+
- **minor**: Code quality concerns — documentation gaps, minor optimizations, style inconsistencies
|
|
85
96
|
</section>
|
|
86
97
|
|
|
87
98
|
<section name="priority-curation" required="true">
|
|
@@ -123,6 +134,7 @@ Output JSON with this structure:
|
|
|
123
134
|
"line": 42,
|
|
124
135
|
"old_or_new": "NEW",
|
|
125
136
|
"type": "bug|improvement|praise|suggestion|design|performance|security|code-style",
|
|
137
|
+
"severity": "critical|medium|minor (omit for praise)",
|
|
126
138
|
"title": "Brief title describing the curated insight",
|
|
127
139
|
"description": "Clear explanation of the issue and why this guidance matters to the human reviewer",
|
|
128
140
|
"suggestion": "Specific, actionable guidance for the reviewer. For praise items this can be omitted. For other types always include specific, actionable suggestions.",
|
|
@@ -132,6 +144,7 @@ Output JSON with this structure:
|
|
|
132
144
|
"fileLevelSuggestions": [{
|
|
133
145
|
"file": "path/to/file",
|
|
134
146
|
"type": "bug|improvement|praise|suggestion|design|performance|security|code-style",
|
|
147
|
+
"severity": "critical|medium|minor (omit for praise)",
|
|
135
148
|
"title": "Brief title describing file-level concern",
|
|
136
149
|
"description": "Explanation of the file-level observation",
|
|
137
150
|
"suggestion": "How to address the file-level concern (omit for praise items)",
|
|
@@ -199,6 +212,7 @@ const sections = [
|
|
|
199
212
|
{ name: 'critical-output', locked: true },
|
|
200
213
|
{ name: 'role-description', required: true },
|
|
201
214
|
{ name: 'custom-instructions', optional: true },
|
|
215
|
+
{ name: 'dedup-instructions', optional: true },
|
|
202
216
|
{ name: 'input-suggestions', locked: true },
|
|
203
217
|
{ name: 'intelligent-merging', required: true },
|
|
204
218
|
{ name: 'priority-curation', required: true },
|
|
@@ -220,6 +234,7 @@ const defaultOrder = [
|
|
|
220
234
|
'critical-output',
|
|
221
235
|
'role-description',
|
|
222
236
|
'custom-instructions',
|
|
237
|
+
'dedup-instructions',
|
|
223
238
|
'input-suggestions',
|
|
224
239
|
'intelligent-merging',
|
|
225
240
|
'priority-curation',
|
|
@@ -28,6 +28,7 @@ const { ORCHESTRATION_INPUT_SCHEMA_DOCS } = require('../../shared/output-schema'
|
|
|
28
28
|
* - {{reviewIntro}} - Review introduction line
|
|
29
29
|
* - {{prContext}} - PR context section (optional, may be empty)
|
|
30
30
|
* - {{customInstructions}} - Custom instructions section (optional)
|
|
31
|
+
* - {{dedupInstructions}} - Dedup instructions section (optional)
|
|
31
32
|
* - {{lineNumberGuidance}} - Line number guidance section
|
|
32
33
|
* - {{level1Count}} - Number of Level 1 suggestions
|
|
33
34
|
* - {{level2Count}} - Number of Level 2 suggestions
|
|
@@ -61,6 +62,10 @@ Curate and merge 3-level suggestions. Remove duplicates. Keep high-value items o
|
|
|
61
62
|
{{customInstructions}}
|
|
62
63
|
</section>
|
|
63
64
|
|
|
65
|
+
<section name="dedup-instructions" optional="true">
|
|
66
|
+
{{dedupInstructions}}
|
|
67
|
+
</section>
|
|
68
|
+
|
|
64
69
|
<section name="input-suggestions" locked="true">
|
|
65
70
|
## Input: Multi-Level Analysis Results
|
|
66
71
|
|
|
@@ -79,6 +84,8 @@ ${ORCHESTRATION_INPUT_SCHEMA_DOCS}
|
|
|
79
84
|
<section name="intelligent-merging" required="true" tier="fast">
|
|
80
85
|
## Rules
|
|
81
86
|
Combine related suggestions. Merge overlaps. Preserve unique insights. Never mention levels.
|
|
87
|
+
Assess severity using evidence across levels; preserve highest when uncertain. Omit for praise.
|
|
88
|
+
Severity: critical (crashes, security, data loss, race conditions, breaking changes, test failures), medium (degraded functionality, missing error handling/validation/test coverage), minor (code quality, docs, optimizations).
|
|
82
89
|
</section>
|
|
83
90
|
|
|
84
91
|
<section name="priority-curation" required="true" tier="fast">
|
|
@@ -105,6 +112,7 @@ Use "Consider...", "Worth noting..." - guidance not mandates.
|
|
|
105
112
|
"line": 42,
|
|
106
113
|
"old_or_new": "NEW",
|
|
107
114
|
"type": "bug|improvement|praise|suggestion|design|performance|security|code-style",
|
|
115
|
+
"severity": "critical|medium|minor (omit for praise)",
|
|
108
116
|
"title": "Brief title",
|
|
109
117
|
"description": "Why it matters",
|
|
110
118
|
"suggestion": "What to do (omit for praise)",
|
|
@@ -113,6 +121,7 @@ Use "Consider...", "Worth noting..." - guidance not mandates.
|
|
|
113
121
|
"fileLevelSuggestions": [{
|
|
114
122
|
"file": "path/to/file",
|
|
115
123
|
"type": "...",
|
|
124
|
+
"severity": "critical|medium|minor (omit for praise)",
|
|
116
125
|
"title": "Brief title",
|
|
117
126
|
"description": "File-level observation",
|
|
118
127
|
"suggestion": "How to fix (omit for praise)",
|
|
@@ -152,6 +161,7 @@ const sections = [
|
|
|
152
161
|
{ name: 'critical-output', locked: true },
|
|
153
162
|
{ name: 'role-description', required: true, tier: ['fast'] },
|
|
154
163
|
{ name: 'custom-instructions', optional: true, tier: ['fast', 'balanced', 'thorough'] },
|
|
164
|
+
{ name: 'dedup-instructions', optional: true },
|
|
155
165
|
{ name: 'input-suggestions', locked: true },
|
|
156
166
|
{ name: 'intelligent-merging', required: true, tier: ['fast'] },
|
|
157
167
|
{ name: 'priority-curation', required: true, tier: ['fast'] },
|
|
@@ -173,6 +183,7 @@ const defaultOrder = [
|
|
|
173
183
|
'critical-output',
|
|
174
184
|
'role-description',
|
|
175
185
|
'custom-instructions',
|
|
186
|
+
'dedup-instructions',
|
|
176
187
|
'input-suggestions',
|
|
177
188
|
'intelligent-merging',
|
|
178
189
|
'priority-curation',
|
|
@@ -32,6 +32,7 @@ const { ORCHESTRATION_INPUT_SCHEMA_DOCS } = require('../../shared/output-schema'
|
|
|
32
32
|
* - {{reviewIntro}} - Review introduction line
|
|
33
33
|
* - {{prContext}} - PR context section (optional, may be empty)
|
|
34
34
|
* - {{customInstructions}} - Custom instructions section (optional)
|
|
35
|
+
* - {{dedupInstructions}} - Dedup instructions section (optional)
|
|
35
36
|
* - {{lineNumberGuidance}} - Line number guidance section
|
|
36
37
|
* - {{level1Count}} - Number of Level 1 suggestions
|
|
37
38
|
* - {{level2Count}} - Number of Level 2 suggestions
|
|
@@ -85,6 +86,10 @@ Quality matters more than speed for this orchestration level. It's better to sur
|
|
|
85
86
|
{{customInstructions}}
|
|
86
87
|
</section>
|
|
87
88
|
|
|
89
|
+
<section name="dedup-instructions" optional="true">
|
|
90
|
+
{{dedupInstructions}}
|
|
91
|
+
</section>
|
|
92
|
+
|
|
88
93
|
<section name="input-suggestions" locked="true">
|
|
89
94
|
## Input: Multi-Level Analysis Results
|
|
90
95
|
|
|
@@ -134,6 +139,12 @@ When levels disagree (e.g., Level 1 flags an issue that Level 3 says follows cod
|
|
|
134
139
|
- Use the clearest framing, regardless of which level provided it
|
|
135
140
|
- Do NOT mention which level found the issue - focus on the insight itself
|
|
136
141
|
- When merging would lose important nuance, keep suggestions distinct
|
|
142
|
+
- **Assess severity** based on the evidence and reasoning across input levels. When levels assign different severities, evaluate the supporting evidence rather than defaulting to the highest. When truly uncertain, preserve the highest severity. Omit severity for praise items.
|
|
143
|
+
|
|
144
|
+
**Severity Definitions:**
|
|
145
|
+
- **critical**: Production incidents, system failures, or security vulnerabilities — runtime crashes, data corruption or loss, race conditions, deadlocks, breaking changes, changes that will cause existing tests to fail
|
|
146
|
+
- **medium**: Degraded functionality or reliability — missing error handling, N+1 queries, missing validation, missing or poor test coverage for new functionality
|
|
147
|
+
- **minor**: Code quality concerns — documentation gaps, minor optimizations, style inconsistencies
|
|
137
148
|
</section>
|
|
138
149
|
|
|
139
150
|
<section name="priority-curation" required="true" tier="thorough">
|
|
@@ -266,6 +277,7 @@ Output JSON with this structure:
|
|
|
266
277
|
"line": 42,
|
|
267
278
|
"old_or_new": "NEW",
|
|
268
279
|
"type": "bug|improvement|praise|suggestion|design|performance|security|code-style",
|
|
280
|
+
"severity": "critical|medium|minor (omit for praise)",
|
|
269
281
|
"title": "Brief title describing the curated insight",
|
|
270
282
|
"description": "Clear explanation of the issue and why this guidance matters to the human reviewer",
|
|
271
283
|
"suggestion": "Specific, actionable guidance for the reviewer (omit for praise items)",
|
|
@@ -275,6 +287,7 @@ Output JSON with this structure:
|
|
|
275
287
|
"fileLevelSuggestions": [{
|
|
276
288
|
"file": "path/to/file",
|
|
277
289
|
"type": "bug|improvement|praise|suggestion|design|performance|security|code-style",
|
|
290
|
+
"severity": "critical|medium|minor (omit for praise)",
|
|
278
291
|
"title": "Brief title describing file-level concern",
|
|
279
292
|
"description": "Explanation of the file-level observation",
|
|
280
293
|
"suggestion": "How to address the file-level concern (omit for praise items)",
|
|
@@ -380,6 +393,7 @@ const sections = [
|
|
|
380
393
|
{ name: 'role-description', required: true, tier: ['thorough'] },
|
|
381
394
|
{ name: 'reasoning-encouragement', required: true, tier: ['thorough'] },
|
|
382
395
|
{ name: 'custom-instructions', optional: true, tier: ['balanced', 'thorough'] },
|
|
396
|
+
{ name: 'dedup-instructions', optional: true },
|
|
383
397
|
{ name: 'input-suggestions', locked: true },
|
|
384
398
|
{ name: 'intelligent-merging', required: true, tier: ['thorough'] },
|
|
385
399
|
{ name: 'priority-curation', required: true, tier: ['thorough'] },
|
|
@@ -405,6 +419,7 @@ const defaultOrder = [
|
|
|
405
419
|
'role-description',
|
|
406
420
|
'reasoning-encouragement',
|
|
407
421
|
'custom-instructions',
|
|
422
|
+
'dedup-instructions',
|
|
408
423
|
'input-suggestions',
|
|
409
424
|
'intelligent-merging',
|
|
410
425
|
'priority-curation',
|
|
@@ -39,6 +39,9 @@ const SKILL_DEFAULTS = {
|
|
|
39
39
|
changedFiles:
|
|
40
40
|
'[Changed files list provided by the orchestrating agent]',
|
|
41
41
|
|
|
42
|
+
// Dedup instructions — empty by default (section collapses)
|
|
43
|
+
dedupInstructions: '',
|
|
44
|
+
|
|
42
45
|
// Orchestration data markers
|
|
43
46
|
level1Count: '[N]',
|
|
44
47
|
level2Count: '[N]',
|
|
@@ -22,6 +22,7 @@ const ORCHESTRATION_INPUT_SCHEMA_DOCS = `Each level provides suggestions as a JS
|
|
|
22
22
|
- title: brief title
|
|
23
23
|
- description: full explanation
|
|
24
24
|
- suggestion: remediation advice
|
|
25
|
+
- severity: "critical", "medium", or "minor" (omit for praise items)
|
|
25
26
|
- confidence: 0.0-1.0 score
|
|
26
27
|
- reasoning: (optional) array of strings with step-by-step reasoning
|
|
27
28
|
- is_file_level: true if this is a file-level suggestion (no line numbers)`;
|
|
@@ -37,6 +38,7 @@ const LEVEL1_OUTPUT_SCHEMA = {
|
|
|
37
38
|
line_end: 42,
|
|
38
39
|
old_or_new: 'NEW',
|
|
39
40
|
type: 'bug|improvement|praise|suggestion|design|performance|security|code-style',
|
|
41
|
+
severity: 'critical|medium|minor (omit for praise)',
|
|
40
42
|
title: 'Brief title',
|
|
41
43
|
description: 'Detailed explanation',
|
|
42
44
|
suggestion: 'How to fix/improve (omit this field for praise items - no action needed)',
|
|
@@ -57,6 +59,7 @@ const LEVEL2_OUTPUT_SCHEMA = {
|
|
|
57
59
|
line_end: 42,
|
|
58
60
|
old_or_new: 'NEW',
|
|
59
61
|
type: 'bug|improvement|praise|suggestion|design|performance|security|code-style',
|
|
62
|
+
severity: 'critical|medium|minor (omit for praise)',
|
|
60
63
|
title: 'Brief title',
|
|
61
64
|
description: 'Detailed explanation mentioning why full file context was needed',
|
|
62
65
|
suggestion: 'How to fix/improve based on file context (omit for praise items)',
|
|
@@ -66,6 +69,7 @@ const LEVEL2_OUTPUT_SCHEMA = {
|
|
|
66
69
|
fileLevelSuggestions: [{
|
|
67
70
|
file: 'path/to/file',
|
|
68
71
|
type: 'bug|improvement|praise|suggestion|design|performance|security|code-style',
|
|
72
|
+
severity: 'critical|medium|minor (omit for praise)',
|
|
69
73
|
title: 'Brief title describing file-level concern',
|
|
70
74
|
description: 'Explanation of the file-level observation (architecture, organization, naming, etc.)',
|
|
71
75
|
suggestion: 'How to address the file-level concern (omit for praise items)',
|
|
@@ -86,6 +90,7 @@ const LEVEL3_OUTPUT_SCHEMA = {
|
|
|
86
90
|
line_end: 42,
|
|
87
91
|
old_or_new: 'NEW',
|
|
88
92
|
type: 'bug|improvement|praise|suggestion|design|performance|security|code-style',
|
|
93
|
+
severity: 'critical|medium|minor (omit for praise)',
|
|
89
94
|
title: 'Brief title',
|
|
90
95
|
description: 'Detailed explanation mentioning why codebase context was needed',
|
|
91
96
|
suggestion: 'How to fix/improve based on codebase context (omit for praise items)',
|
|
@@ -95,6 +100,7 @@ const LEVEL3_OUTPUT_SCHEMA = {
|
|
|
95
100
|
fileLevelSuggestions: [{
|
|
96
101
|
file: 'path/to/file',
|
|
97
102
|
type: 'bug|improvement|praise|suggestion|design|performance|security|code-style',
|
|
103
|
+
severity: 'critical|medium|minor (omit for praise)',
|
|
98
104
|
title: 'Brief title describing file-level concern',
|
|
99
105
|
description: 'Explanation of the file-level observation from codebase perspective',
|
|
100
106
|
suggestion: 'How to address the file-level concern (omit for praise items)',
|
|
@@ -115,6 +121,7 @@ const ORCHESTRATION_OUTPUT_SCHEMA = {
|
|
|
115
121
|
line_end: 42,
|
|
116
122
|
old_or_new: 'NEW',
|
|
117
123
|
type: 'bug|improvement|praise|suggestion|design|performance|security|code-style',
|
|
124
|
+
severity: 'critical|medium|minor (omit for praise)',
|
|
118
125
|
title: 'Brief title describing the curated insight',
|
|
119
126
|
description: 'Clear explanation of the issue and why this guidance matters to the human reviewer',
|
|
120
127
|
suggestion: 'Specific, actionable guidance for the reviewer (omit for praise items)',
|
|
@@ -124,6 +131,7 @@ const ORCHESTRATION_OUTPUT_SCHEMA = {
|
|
|
124
131
|
fileLevelSuggestions: [{
|
|
125
132
|
file: 'path/to/file',
|
|
126
133
|
type: 'bug|improvement|praise|suggestion|design|performance|security|code-style',
|
|
134
|
+
severity: 'critical|medium|minor (omit for praise)',
|
|
127
135
|
title: 'Brief title describing file-level concern',
|
|
128
136
|
description: 'Explanation of the file-level observation',
|
|
129
137
|
suggestion: 'How to address the file-level concern (omit for praise items)',
|
package/src/ai/provider.js
CHANGED
|
@@ -424,9 +424,43 @@ function resolveDefaultModel(models) {
|
|
|
424
424
|
}
|
|
425
425
|
|
|
426
426
|
/**
|
|
427
|
-
*
|
|
428
|
-
*
|
|
429
|
-
*
|
|
427
|
+
* Create an aliased provider class that reuses an existing provider's implementation
|
|
428
|
+
* but with a different ID, name, and config overrides.
|
|
429
|
+
*
|
|
430
|
+
* @param {string} aliasId - New provider ID (e.g., 'pi-reskin')
|
|
431
|
+
* @param {typeof AIProvider} BaseClass - The base provider class to alias
|
|
432
|
+
* @param {Object} aliasConfig - Config for the alias (name, models, etc.)
|
|
433
|
+
* @returns {typeof AIProvider} A subclass with overridden static metadata
|
|
434
|
+
*/
|
|
435
|
+
function createAliasedProviderClass(aliasId, BaseClass, aliasConfig) {
|
|
436
|
+
const processedModels = Array.isArray(aliasConfig.models) && aliasConfig.models.length > 0
|
|
437
|
+
? aliasConfig.models.map(inferModelDefaults)
|
|
438
|
+
: null;
|
|
439
|
+
|
|
440
|
+
class AliasedProvider extends BaseClass {}
|
|
441
|
+
|
|
442
|
+
// Override static metadata so the alias has its own identity
|
|
443
|
+
AliasedProvider.getProviderName = () => aliasConfig.name || aliasId;
|
|
444
|
+
AliasedProvider.getProviderId = () => aliasId;
|
|
445
|
+
if (processedModels) {
|
|
446
|
+
AliasedProvider.getModels = () => processedModels;
|
|
447
|
+
AliasedProvider.getDefaultModel = () => resolveDefaultModel(processedModels);
|
|
448
|
+
}
|
|
449
|
+
if (aliasConfig.installInstructions) {
|
|
450
|
+
AliasedProvider.getInstallInstructions = () => aliasConfig.installInstructions;
|
|
451
|
+
}
|
|
452
|
+
if (aliasConfig.defaultTimeout != null) {
|
|
453
|
+
AliasedProvider.defaultTimeout = aliasConfig.defaultTimeout;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
return AliasedProvider;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Apply configuration overrides for all providers.
|
|
461
|
+
* Called once at startup after all providers have self-registered.
|
|
462
|
+
* Does not support re-application — the provider registry is intentionally
|
|
463
|
+
* not cleaned between calls (aliased/executable classes persist).
|
|
430
464
|
* @param {Object} config - Configuration object from loadConfig()
|
|
431
465
|
*/
|
|
432
466
|
function applyConfigOverrides(config) {
|
|
@@ -446,6 +480,47 @@ function applyConfigOverrides(config) {
|
|
|
446
480
|
for (const [providerId, providerConfig] of Object.entries(providersConfig)) {
|
|
447
481
|
logger.debug(`Applying config overrides for provider: ${providerId}`);
|
|
448
482
|
|
|
483
|
+
// Executable providers: dynamically create and register a provider class
|
|
484
|
+
if (providerConfig.type === 'executable') {
|
|
485
|
+
if (!providerConfig.command) {
|
|
486
|
+
logger.warn(`Executable provider "${providerId}" missing required "command" field`);
|
|
487
|
+
continue;
|
|
488
|
+
}
|
|
489
|
+
// Lazy-require to avoid circular dependency
|
|
490
|
+
const { createExecutableProviderClass } = require('./executable-provider');
|
|
491
|
+
const ExecClass = createExecutableProviderClass(providerId, providerConfig);
|
|
492
|
+
registerProvider(providerId, ExecClass);
|
|
493
|
+
providerConfigOverrides.set(providerId, { ...providerConfig, models: ExecClass.getModels() });
|
|
494
|
+
logger.debug(`Registered executable provider: ${providerId}`);
|
|
495
|
+
continue;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Type matching a registered provider ID creates an alias of that provider
|
|
499
|
+
if (providerConfig.type && providerConfig.type !== providerId && providerRegistry.has(providerConfig.type)) {
|
|
500
|
+
const BaseClass = providerRegistry.get(providerConfig.type);
|
|
501
|
+
const AliasClass = createAliasedProviderClass(providerId, BaseClass, providerConfig);
|
|
502
|
+
registerProvider(providerId, AliasClass);
|
|
503
|
+
|
|
504
|
+
// Aliases reuse the base provider's implementation class, not its config.
|
|
505
|
+
// Only universal override fields are forwarded; provider-specific fields
|
|
506
|
+
// (e.g. codex args) must be explicitly set in the alias config.
|
|
507
|
+
providerConfigOverrides.set(providerId, {
|
|
508
|
+
command: providerConfig.command,
|
|
509
|
+
installInstructions: providerConfig.installInstructions,
|
|
510
|
+
extra_args: providerConfig.extra_args,
|
|
511
|
+
env: providerConfig.env,
|
|
512
|
+
models: AliasClass.getModels() !== BaseClass.getModels() ? AliasClass.getModels() : null
|
|
513
|
+
});
|
|
514
|
+
logger.debug(`Registered aliased provider: ${providerId} (base: ${providerConfig.type})`);
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// Unknown type: warn and skip (self-referential type falls through to standard override path)
|
|
519
|
+
if (providerConfig.type && providerConfig.type !== providerId) {
|
|
520
|
+
logger.warn(`Provider "${providerId}" has unknown type "${providerConfig.type}" — no matching registered provider`);
|
|
521
|
+
continue;
|
|
522
|
+
}
|
|
523
|
+
|
|
449
524
|
// Process models if specified - infer defaults for each
|
|
450
525
|
let processedModels = null;
|
|
451
526
|
if (Array.isArray(providerConfig.models) && providerConfig.models.length > 0) {
|
|
@@ -543,12 +618,21 @@ function getAllProvidersInfo() {
|
|
|
543
618
|
// Use overridden install instructions if available
|
|
544
619
|
const installInstructions = overrides?.installInstructions || ProviderClass.getInstallInstructions();
|
|
545
620
|
|
|
621
|
+
// Build capabilities: executable providers define their own, others get defaults
|
|
622
|
+
const capabilities = ProviderClass.capabilities || {
|
|
623
|
+
review_levels: true,
|
|
624
|
+
custom_instructions: true
|
|
625
|
+
};
|
|
626
|
+
|
|
546
627
|
providers.push({
|
|
547
628
|
id,
|
|
548
629
|
name: ProviderClass.getProviderName(),
|
|
549
630
|
models,
|
|
550
631
|
defaultModel,
|
|
551
|
-
installInstructions
|
|
632
|
+
installInstructions,
|
|
633
|
+
capabilities,
|
|
634
|
+
isExecutable: ProviderClass.isExecutable || false,
|
|
635
|
+
...(ProviderClass.defaultTimeout != null ? { defaultTimeout: ProviderClass.defaultTimeout } : {})
|
|
552
636
|
});
|
|
553
637
|
}
|
|
554
638
|
return providers;
|
|
@@ -656,6 +740,7 @@ module.exports = {
|
|
|
656
740
|
testProviderAvailability,
|
|
657
741
|
// Config override support
|
|
658
742
|
applyConfigOverrides,
|
|
743
|
+
createAliasedProviderClass,
|
|
659
744
|
getProviderConfigOverrides,
|
|
660
745
|
inferModelDefaults,
|
|
661
746
|
resolveDefaultModel,
|
|
@@ -18,9 +18,10 @@ const logger = require('../utils/logger');
|
|
|
18
18
|
* @param {Object} options.review - Review metadata {id, pr_number, repository, review_type, local_path, name}
|
|
19
19
|
* @param {Object} [options.prData] - PR data with base_sha/head_sha (for PR reviews)
|
|
20
20
|
* @param {string} [options.chatInstructions] - Custom instructions from repo settings to append to system prompt
|
|
21
|
+
* @param {string} [options.commentFormatTemplate] - Resolved comment format template for consistent comment formatting
|
|
21
22
|
* @returns {string} System prompt for the chat agent
|
|
22
23
|
*/
|
|
23
|
-
function buildChatPrompt({ review, prData, chatInstructions }) {
|
|
24
|
+
function buildChatPrompt({ review, prData, chatInstructions, commentFormatTemplate }) {
|
|
24
25
|
const sections = [];
|
|
25
26
|
|
|
26
27
|
// Role
|
|
@@ -53,6 +54,21 @@ function buildChatPrompt({ review, prData, chatInstructions }) {
|
|
|
53
54
|
}
|
|
54
55
|
sections.push(domainLines.join('\n'));
|
|
55
56
|
|
|
57
|
+
// Comment format template — injected when the user has a configured format
|
|
58
|
+
if (commentFormatTemplate) {
|
|
59
|
+
sections.push(
|
|
60
|
+
'## Comment format\n\n' +
|
|
61
|
+
'When creating or editing review comments, use this template:\n' +
|
|
62
|
+
'<template>\n' +
|
|
63
|
+
commentFormatTemplate + '\n' +
|
|
64
|
+
'</template>\n\n' +
|
|
65
|
+
'Template placeholders: {emoji}, {category}, {title}, {severity}, {SEVERITY}, {description}, {suggestion}.\n' +
|
|
66
|
+
'{severity} renders as Title Case (e.g. "Critical"), {SEVERITY} renders as UPPERCASE (e.g. "CRITICAL").\n' +
|
|
67
|
+
'Conditional sections: {?field}...{/field} — include content only when the field has a value.\n' +
|
|
68
|
+
'Always follow this format for consistency with the reviewer\'s preferences.'
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
56
72
|
// API Access — cheat-sheet is injected into initial context; full docs available via GET /api.md
|
|
57
73
|
sections.push(
|
|
58
74
|
'## API Access\n\n' +
|
|
@@ -44,6 +44,12 @@ class ChatSessionManager {
|
|
|
44
44
|
* @returns {Promise<{id: number, status: string}>}
|
|
45
45
|
*/
|
|
46
46
|
async createSession({ provider, model, reviewId, contextCommentId, systemPrompt, cwd, initialContext }) {
|
|
47
|
+
// Resolve provider definition once — used for model fallback and bridge construction
|
|
48
|
+
const providerDef = getChatProvider(provider);
|
|
49
|
+
|
|
50
|
+
// Resolve model: explicit request value > provider config default
|
|
51
|
+
const resolvedModel = model || providerDef?.model || null;
|
|
52
|
+
|
|
47
53
|
// Insert session record into DB
|
|
48
54
|
const stmt = this._db.prepare(`
|
|
49
55
|
INSERT INTO chat_sessions (review_id, context_comment_id, provider, model, status)
|
|
@@ -53,20 +59,20 @@ class ChatSessionManager {
|
|
|
53
59
|
reviewId,
|
|
54
60
|
contextCommentId || null,
|
|
55
61
|
provider,
|
|
56
|
-
|
|
62
|
+
resolvedModel
|
|
57
63
|
);
|
|
58
64
|
const sessionId = Number(result.lastInsertRowid);
|
|
59
65
|
|
|
60
|
-
logger.info(`[ChatSession] Creating session ${sessionId} (provider=${provider}, review=${reviewId})`);
|
|
66
|
+
logger.info(`[ChatSession] Creating session ${sessionId} (provider=${provider}, model=${resolvedModel}, review=${reviewId})`);
|
|
61
67
|
|
|
62
68
|
// Create and start the bridge
|
|
63
69
|
// Chat sessions get bash for git commands; review analysis uses the safe default
|
|
64
70
|
const bridge = this._createBridge(provider, {
|
|
65
71
|
provider,
|
|
66
|
-
model,
|
|
72
|
+
model: resolvedModel,
|
|
67
73
|
cwd,
|
|
68
74
|
systemPrompt,
|
|
69
|
-
});
|
|
75
|
+
}, providerDef);
|
|
70
76
|
|
|
71
77
|
const listeners = {
|
|
72
78
|
delta: new Set(),
|
|
@@ -530,39 +536,38 @@ class ChatSessionManager {
|
|
|
530
536
|
* ACP providers get an AcpBridge; everything else gets a PiBridge with tools/skills.
|
|
531
537
|
* @param {string} provider
|
|
532
538
|
* @param {Object} options - Bridge constructor options
|
|
539
|
+
* @param {Object} [providerDef] - Pre-resolved provider definition (avoids redundant getChatProvider calls)
|
|
533
540
|
* @returns {PiBridge|AcpBridge}
|
|
534
541
|
*/
|
|
535
|
-
_createBridge(provider, options) {
|
|
542
|
+
_createBridge(provider, options, providerDef) {
|
|
543
|
+
const def = providerDef || getChatProvider(provider);
|
|
536
544
|
if (isAcpProvider(provider)) {
|
|
537
|
-
const providerDef = getChatProvider(provider);
|
|
538
545
|
return new AcpBridge({
|
|
539
546
|
...options,
|
|
540
|
-
model: options.model ||
|
|
541
|
-
acpCommand:
|
|
542
|
-
acpArgs:
|
|
543
|
-
env:
|
|
544
|
-
useShell:
|
|
547
|
+
model: options.model || def?.model,
|
|
548
|
+
acpCommand: def?.command,
|
|
549
|
+
acpArgs: def?.args,
|
|
550
|
+
env: def?.env,
|
|
551
|
+
useShell: def?.useShell,
|
|
545
552
|
});
|
|
546
553
|
}
|
|
547
554
|
if (isClaudeCodeProvider(provider)) {
|
|
548
|
-
const providerDef = getChatProvider(provider);
|
|
549
555
|
return new ClaudeCodeBridge({
|
|
550
556
|
...options,
|
|
551
|
-
model: options.model ||
|
|
552
|
-
claudeCommand:
|
|
553
|
-
env:
|
|
554
|
-
useShell:
|
|
557
|
+
model: options.model || def?.model,
|
|
558
|
+
claudeCommand: def?.command,
|
|
559
|
+
env: def?.env,
|
|
560
|
+
useShell: def?.useShell,
|
|
555
561
|
});
|
|
556
562
|
}
|
|
557
563
|
if (isCodexProvider(provider)) {
|
|
558
|
-
const providerDef = getChatProvider(provider);
|
|
559
564
|
return new CodexBridge({
|
|
560
565
|
...options,
|
|
561
|
-
model: options.model ||
|
|
562
|
-
codexCommand:
|
|
563
|
-
codexArgs:
|
|
564
|
-
env:
|
|
565
|
-
useShell:
|
|
566
|
+
model: options.model || def?.model,
|
|
567
|
+
codexCommand: def?.command,
|
|
568
|
+
codexArgs: def?.args,
|
|
569
|
+
env: def?.env,
|
|
570
|
+
useShell: def?.useShell,
|
|
566
571
|
});
|
|
567
572
|
}
|
|
568
573
|
// Pi provider — resolve config overrides (command, model, env) from provider def.
|
|
@@ -570,14 +575,13 @@ class ChatSessionManager {
|
|
|
570
575
|
// which would forward it as `--provider pi` to the Pi CLI. The CLI's --provider flag
|
|
571
576
|
// expects a model provider ("google", "anthropic", etc.) and should only come from
|
|
572
577
|
// explicit user configuration (providerDef.provider).
|
|
573
|
-
const providerDef = getChatProvider(provider);
|
|
574
578
|
return new PiBridge({
|
|
575
579
|
...options,
|
|
576
|
-
provider:
|
|
577
|
-
model: options.model ||
|
|
578
|
-
piCommand:
|
|
579
|
-
env:
|
|
580
|
-
useShell:
|
|
580
|
+
provider: def?.provider || null,
|
|
581
|
+
model: options.model || def?.model,
|
|
582
|
+
piCommand: def?.command,
|
|
583
|
+
env: def?.env,
|
|
584
|
+
useShell: def?.useShell,
|
|
581
585
|
tools: CHAT_TOOLS,
|
|
582
586
|
extensions: [taskExtensionDir],
|
|
583
587
|
});
|