@in-the-loop-labs/pair-review 1.4.3 → 1.5.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 (48) hide show
  1. package/package.json +1 -1
  2. package/plugin/.claude-plugin/plugin.json +1 -1
  3. package/plugin/skills/review-requests/SKILL.md +54 -0
  4. package/plugin-code-critic/.claude-plugin/plugin.json +1 -1
  5. package/public/css/pr.css +1081 -54
  6. package/public/css/repo-settings.css +452 -140
  7. package/public/js/components/AdvancedConfigTab.js +1364 -0
  8. package/public/js/components/AnalysisConfigModal.js +488 -112
  9. package/public/js/components/CouncilProgressModal.js +1416 -0
  10. package/public/js/components/TextInputDialog.js +231 -0
  11. package/public/js/components/TimeoutSelect.js +367 -0
  12. package/public/js/components/VoiceCentricConfigTab.js +1334 -0
  13. package/public/js/local.js +162 -83
  14. package/public/js/modules/analysis-history.js +185 -11
  15. package/public/js/modules/comment-manager.js +13 -0
  16. package/public/js/modules/file-comment-manager.js +28 -0
  17. package/public/js/pr.js +233 -115
  18. package/public/js/repo-settings.js +575 -106
  19. package/public/local.html +11 -1
  20. package/public/pr.html +6 -1
  21. package/public/repo-settings.html +28 -21
  22. package/public/setup.html +8 -2
  23. package/src/ai/analyzer.js +1262 -111
  24. package/src/ai/claude-cli.js +2 -2
  25. package/src/ai/claude-provider.js +6 -6
  26. package/src/ai/codex-provider.js +6 -6
  27. package/src/ai/copilot-provider.js +3 -3
  28. package/src/ai/cursor-agent-provider.js +6 -6
  29. package/src/ai/gemini-provider.js +6 -6
  30. package/src/ai/opencode-provider.js +6 -6
  31. package/src/ai/pi-provider.js +6 -6
  32. package/src/ai/prompts/baseline/consolidation/balanced.js +208 -0
  33. package/src/ai/prompts/baseline/consolidation/fast.js +175 -0
  34. package/src/ai/prompts/baseline/consolidation/thorough.js +283 -0
  35. package/src/ai/prompts/config.js +1 -1
  36. package/src/ai/prompts/index.js +26 -2
  37. package/src/ai/provider.js +4 -2
  38. package/src/database.js +417 -14
  39. package/src/main.js +1 -1
  40. package/src/routes/analysis.js +495 -10
  41. package/src/routes/config.js +36 -15
  42. package/src/routes/councils.js +351 -0
  43. package/src/routes/local.js +33 -11
  44. package/src/routes/mcp.js +9 -2
  45. package/src/routes/setup.js +12 -2
  46. package/src/routes/shared.js +126 -13
  47. package/src/server.js +34 -4
  48. package/src/utils/stats-calculator.js +2 -0
@@ -0,0 +1,283 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ /**
3
+ * Consolidation Thorough Prompt - Comprehensive Cross-Reviewer Suggestion Merging
4
+ *
5
+ * This is the thorough tier variant of Consolidation analysis. It is optimized for
6
+ * careful, detailed merging with extended reasoning and comprehensive guidance
7
+ * for resolving conflicts and synthesizing multi-reviewer findings.
8
+ *
9
+ * Tier-specific optimizations applied:
10
+ * - ADDED: Reasoning encouragement section for thoughtful synthesis
11
+ * - COMPREHENSIVE: Consolidation rules with detailed conflict resolution
12
+ * - COMPREHENSIVE: Consensus handling with confidence calibration
13
+ * - ADDED: Summary synthesis guidance
14
+ * - EXPANDED: Guidelines with review philosophy
15
+ * - INCLUDED: All optional sections
16
+ *
17
+ * Section categories:
18
+ * - locked: Cannot be modified by variants (data integrity)
19
+ * - required: Must be present, content can be rephrased
20
+ * - optional: Can be removed entirely if unhelpful
21
+ */
22
+
23
+ /**
24
+ * Tagged prompt template for Consolidation Thorough analysis
25
+ *
26
+ * Placeholders:
27
+ * - {{reviewIntro}} - Review introduction line
28
+ * - {{lineNumberGuidance}} - Line number guidance section
29
+ * - {{customInstructions}} - Custom instructions section (optional)
30
+ * - {{reviewerSuggestions}} - Formatted reviewer suggestions input
31
+ * - {{suggestionCount}} - Total number of input suggestions
32
+ * - {{reviewerCount}} - Number of reviewers being consolidated
33
+ */
34
+ const taggedPrompt = `<section name="role" required="true" tier="thorough">
35
+ {{reviewIntro}}
36
+ </section>
37
+
38
+ <section name="task-header" required="true" tier="thorough">
39
+ # Deep Cross-Reviewer Consolidation Task
40
+ </section>
41
+
42
+ <section name="line-number-guidance" required="true">
43
+ {{lineNumberGuidance}}
44
+ </section>
45
+
46
+ <section name="critical-output" locked="true">
47
+ **>>> CRITICAL: Output ONLY valid JSON. No markdown, no \`\`\`json blocks. Start with { end with }. <<<**
48
+ </section>
49
+
50
+ <section name="role-description" required="true" tier="thorough">
51
+ ## Your Role
52
+ Multiple independent AI reviewers have analyzed the same code changes. Your task is to carefully merge their findings into a single, high-quality set of suggestions. This requires thoughtful deduplication, nuanced conflict resolution, and preservation of the most valuable unique insights from each reviewer.
53
+
54
+ Each reviewer may have used a different AI model, perspective, or focus area. Your consolidation should produce output that is stronger than any individual review.
55
+ </section>
56
+
57
+ <section name="reasoning-encouragement" required="true" tier="thorough">
58
+ ## Reasoning Approach
59
+ Take your time to analyze the reviewer findings thoroughly. For each cluster of related suggestions:
60
+ 1. Identify which reviewers flagged the same or overlapping issues
61
+ 2. Evaluate the strength of evidence from each reviewer
62
+ 3. Determine the best framing that captures the full insight
63
+ 4. Calibrate confidence based on reviewer agreement and evidence quality
64
+ 5. Consider whether merging would lose important nuance
65
+ 6. Formulate clear, actionable guidance that respects reviewer autonomy
66
+ </section>
67
+
68
+ <section name="custom-instructions" optional="true" tier="balanced,thorough">
69
+ {{customInstructions}}
70
+ </section>
71
+
72
+ <section name="input-suggestions" locked="true">
73
+ ## Input: {{reviewerCount}} Reviewer(s), {{suggestionCount}} Total Suggestions
74
+
75
+ {{reviewerSuggestions}}
76
+ </section>
77
+
78
+ <section name="consolidation-rules" required="true" tier="thorough">
79
+ ## Consolidation Guidelines
80
+
81
+ ### 1. Deduplication
82
+ Apply careful analysis when identifying duplicates:
83
+
84
+ **When to Merge:**
85
+ - Same issue identified at the same file and line by multiple reviewers
86
+ - Overlapping concerns that are better presented as a unified insight
87
+ - Complementary details from different reviewers that enrich understanding
88
+
89
+ **When NOT to Merge:**
90
+ - Issues that are genuinely distinct despite affecting similar code
91
+ - Reviewer-specific context that would be lost in merging
92
+ - Situations where separate action items are clearer than combined ones
93
+
94
+ **Merging Best Practices:**
95
+ - Preserve the most actionable and specific details from each reviewer
96
+ - Use the clearest framing, regardless of which reviewer provided it
97
+ - Do NOT mention which reviewer found the issue — focus on the insight itself
98
+
99
+ ### 2. Conflict Resolution
100
+ When reviewers disagree about an issue:
101
+ - **Evaluate evidence quality**: Concrete code analysis > pattern matching > heuristics
102
+ - **Consider specificity**: More specific analysis usually wins
103
+ - **Weight actionability**: Prefer the suggestion that gives clearer next steps
104
+ - **When truly uncertain**: Include the suggestion with reduced confidence and note the tension in the description
105
+
106
+ ### 3. Unique Insights
107
+ - **Preserve suggestions** that only one reviewer noticed — these are often the most valuable
108
+ - A unique finding from one reviewer may represent a perspective the others missed
109
+ - Don't penalize unique findings with lower confidence just because they lack consensus
110
+
111
+ ### 4. Quality Filter
112
+ - Drop suggestions with very low confidence (< 0.3) unless multiple reviewers agree
113
+ - Elevate suggestions where reviewers independently converge
114
+ </section>
115
+
116
+ <section name="consensus-handling" required="true" tier="thorough">
117
+ ### 5. Consensus Handling and Confidence Calibration
118
+
119
+ **Cross-Reviewer Agreement:**
120
+ - **Strong consensus** (3+ reviewers): Boost confidence by 0.2 (cap at 1.0)
121
+ - **Moderate consensus** (2 reviewers): Boost confidence by 0.1
122
+ - **Single reviewer**: Preserve original confidence — don't penalize valuable unique findings
123
+ - **Contradiction**: Use the lower confidence minus 0.1
124
+
125
+ **Confidence Calibration:**
126
+ - High (0.8+): Clear issues with strong evidence or multi-reviewer consensus
127
+ - Medium (0.5-0.79): Likely valuable suggestions with reasonable evidence
128
+ - Lower (0.3-0.49): Marginal suggestions — include only if unique and actionable
129
+ - Very low (<0.3): Consider omitting unless multi-reviewer consensus
130
+
131
+ Note: Confidence is about certainty of value, not severity.
132
+ </section>
133
+
134
+ <section name="summary-synthesis" required="true" tier="thorough">
135
+ ## Summary Synthesis Guidance
136
+ The summary field should synthesize the findings, not list them.
137
+
138
+ **Effective Summary Approach:**
139
+ - **Lead with the most important insight**: What should the reviewer focus on first?
140
+ - **Connect the dots**: How do individual findings relate to each other?
141
+ - **Calibrate severity**: Is this code fundamentally sound with minor issues, or are there structural problems?
142
+ - **Write as a single reviewer**: Do NOT mention consolidation, merging, or multiple reviewers
143
+ </section>
144
+
145
+ <section name="output-schema" locked="true">
146
+ ## Output Format
147
+
148
+ **>>> CRITICAL: Output ONLY valid JSON. No markdown, no \`\`\`json blocks. Start with { end with }. <<<**
149
+
150
+ Output JSON with this structure:
151
+ {
152
+ "suggestions": [
153
+ {
154
+ "file": "path/to/file",
155
+ "line": 42,
156
+ "old_or_new": "NEW",
157
+ "type": "bug|improvement|praise|suggestion|design|performance|security|code-style",
158
+ "title": "Brief title",
159
+ "description": "Detailed explanation",
160
+ "suggestion": "How to fix/improve (omit for praise)",
161
+ "confidence": 0.0-1.0
162
+ }
163
+ ],
164
+ "fileLevelSuggestions": [{
165
+ "file": "path/to/file",
166
+ "type": "bug|improvement|praise|suggestion|design|performance|security|code-style",
167
+ "title": "Brief title describing file-level concern",
168
+ "description": "Explanation of the file-level observation",
169
+ "suggestion": "How to address the file-level concern (omit for praise items)",
170
+ "confidence": 0.0-1.0
171
+ }],
172
+ "summary": "Brief summary of the key findings and their significance. Write as if a single reviewer produced this analysis — do NOT mention 'consolidation', 'merging', or 'multiple reviewers'."
173
+ }
174
+ </section>
175
+
176
+ <section name="diff-instructions" required="true" tier="thorough">
177
+ ## Line Number Reference (old_or_new field)
178
+ The "old_or_new" field indicates which line number column to use:
179
+ - **"NEW"** (default): Use the NEW column number. Correct for added [+] and context lines.
180
+ - **"OLD"**: Use the OLD column number. ONLY for deleted [-] lines.
181
+
182
+ **IMPORTANT**: Context lines exist in BOTH versions — always use "NEW" for them.
183
+ Preserve the old_or_new value from input suggestions when merging.
184
+ </section>
185
+
186
+ <section name="guidelines" required="true" tier="thorough">
187
+ ## Important Guidelines
188
+
189
+ ### Output Quality
190
+ - **Quality over quantity** — better to have fewer excellent suggestions than many mediocre ones
191
+ - **Cross-reviewer agreement** is strong evidence — boost confidence accordingly
192
+ - **Preserve actionability** — every suggestion should give clear next steps
193
+ - **Maintain context** — don't lose important details when merging
194
+
195
+ ### Coverage and Scope
196
+ - **Only include modified files** — discard suggestions for files not in this changeset
197
+ - **Balance across files** — ensure important issues in all modified files are represented
198
+ - **Preserve unique perspectives** — different reviewer models may catch different things
199
+
200
+ ### Review Philosophy
201
+ - Frame suggestions as considerations, not mandates
202
+ - The human reviewer has context you don't have
203
+ - Focus on the code, not the reviewers
204
+ - When uncertain, prefer quality over quantity
205
+ </section>`;
206
+
207
+ /**
208
+ * Section definitions with metadata
209
+ * Used for parsing and validation
210
+ */
211
+ const sections = [
212
+ { name: 'role', required: true, tier: ['thorough'] },
213
+ { name: 'task-header', required: true, tier: ['thorough'] },
214
+ { name: 'line-number-guidance', required: true },
215
+ { name: 'critical-output', locked: true },
216
+ { name: 'role-description', required: true, tier: ['thorough'] },
217
+ { name: 'reasoning-encouragement', required: true, tier: ['thorough'] },
218
+ { name: 'custom-instructions', optional: true, tier: ['balanced', 'thorough'] },
219
+ { name: 'input-suggestions', locked: true },
220
+ { name: 'consolidation-rules', required: true, tier: ['thorough'] },
221
+ { name: 'consensus-handling', required: true, tier: ['thorough'] },
222
+ { name: 'summary-synthesis', required: true, tier: ['thorough'] },
223
+ { name: 'output-schema', locked: true },
224
+ { name: 'diff-instructions', required: true, tier: ['thorough'] },
225
+ { name: 'guidelines', required: true, tier: ['thorough'] }
226
+ ];
227
+
228
+ /**
229
+ * Default section order for Consolidation Thorough
230
+ */
231
+ const defaultOrder = [
232
+ 'role',
233
+ 'task-header',
234
+ 'line-number-guidance',
235
+ 'critical-output',
236
+ 'role-description',
237
+ 'reasoning-encouragement',
238
+ 'custom-instructions',
239
+ 'input-suggestions',
240
+ 'consolidation-rules',
241
+ 'consensus-handling',
242
+ 'summary-synthesis',
243
+ 'output-schema',
244
+ 'diff-instructions',
245
+ 'guidelines'
246
+ ];
247
+
248
+ /**
249
+ * Parse the tagged prompt into section objects
250
+ * @returns {Array<Object>} Array of section objects with name, attributes, and content
251
+ */
252
+ function parseSections() {
253
+ const sectionRegex = /<section\s+name="([^"]+)"([^>]*)>([\s\S]*?)<\/section>/g;
254
+ const parsed = [];
255
+ let match;
256
+
257
+ while ((match = sectionRegex.exec(taggedPrompt)) !== null) {
258
+ const [, name, attrs, content] = match;
259
+ const section = {
260
+ name,
261
+ content: content.trim(),
262
+ locked: attrs.includes('locked="true"'),
263
+ required: attrs.includes('required="true"'),
264
+ optional: attrs.includes('optional="true"')
265
+ };
266
+
267
+ const tierMatch = attrs.match(/tier="([^"]+)"/);
268
+ if (tierMatch) {
269
+ section.tier = tierMatch[1].split(',').map(t => t.trim());
270
+ }
271
+
272
+ parsed.push(section);
273
+ }
274
+
275
+ return parsed;
276
+ }
277
+
278
+ module.exports = {
279
+ taggedPrompt,
280
+ sections,
281
+ defaultOrder,
282
+ parseSections
283
+ };
@@ -24,7 +24,7 @@ const TIERS = ['fast', 'balanced', 'thorough'];
24
24
  /**
25
25
  * Prompt types (analysis levels)
26
26
  */
27
- const PROMPT_TYPES = ['level1', 'level2', 'level3', 'orchestration'];
27
+ const PROMPT_TYPES = ['level1', 'level2', 'level3', 'orchestration', 'consolidation'];
28
28
 
29
29
  /**
30
30
  * Resolve a user-friendly tier alias to internal tier
@@ -25,10 +25,13 @@ let level3Thorough = null;
25
25
  let orchestrationBalanced = null;
26
26
  let orchestrationFast = null;
27
27
  let orchestrationThorough = null;
28
+ let consolidationFast = null;
29
+ let consolidationBalanced = null;
30
+ let consolidationThorough = null;
28
31
 
29
32
  /**
30
33
  * Load a baseline prompt module
31
- * @param {string} promptType - Prompt type (level1, level2, level3, orchestration)
34
+ * @param {string} promptType - Prompt type (level1, level2, level3, orchestration, consolidation)
32
35
  * @param {string} tier - Capability tier (fast, balanced, thorough)
33
36
  * @returns {Object|null} Baseline module or null if not found
34
37
  */
@@ -117,6 +120,27 @@ function loadBaseline(promptType, tier) {
117
120
  }
118
121
  return orchestrationThorough;
119
122
  }
123
+ // Consolidation Fast
124
+ if (promptType === 'consolidation' && tier === 'fast') {
125
+ if (!consolidationFast) {
126
+ consolidationFast = require('./baseline/consolidation/fast');
127
+ }
128
+ return consolidationFast;
129
+ }
130
+ // Consolidation Balanced
131
+ if (promptType === 'consolidation' && tier === 'balanced') {
132
+ if (!consolidationBalanced) {
133
+ consolidationBalanced = require('./baseline/consolidation/balanced');
134
+ }
135
+ return consolidationBalanced;
136
+ }
137
+ // Consolidation Thorough
138
+ if (promptType === 'consolidation' && tier === 'thorough') {
139
+ if (!consolidationThorough) {
140
+ consolidationThorough = require('./baseline/consolidation/thorough');
141
+ }
142
+ return consolidationThorough;
143
+ }
120
144
  return null;
121
145
  }
122
146
 
@@ -168,7 +192,7 @@ function stripSectionTags(taggedPrompt) {
168
192
  /**
169
193
  * Create a prompt builder for a specific prompt type and tier
170
194
  *
171
- * @param {string} promptType - Prompt type (level1, level2, level3, orchestration)
195
+ * @param {string} promptType - Prompt type (level1, level2, level3, orchestration, consolidation)
172
196
  * @param {string} tier - Capability tier (fast, balanced, thorough) or alias
173
197
  * @param {string} provider - Provider ID (default: 'claude')
174
198
  * @returns {Object|null} Prompt builder object or null if not available
@@ -99,6 +99,8 @@ class AIProvider {
99
99
  * Called with normalized events: { type: 'assistant_text'|'tool_use', text: string, timestamp: number }.
100
100
  * Providers that support streaming (Claude, Codex) will call this as data arrives.
101
101
  * Providers without streaming support silently ignore this option.
102
+ * @param {string} [options.logPrefix] - Custom log prefix to use instead of `[Level N]`.
103
+ * Used by council mode to disambiguate concurrent reviewers (e.g., `[L1 R1]`).
102
104
  * @returns {Promise<Object>} Parsed JSON response or { raw, parsed: false }
103
105
  */
104
106
  async execute(prompt, options = {}) {
@@ -195,8 +197,8 @@ class AIProvider {
195
197
  * @returns {Promise<{success: boolean, data?: Object, error?: string}>}
196
198
  */
197
199
  async extractJSONWithLLM(rawResponse, options = {}) {
198
- const { level = 'extraction', analysisId, registerProcess } = options;
199
- const levelPrefix = `[Level ${level}]`;
200
+ const { level = 'extraction', analysisId, registerProcess, logPrefix } = options;
201
+ const levelPrefix = logPrefix || `[Level ${level}]`;
200
202
 
201
203
  // Get the fast-tier model, with fallback to analysis model
202
204
  const extractionModel = this.getFastTierModel();