@in-the-loop-labs/pair-review 1.6.2 → 2.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.
- package/README.md +77 -4
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/skills/review-requests/SKILL.md +4 -1
- package/plugin-code-critic/.claude-plugin/plugin.json +1 -1
- package/plugin-code-critic/skills/analyze/SKILL.md +4 -3
- package/public/css/pr.css +1962 -114
- package/public/js/CONVENTIONS.md +16 -0
- package/public/js/components/AIPanel.js +66 -0
- package/public/js/components/AnalysisConfigModal.js +2 -2
- package/public/js/components/ChatPanel.js +2955 -0
- package/public/js/components/CouncilProgressModal.js +12 -16
- package/public/js/components/KeyboardShortcuts.js +3 -0
- package/public/js/components/PanelGroup.js +723 -0
- package/public/js/components/PreviewModal.js +3 -8
- package/public/js/index.js +8 -0
- package/public/js/local.js +17 -615
- package/public/js/modules/analysis-history.js +19 -68
- package/public/js/modules/comment-manager.js +103 -20
- package/public/js/modules/diff-context.js +176 -0
- package/public/js/modules/diff-renderer.js +30 -0
- package/public/js/modules/file-comment-manager.js +126 -105
- package/public/js/modules/file-list-merger.js +64 -0
- package/public/js/modules/panel-resizer.js +25 -6
- package/public/js/modules/suggestion-manager.js +40 -125
- package/public/js/pr.js +1009 -159
- package/public/js/repo-settings.js +36 -6
- package/public/js/utils/category-emoji.js +44 -0
- package/public/js/utils/time.js +32 -0
- package/public/local.html +107 -70
- package/public/pr.html +107 -70
- package/public/repo-settings.html +32 -0
- package/src/ai/analyzer.js +5 -1
- package/src/ai/copilot-provider.js +39 -9
- package/src/ai/cursor-agent-provider.js +45 -11
- package/src/ai/gemini-provider.js +17 -4
- package/src/ai/prompts/config.js +7 -1
- package/src/ai/provider-availability.js +1 -1
- package/src/ai/provider.js +25 -37
- package/src/chat/CONVENTIONS.md +18 -0
- package/src/chat/pi-bridge.js +491 -0
- package/src/chat/prompt-builder.js +272 -0
- package/src/chat/session-manager.js +619 -0
- package/src/config.js +14 -0
- package/src/database.js +322 -15
- package/src/main.js +4 -17
- package/src/routes/analyses.js +721 -0
- package/src/routes/chat.js +655 -0
- package/src/routes/config.js +29 -8
- package/src/routes/context-files.js +274 -0
- package/src/routes/local.js +225 -1133
- package/src/routes/mcp.js +39 -30
- package/src/routes/pr.js +424 -58
- package/src/routes/reviews.js +1035 -0
- package/src/routes/shared.js +4 -29
- package/src/server.js +34 -12
- package/src/sse/review-events.js +46 -0
- package/src/utils/auto-context.js +88 -0
- package/src/utils/category-emoji.js +33 -0
- package/src/utils/diff-annotator.js +75 -1
- package/src/utils/diff-file-list.js +57 -0
- package/src/routes/analysis.js +0 -1600
- package/src/routes/comments.js +0 -534
package/public/pr.html
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
-
<html lang="en" data-theme="light">
|
|
2
|
+
<html lang="en" data-theme="light" data-chat="disabled">
|
|
3
3
|
<head>
|
|
4
4
|
<script>
|
|
5
5
|
// Initialize theme immediately to prevent flash
|
|
@@ -7,6 +7,16 @@
|
|
|
7
7
|
const savedTheme = localStorage.getItem('theme') || 'light';
|
|
8
8
|
document.documentElement.setAttribute('data-theme', savedTheme);
|
|
9
9
|
})();
|
|
10
|
+
// Fetch chat availability early so PanelGroup sees the correct state
|
|
11
|
+
fetch('/api/config').then(r => r.ok ? r.json() : null).then(config => {
|
|
12
|
+
if (!config) return;
|
|
13
|
+
let state = 'disabled';
|
|
14
|
+
if (config.enable_chat) state = config.pi_available ? 'available' : 'unavailable';
|
|
15
|
+
document.documentElement.setAttribute('data-chat', state);
|
|
16
|
+
const shortcutsState = config.chat_enable_shortcuts === false ? 'disabled' : 'enabled';
|
|
17
|
+
document.documentElement.setAttribute('data-chat-shortcuts', shortcutsState);
|
|
18
|
+
window.dispatchEvent(new CustomEvent('chat-state-changed', { detail: { state } }));
|
|
19
|
+
}).catch(() => {});
|
|
10
20
|
</script>
|
|
11
21
|
<meta charset="UTF-8">
|
|
12
22
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
@@ -116,7 +126,7 @@
|
|
|
116
126
|
<!-- File Tree Sidebar (Left) -->
|
|
117
127
|
<aside class="sidebar files-sidebar" id="files-sidebar">
|
|
118
128
|
<div class="sidebar-header">
|
|
119
|
-
<span class="sidebar-title">
|
|
129
|
+
<span class="sidebar-title">File Navigator</span>
|
|
120
130
|
<div style="display: flex; align-items: center; gap: 8px;">
|
|
121
131
|
<span class="sidebar-count" id="sidebar-file-count">0</span>
|
|
122
132
|
<button class="sidebar-collapse-btn" id="sidebar-collapse-btn" title="Close panel">
|
|
@@ -187,10 +197,19 @@
|
|
|
187
197
|
</svg>
|
|
188
198
|
<span class="btn-text">Analyze</span>
|
|
189
199
|
</button>
|
|
190
|
-
<button class="btn btn-sm btn-icon" id="
|
|
200
|
+
<button class="btn btn-sm btn-icon" id="chat-toggle-btn" title="Toggle Chat panel">
|
|
201
|
+
<svg class="chat-icon" viewBox="0 0 16 16" fill="currentColor" width="14" height="14">
|
|
202
|
+
<path d="M1.75 1h8.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 10.25 10H7.061l-2.574 2.573A1.458 1.458 0 0 1 2 11.543V10h-.25A1.75 1.75 0 0 1 0 8.25v-5.5C0 1.784.784 1 1.75 1ZM1.5 2.75v5.5c0 .138.112.25.25.25h1a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h3.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25Zm13 2a.25.25 0 0 0-.25-.25h-.5a.75.75 0 0 1 0-1.5h.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 14.25 12H14v1.543a1.458 1.458 0 0 1-2.487 1.03L9.22 12.28a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l2.22 2.22v-2.19a.75.75 0 0 1 .75-.75h1a.25.25 0 0 0 .25-.25Z"/>
|
|
203
|
+
</svg>
|
|
204
|
+
</button>
|
|
205
|
+
<button class="btn btn-sm btn-icon" id="panel-layout-toggle" title="Switch panel layout" style="display: none;">
|
|
191
206
|
<svg viewBox="0 0 16 16" fill="currentColor" width="14" height="14">
|
|
192
|
-
<path d="
|
|
193
|
-
|
|
207
|
+
<path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25ZM1.5 1.75v12.5c0 .138.112.25.25.25H7.5v-13H1.75a.25.25 0 0 0-.25.25ZM8.5 14.5h5.75a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25H8.5Z"/>
|
|
208
|
+
</svg>
|
|
209
|
+
</button>
|
|
210
|
+
<button class="btn btn-sm btn-icon" id="ai-panel-toggle" title="Toggle Review panel">
|
|
211
|
+
<svg viewBox="0 0 16 16" width="16" height="16" fill="currentColor">
|
|
212
|
+
<path d="M2 2h4a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1Zm4.655 8.595a.75.75 0 0 1 0 1.06L4.03 14.28a.75.75 0 0 1-1.06 0l-1.5-1.5a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l.97.97 2.095-2.095a.75.75 0 0 1 1.06 0ZM9.75 2.5h5.5a.75.75 0 0 1 0 1.5h-5.5a.75.75 0 0 1 0-1.5Zm0 5h5.5a.75.75 0 0 1 0 1.5h-5.5a.75.75 0 0 1 0-1.5Zm0 5h5.5a.75.75 0 0 1 0 1.5h-5.5a.75.75 0 0 1 0-1.5Zm-7.25-9v3h3v-3Z"/>
|
|
194
213
|
</svg>
|
|
195
214
|
</button>
|
|
196
215
|
</div>
|
|
@@ -200,86 +219,90 @@
|
|
|
200
219
|
</div>
|
|
201
220
|
</main>
|
|
202
221
|
|
|
203
|
-
<!-- AI
|
|
204
|
-
<
|
|
205
|
-
|
|
206
|
-
<
|
|
207
|
-
<div class="ai-panel
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
<
|
|
222
|
+
<!-- Right Panel Group (AI Panel + Chat) -->
|
|
223
|
+
<div class="right-panel-group" id="right-panel-group">
|
|
224
|
+
<!-- AI Analysis Panel (Right) -->
|
|
225
|
+
<aside class="ai-panel" id="ai-panel">
|
|
226
|
+
<div class="resize-handle resize-handle-left" data-panel="ai-panel"></div>
|
|
227
|
+
<div class="ai-panel-header">
|
|
228
|
+
<div class="ai-panel-title">
|
|
229
|
+
<button class="ai-avatar-small ai-summary-btn" id="ai-summary-btn" aria-label="View AI summary" title="View AI Summary">
|
|
230
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" width="14" height="14">
|
|
231
|
+
<path d="M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z"/>
|
|
232
|
+
<path d="M18.259 8.715L18 9.75l-.259-1.035a3.375 3.375 0 00-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 002.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 002.456 2.456L21.75 6l-1.035.259a3.375 3.375 0 00-2.456 2.456z"/>
|
|
233
|
+
</svg>
|
|
234
|
+
</button>
|
|
235
|
+
<span>Review</span>
|
|
236
|
+
</div>
|
|
237
|
+
<button class="ai-panel-close" id="ai-panel-close" title="Close panel">
|
|
238
|
+
<svg viewBox="0 0 16 16" fill="currentColor" width="14" height="14">
|
|
239
|
+
<path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.75.75 0 1 1 1.06 1.06L9.06 8l3.22 3.22a.75.75 0 1 1-1.06 1.06L8 9.06l-3.22 3.22a.75.75 0 0 1-1.06-1.06L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"/>
|
|
212
240
|
</svg>
|
|
213
241
|
</button>
|
|
214
|
-
<span>Review</span>
|
|
215
242
|
</div>
|
|
216
|
-
<button class="ai-panel-close" id="ai-panel-close" title="Close panel">
|
|
217
|
-
<svg viewBox="0 0 16 16" fill="currentColor" width="14" height="14">
|
|
218
|
-
<path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.75.75 0 1 1 1.06 1.06L9.06 8l3.22 3.22a.75.75 0 1 1-1.06 1.06L8 9.06l-3.22 3.22a.75.75 0 0 1-1.06-1.06L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"/>
|
|
219
|
-
</svg>
|
|
220
|
-
</button>
|
|
221
|
-
</div>
|
|
222
243
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
</svg>
|
|
230
|
-
<span>No AI analysis yet</span>
|
|
231
|
-
</div>
|
|
232
|
-
|
|
233
|
-
<!-- Selector (hidden until analysis exists) -->
|
|
234
|
-
<div class="analysis-context-selector" id="analysis-context-selector" style="display: none;">
|
|
235
|
-
<button class="analysis-context-btn" id="analysis-context-btn">
|
|
236
|
-
<span class="analysis-context-label" id="analysis-context-label">--</span>
|
|
237
|
-
<svg class="dropdown-caret" width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
|
|
238
|
-
<path d="M2.5 4.5L6 8L9.5 4.5" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
|
244
|
+
<!-- Analysis Context Section -->
|
|
245
|
+
<div class="analysis-context" id="analysis-context">
|
|
246
|
+
<!-- Empty state -->
|
|
247
|
+
<div class="analysis-context-empty" id="analysis-context-empty">
|
|
248
|
+
<svg class="analysis-context-empty-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
249
|
+
<path d="M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z"/>
|
|
239
250
|
</svg>
|
|
240
|
-
|
|
241
|
-
|
|
251
|
+
<span>No AI analysis yet</span>
|
|
252
|
+
</div>
|
|
242
253
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
254
|
+
<!-- Selector (hidden until analysis exists) -->
|
|
255
|
+
<div class="analysis-context-selector" id="analysis-context-selector" style="display: none;">
|
|
256
|
+
<button class="analysis-context-btn" id="analysis-context-btn">
|
|
257
|
+
<span class="analysis-context-label" id="analysis-context-label">--</span>
|
|
258
|
+
<svg class="dropdown-caret" width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
|
|
259
|
+
<path d="M2.5 4.5L6 8L9.5 4.5" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
|
260
|
+
</svg>
|
|
261
|
+
</button>
|
|
247
262
|
</div>
|
|
248
|
-
|
|
249
|
-
|
|
263
|
+
|
|
264
|
+
<!-- Split-panel dropdown (hidden by default) -->
|
|
265
|
+
<div class="analysis-context-dropdown" id="analysis-context-dropdown">
|
|
266
|
+
<div class="analysis-run-list" id="analysis-context-list">
|
|
267
|
+
<!-- Populated by JavaScript -->
|
|
268
|
+
</div>
|
|
269
|
+
<div class="analysis-preview-panel" id="analysis-context-preview">
|
|
270
|
+
<!-- Populated by JavaScript on hover -->
|
|
271
|
+
</div>
|
|
250
272
|
</div>
|
|
251
273
|
</div>
|
|
252
|
-
</div>
|
|
253
274
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
275
|
+
<!-- Segment Control -->
|
|
276
|
+
<div class="segment-control" id="segment-control">
|
|
277
|
+
<div class="segment-control-inner">
|
|
278
|
+
<button class="segment-btn active" data-segment="ai">AI <span class="segment-count">(0)</span></button>
|
|
279
|
+
<button class="segment-btn" data-segment="comments">User <span class="segment-count">(0)</span></button>
|
|
280
|
+
<button class="segment-btn" data-segment="all">All <span class="segment-count">(0)</span></button>
|
|
281
|
+
</div>
|
|
260
282
|
</div>
|
|
261
|
-
</div>
|
|
262
|
-
|
|
263
|
-
<!-- Level Filter -->
|
|
264
|
-
<div class="level-filter" id="level-filter">
|
|
265
|
-
<button class="level-pill active" data-level="final" title="Curated suggestions from all levels">Overall</button>
|
|
266
|
-
<button class="level-pill" data-level="1" title="Line-level analysis">Line</button>
|
|
267
|
-
<button class="level-pill" data-level="2" title="File-level analysis">File</button>
|
|
268
|
-
<button class="level-pill" data-level="3" title="Codebase-level analysis">Codebase</button>
|
|
269
|
-
</div>
|
|
270
283
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
<
|
|
284
|
+
<!-- Level Filter -->
|
|
285
|
+
<div class="level-filter" id="level-filter">
|
|
286
|
+
<button class="level-pill active" data-level="final" title="Curated suggestions from all levels">Overall</button>
|
|
287
|
+
<button class="level-pill" data-level="1" title="Line-level analysis">Line</button>
|
|
288
|
+
<button class="level-pill" data-level="2" title="File-level analysis">File</button>
|
|
289
|
+
<button class="level-pill" data-level="3" title="Codebase-level analysis">Codebase</button>
|
|
275
290
|
</div>
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
291
|
+
|
|
292
|
+
<!-- Findings Summary -->
|
|
293
|
+
<div class="findings-summary" id="findings-summary">
|
|
294
|
+
<div class="findings-header">
|
|
295
|
+
<span class="findings-count" id="findings-count">0 items</span>
|
|
296
|
+
</div>
|
|
297
|
+
<div class="findings-list" id="findings-list">
|
|
298
|
+
<div class="findings-empty">
|
|
299
|
+
<p>No AI analysis yet. Click "Analyze" to get started.</p>
|
|
300
|
+
</div>
|
|
279
301
|
</div>
|
|
280
302
|
</div>
|
|
281
|
-
</
|
|
282
|
-
|
|
303
|
+
</aside>
|
|
304
|
+
<div id="chat-panel-container"></div>
|
|
305
|
+
</div>
|
|
283
306
|
</div>
|
|
284
307
|
</div>
|
|
285
308
|
|
|
@@ -299,12 +322,18 @@
|
|
|
299
322
|
<!-- Tier icons utility -->
|
|
300
323
|
<script src="/js/utils/tier-icons.js"></script>
|
|
301
324
|
|
|
325
|
+
<!-- Category emoji mapping -->
|
|
326
|
+
<script src="/js/utils/category-emoji.js"></script>
|
|
327
|
+
|
|
302
328
|
<!-- Suggestion UI utility -->
|
|
303
329
|
<script src="/js/utils/suggestion-ui.js"></script>
|
|
304
330
|
|
|
305
331
|
<!-- File order utility -->
|
|
306
332
|
<script src="/js/utils/file-order.js"></script>
|
|
307
333
|
|
|
334
|
+
<!-- Timestamp parsing utility -->
|
|
335
|
+
<script src="/js/utils/time.js"></script>
|
|
336
|
+
|
|
308
337
|
<!-- Components -->
|
|
309
338
|
<script src="/js/components/Toast.js"></script>
|
|
310
339
|
<script src="/js/components/ConfirmDialog.js"></script>
|
|
@@ -335,6 +364,14 @@
|
|
|
335
364
|
<script src="/js/modules/file-comment-manager.js"></script>
|
|
336
365
|
<script src="/js/modules/panel-resizer.js"></script>
|
|
337
366
|
<script src="/js/modules/analysis-history.js"></script>
|
|
367
|
+
<script src="/js/modules/diff-context.js"></script>
|
|
368
|
+
<script src="/js/modules/file-list-merger.js"></script>
|
|
369
|
+
|
|
370
|
+
<!-- Chat Panel Component -->
|
|
371
|
+
<script src="/js/components/ChatPanel.js"></script>
|
|
372
|
+
|
|
373
|
+
<!-- Panel Group Component -->
|
|
374
|
+
<script src="/js/components/PanelGroup.js"></script>
|
|
338
375
|
|
|
339
376
|
<!-- PR JavaScript -->
|
|
340
377
|
<script src="/js/pr.js"></script>
|
|
@@ -166,6 +166,38 @@ Examples:
|
|
|
166
166
|
</div>
|
|
167
167
|
</section>
|
|
168
168
|
|
|
169
|
+
<!-- Chat Instructions Section -->
|
|
170
|
+
<section class="settings-section">
|
|
171
|
+
<div class="section-header">
|
|
172
|
+
<h2>
|
|
173
|
+
Chat Instructions
|
|
174
|
+
</h2>
|
|
175
|
+
<p class="section-description">
|
|
176
|
+
These instructions will be appended to the system prompt when starting chat sessions for this repository.
|
|
177
|
+
Use this for guiding the chat assistant's behavior, tone, or focus areas.
|
|
178
|
+
</p>
|
|
179
|
+
</div>
|
|
180
|
+
<div class="instructions-wrapper">
|
|
181
|
+
<textarea
|
|
182
|
+
id="chat-instructions"
|
|
183
|
+
name="default_chat_instructions"
|
|
184
|
+
class="instructions-textarea"
|
|
185
|
+
placeholder="Enter instructions for chat sessions...
|
|
186
|
+
|
|
187
|
+
Examples:
|
|
188
|
+
• Always reference the project's coding standards when answering
|
|
189
|
+
• Focus on explaining the reasoning behind suggestions
|
|
190
|
+
• When discussing tests, prefer integration tests over unit tests
|
|
191
|
+
• Use concise responses unless asked for detail"
|
|
192
|
+
rows="6"
|
|
193
|
+
></textarea>
|
|
194
|
+
<div class="textarea-footer">
|
|
195
|
+
<span class="char-count"><span id="chat-char-count">0</span> characters</span>
|
|
196
|
+
<span class="textarea-hint">Markdown supported</span>
|
|
197
|
+
</div>
|
|
198
|
+
</div>
|
|
199
|
+
</section>
|
|
200
|
+
|
|
169
201
|
<!-- Repository Location Section -->
|
|
170
202
|
<section class="settings-section" id="local-path-section">
|
|
171
203
|
<div class="section-header">
|
package/src/ai/analyzer.js
CHANGED
|
@@ -17,6 +17,7 @@ const {
|
|
|
17
17
|
buildAnalysisLineNumberGuidance,
|
|
18
18
|
buildOrchestrationLineNumberGuidance: buildOrchestrationGuidance,
|
|
19
19
|
} = require('./prompts/line-number-guidance');
|
|
20
|
+
const { resolveTier } = require('./prompts/config');
|
|
20
21
|
const { registerProcess, isAnalysisCancelled, CancellationError } = require('../routes/shared');
|
|
21
22
|
const { AnalysisRunRepository, CommentRepository } = require('../database');
|
|
22
23
|
const { mergeInstructions } = require('../utils/instructions');
|
|
@@ -175,6 +176,7 @@ class Analyzer {
|
|
|
175
176
|
reviewId: prId, // prId is actually review.id (works for both PR and local modes)
|
|
176
177
|
provider: this.provider,
|
|
177
178
|
model: this.model,
|
|
179
|
+
tier: options.tier ? resolveTier(options.tier) : 'balanced',
|
|
178
180
|
customInstructions: mergedInstructions, // Keep for backward compat
|
|
179
181
|
repoInstructions,
|
|
180
182
|
requestInstructions,
|
|
@@ -212,7 +214,7 @@ class Analyzer {
|
|
|
212
214
|
if (mergedInstructions) {
|
|
213
215
|
logger.info(`${logPrefix}Custom instructions provided: ${mergedInstructions.length} chars`);
|
|
214
216
|
}
|
|
215
|
-
const tier = options.tier
|
|
217
|
+
const tier = options.tier ? resolveTier(options.tier) : 'balanced';
|
|
216
218
|
|
|
217
219
|
// Build the promises array for each level based on enabledLevels
|
|
218
220
|
const levelAnalyzers = [
|
|
@@ -2664,6 +2666,7 @@ File-level suggestions should NOT have a line number. They apply to the entire f
|
|
|
2664
2666
|
reviewId,
|
|
2665
2667
|
provider: 'council',
|
|
2666
2668
|
model: 'voice-centric',
|
|
2669
|
+
tier: null,
|
|
2667
2670
|
customInstructions: mergedInstructions,
|
|
2668
2671
|
repoInstructions: instructions?.repoInstructions || null,
|
|
2669
2672
|
requestInstructions: instructions?.requestInstructions || null,
|
|
@@ -2760,6 +2763,7 @@ File-level suggestions should NOT have a line number. They apply to the entire f
|
|
|
2760
2763
|
reviewId,
|
|
2761
2764
|
provider: voice.provider,
|
|
2762
2765
|
model: voice.model,
|
|
2766
|
+
tier: voiceTier,
|
|
2763
2767
|
customInstructions: mergedInstructions,
|
|
2764
2768
|
repoInstructions: instructions?.repoInstructions || null,
|
|
2765
2769
|
requestInstructions: instructions?.requestInstructions || null,
|
|
@@ -21,9 +21,10 @@ const BIN_DIR = path.join(__dirname, '..', '..', 'bin');
|
|
|
21
21
|
*
|
|
22
22
|
* GitHub Copilot CLI supports multiple AI models including OpenAI,
|
|
23
23
|
* Anthropic, and Google models via the --model flag.
|
|
24
|
-
* Available models (as of Feb 2026): claude-haiku-4.5, claude-sonnet-4.
|
|
25
|
-
* gemini-3-pro-preview, gpt-5.2-codex,
|
|
26
|
-
* claude-opus-4.6
|
|
24
|
+
* Available models (as of Feb 2026): claude-haiku-4.5, claude-sonnet-4.6,
|
|
25
|
+
* claude-sonnet-4.5, gemini-3-pro-preview, gpt-5.2-codex, gpt-5.3-codex,
|
|
26
|
+
* claude-opus-4.5, claude-opus-4.6, claude-opus-4.6-fast.
|
|
27
|
+
* Default is claude-sonnet-4.6.
|
|
27
28
|
*/
|
|
28
29
|
const COPILOT_MODELS = [
|
|
29
30
|
{
|
|
@@ -36,15 +37,24 @@ const COPILOT_MODELS = [
|
|
|
36
37
|
badgeClass: 'badge-speed'
|
|
37
38
|
},
|
|
38
39
|
{
|
|
39
|
-
id: 'claude-sonnet-4.
|
|
40
|
-
name: 'Claude Sonnet 4.
|
|
40
|
+
id: 'claude-sonnet-4.6',
|
|
41
|
+
name: 'Claude Sonnet 4.6',
|
|
41
42
|
tier: 'balanced',
|
|
42
|
-
tagline: '
|
|
43
|
-
description: '
|
|
43
|
+
tagline: 'Best Balance',
|
|
44
|
+
description: 'Latest Sonnet—excellent code understanding with fast turnaround',
|
|
44
45
|
badge: 'Recommended',
|
|
45
46
|
badgeClass: 'badge-recommended',
|
|
46
47
|
default: true
|
|
47
48
|
},
|
|
49
|
+
{
|
|
50
|
+
id: 'claude-sonnet-4.5',
|
|
51
|
+
name: 'Claude Sonnet 4.5',
|
|
52
|
+
tier: 'balanced',
|
|
53
|
+
tagline: 'Previous Gen',
|
|
54
|
+
description: 'Previous generation Sonnet—strong code understanding with excellent quality-to-cost ratio',
|
|
55
|
+
badge: 'Previous Gen',
|
|
56
|
+
badgeClass: 'badge-balanced'
|
|
57
|
+
},
|
|
48
58
|
{
|
|
49
59
|
id: 'gemini-3-pro-preview',
|
|
50
60
|
name: 'Gemini 3 Pro',
|
|
@@ -63,6 +73,15 @@ const COPILOT_MODELS = [
|
|
|
63
73
|
badge: 'Balanced',
|
|
64
74
|
badgeClass: 'badge-balanced'
|
|
65
75
|
},
|
|
76
|
+
{
|
|
77
|
+
id: 'gpt-5.3-codex',
|
|
78
|
+
name: 'GPT-5.3 Codex',
|
|
79
|
+
tier: 'thorough',
|
|
80
|
+
tagline: 'Deep Code Analysis',
|
|
81
|
+
description: 'Most capable OpenAI coding model—frontier performance for complex multi-file reviews',
|
|
82
|
+
badge: 'Thorough',
|
|
83
|
+
badgeClass: 'badge-power'
|
|
84
|
+
},
|
|
66
85
|
{
|
|
67
86
|
id: 'claude-opus-4.5',
|
|
68
87
|
name: 'Claude Opus 4.5',
|
|
@@ -80,9 +99,20 @@ const COPILOT_MODELS = [
|
|
|
80
99
|
description: 'Most capable model for critical code reviews—deep reasoning for security and architecture',
|
|
81
100
|
badge: 'Premium',
|
|
82
101
|
badgeClass: 'badge-premium'
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
id: 'claude-opus-4.6-fast',
|
|
105
|
+
name: 'Claude Opus 4.6 Fast',
|
|
106
|
+
tier: 'thorough',
|
|
107
|
+
tagline: 'Fast Opus',
|
|
108
|
+
description: 'Opus-level analysis at reduced latency—preview mode for faster deep reviews',
|
|
109
|
+
badge: 'Preview',
|
|
110
|
+
badgeClass: 'badge-premium'
|
|
83
111
|
}
|
|
84
112
|
];
|
|
85
113
|
|
|
114
|
+
const DEFAULT_COPILOT_MODEL = 'claude-sonnet-4.6';
|
|
115
|
+
|
|
86
116
|
class CopilotProvider extends AIProvider {
|
|
87
117
|
/**
|
|
88
118
|
* @param {string} model - Model identifier
|
|
@@ -92,7 +122,7 @@ class CopilotProvider extends AIProvider {
|
|
|
92
122
|
* @param {Object} configOverrides.env - Additional environment variables
|
|
93
123
|
* @param {Object[]} configOverrides.models - Custom model definitions
|
|
94
124
|
*/
|
|
95
|
-
constructor(model =
|
|
125
|
+
constructor(model = DEFAULT_COPILOT_MODEL, configOverrides = {}) {
|
|
96
126
|
super(model);
|
|
97
127
|
|
|
98
128
|
// Command precedence: ENV > config > default
|
|
@@ -462,7 +492,7 @@ class CopilotProvider extends AIProvider {
|
|
|
462
492
|
}
|
|
463
493
|
|
|
464
494
|
static getDefaultModel() {
|
|
465
|
-
return
|
|
495
|
+
return DEFAULT_COPILOT_MODEL;
|
|
466
496
|
}
|
|
467
497
|
|
|
468
498
|
static getInstallInstructions() {
|
|
@@ -31,8 +31,8 @@ const BIN_DIR = path.join(__dirname, '..', '..', 'bin');
|
|
|
31
31
|
* Tier structure:
|
|
32
32
|
* - free (auto): Cursor's default auto-routing model
|
|
33
33
|
* - fast (composer-1, gpt-5.3-codex-fast, gemini-3-flash): Quick analysis
|
|
34
|
-
* - balanced (composer-1.5, sonnet-4.5-thinking, gemini-3-pro): Recommended for most reviews
|
|
35
|
-
* - thorough (gpt-5.3-codex-high, opus-4.5-thinking, opus-4.6-thinking): Deep analysis for complex code
|
|
34
|
+
* - balanced (composer-1.5, sonnet-4.6-thinking, sonnet-4.5-thinking, gemini-3-pro, gemini-3.1-pro): Recommended for most reviews
|
|
35
|
+
* - thorough (gpt-5.3-codex-high, gpt-5.3-codex-xhigh, opus-4.5-thinking, opus-4.6-thinking): Deep analysis for complex code
|
|
36
36
|
*/
|
|
37
37
|
const CURSOR_AGENT_MODELS = [
|
|
38
38
|
{
|
|
@@ -81,15 +81,24 @@ const CURSOR_AGENT_MODELS = [
|
|
|
81
81
|
badgeClass: 'badge-speed'
|
|
82
82
|
},
|
|
83
83
|
{
|
|
84
|
-
id: 'sonnet-4.
|
|
85
|
-
name: 'Claude 4.
|
|
84
|
+
id: 'sonnet-4.6-thinking',
|
|
85
|
+
name: 'Claude 4.6 Sonnet (Thinking)',
|
|
86
86
|
tier: 'balanced',
|
|
87
87
|
tagline: 'Best Balance',
|
|
88
|
-
description: '
|
|
88
|
+
description: 'Latest Sonnet with extended thinking—excellent quality-to-cost ratio for thorough reviews',
|
|
89
89
|
badge: 'Recommended',
|
|
90
90
|
badgeClass: 'badge-recommended',
|
|
91
91
|
default: true
|
|
92
92
|
},
|
|
93
|
+
{
|
|
94
|
+
id: 'sonnet-4.5-thinking',
|
|
95
|
+
name: 'Claude 4.5 Sonnet (Thinking)',
|
|
96
|
+
tier: 'balanced',
|
|
97
|
+
tagline: 'Previous Gen',
|
|
98
|
+
description: 'Previous generation extended thinking—still strong for thorough analysis',
|
|
99
|
+
badge: 'Previous Gen',
|
|
100
|
+
badgeClass: 'badge-balanced'
|
|
101
|
+
},
|
|
93
102
|
{
|
|
94
103
|
id: 'gemini-3-pro',
|
|
95
104
|
name: 'Gemini 3 Pro',
|
|
@@ -99,6 +108,15 @@ const CURSOR_AGENT_MODELS = [
|
|
|
99
108
|
badge: 'Balanced',
|
|
100
109
|
badgeClass: 'badge-balanced'
|
|
101
110
|
},
|
|
111
|
+
{
|
|
112
|
+
id: 'gemini-3.1-pro',
|
|
113
|
+
name: 'Gemini 3.1 Pro',
|
|
114
|
+
tier: 'balanced',
|
|
115
|
+
tagline: 'Latest Gemini',
|
|
116
|
+
description: 'Newest Gemini model—cutting-edge reasoning for complex multi-file reviews',
|
|
117
|
+
badge: 'Latest',
|
|
118
|
+
badgeClass: 'badge-balanced'
|
|
119
|
+
},
|
|
102
120
|
{
|
|
103
121
|
id: 'gpt-5.3-codex-high',
|
|
104
122
|
name: 'GPT-5.3 Codex High',
|
|
@@ -108,6 +126,15 @@ const CURSOR_AGENT_MODELS = [
|
|
|
108
126
|
badge: 'Thorough',
|
|
109
127
|
badgeClass: 'badge-power'
|
|
110
128
|
},
|
|
129
|
+
{
|
|
130
|
+
id: 'gpt-5.3-codex-xhigh',
|
|
131
|
+
name: 'GPT-5.3 Codex Extra High',
|
|
132
|
+
tier: 'thorough',
|
|
133
|
+
tagline: 'Maximum Reasoning',
|
|
134
|
+
description: 'Highest reasoning effort for the most complex architectural reviews',
|
|
135
|
+
badge: 'Maximum',
|
|
136
|
+
badgeClass: 'badge-power'
|
|
137
|
+
},
|
|
111
138
|
{
|
|
112
139
|
id: 'opus-4.5-thinking',
|
|
113
140
|
name: 'Claude 4.5 Opus (Thinking)',
|
|
@@ -128,6 +155,8 @@ const CURSOR_AGENT_MODELS = [
|
|
|
128
155
|
}
|
|
129
156
|
];
|
|
130
157
|
|
|
158
|
+
const DEFAULT_CURSOR_AGENT_MODEL = 'sonnet-4.6-thinking';
|
|
159
|
+
|
|
131
160
|
class CursorAgentProvider extends AIProvider {
|
|
132
161
|
/**
|
|
133
162
|
* @param {string} model - Model identifier
|
|
@@ -136,8 +165,9 @@ class CursorAgentProvider extends AIProvider {
|
|
|
136
165
|
* @param {string[]} configOverrides.extra_args - Additional CLI arguments
|
|
137
166
|
* @param {Object} configOverrides.env - Additional environment variables
|
|
138
167
|
* @param {Object[]} configOverrides.models - Custom model definitions
|
|
168
|
+
* @param {boolean} configOverrides.yolo - When true, use --yolo instead of --trust/--sandbox
|
|
139
169
|
*/
|
|
140
|
-
constructor(model =
|
|
170
|
+
constructor(model = DEFAULT_CURSOR_AGENT_MODEL, configOverrides = {}) {
|
|
141
171
|
super(model);
|
|
142
172
|
|
|
143
173
|
// Command precedence: ENV > config > default
|
|
@@ -180,9 +210,12 @@ class CursorAgentProvider extends AIProvider {
|
|
|
180
210
|
// in parseCursorAgentResponse (isStreamingDelta / timestamp_ms check). If this
|
|
181
211
|
// flag is removed, the parser will treat all assistant events as complete messages,
|
|
182
212
|
// which is fine but will change accumulation behavior. Keep these in sync.
|
|
183
|
-
//
|
|
184
|
-
|
|
185
|
-
const
|
|
213
|
+
// Normal mode: --trust to auto-approve the working directory, --sandbox enabled for safety
|
|
214
|
+
// Yolo mode: --yolo to skip all permissions (implies trust + sandbox disabled)
|
|
215
|
+
const permissionArgs = configOverrides.yolo
|
|
216
|
+
? ['--yolo']
|
|
217
|
+
: ['--trust', '--sandbox', 'enabled'];
|
|
218
|
+
const baseArgs = ['-p', '--output-format', 'stream-json', '--stream-partial-output', '--model', model, ...permissionArgs];
|
|
186
219
|
const providerArgs = configOverrides.extra_args || [];
|
|
187
220
|
const modelConfig = configOverrides.models?.find(m => m.id === model);
|
|
188
221
|
const modelArgs = modelConfig?.extra_args || [];
|
|
@@ -671,7 +704,8 @@ class CursorAgentProvider extends AIProvider {
|
|
|
671
704
|
*/
|
|
672
705
|
buildArgsForModel(model) {
|
|
673
706
|
// Base args for extraction (text output, no tools needed)
|
|
674
|
-
|
|
707
|
+
// --trust needed to auto-approve the working directory without interactive prompt
|
|
708
|
+
const baseArgs = ['-p', '--output-format', 'text', '--trust', '--model', model];
|
|
675
709
|
// Provider-level extra_args (from configOverrides)
|
|
676
710
|
const providerArgs = this.configOverrides?.extra_args || [];
|
|
677
711
|
// Model-specific extra_args (from the model config for the given model)
|
|
@@ -790,7 +824,7 @@ class CursorAgentProvider extends AIProvider {
|
|
|
790
824
|
}
|
|
791
825
|
|
|
792
826
|
static getDefaultModel() {
|
|
793
|
-
return
|
|
827
|
+
return DEFAULT_CURSOR_AGENT_MODEL;
|
|
794
828
|
}
|
|
795
829
|
|
|
796
830
|
static getInstallInstructions() {
|
|
@@ -21,7 +21,8 @@ const BIN_DIR = path.join(__dirname, '..', '..', 'bin');
|
|
|
21
21
|
*/
|
|
22
22
|
const GEMINI_MODELS = [
|
|
23
23
|
{
|
|
24
|
-
id: 'gemini-3-flash
|
|
24
|
+
id: 'gemini-3-flash',
|
|
25
|
+
aliases: ['gemini-3-flash-preview'],
|
|
25
26
|
name: '3.0 Flash',
|
|
26
27
|
tier: 'fast',
|
|
27
28
|
tagline: 'Rapid Sanity Check',
|
|
@@ -40,16 +41,28 @@ const GEMINI_MODELS = [
|
|
|
40
41
|
default: true
|
|
41
42
|
},
|
|
42
43
|
{
|
|
43
|
-
id: 'gemini-3-pro
|
|
44
|
+
id: 'gemini-3-pro',
|
|
45
|
+
aliases: ['gemini-3-pro-preview'],
|
|
44
46
|
name: '3.0 Pro',
|
|
45
47
|
tier: 'thorough',
|
|
46
48
|
tagline: 'Architectural Audit',
|
|
47
49
|
description: 'Most intelligent Gemini model—advanced reasoning for deep architectural analysis',
|
|
48
50
|
badge: 'Deep Dive',
|
|
49
51
|
badgeClass: 'badge-power'
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: 'gemini-3.1-pro',
|
|
55
|
+
name: '3.1 Pro',
|
|
56
|
+
tier: 'thorough',
|
|
57
|
+
tagline: 'Latest & Greatest',
|
|
58
|
+
description: 'Newest Gemini model—cutting-edge reasoning for complex architectural reviews',
|
|
59
|
+
badge: 'Latest',
|
|
60
|
+
badgeClass: 'badge-power'
|
|
50
61
|
}
|
|
51
62
|
];
|
|
52
63
|
|
|
64
|
+
const DEFAULT_GEMINI_MODEL = 'gemini-2.5-pro';
|
|
65
|
+
|
|
53
66
|
class GeminiProvider extends AIProvider {
|
|
54
67
|
/**
|
|
55
68
|
* @param {string} model - Model identifier
|
|
@@ -59,7 +72,7 @@ class GeminiProvider extends AIProvider {
|
|
|
59
72
|
* @param {Object} configOverrides.env - Additional environment variables
|
|
60
73
|
* @param {Object[]} configOverrides.models - Custom model definitions
|
|
61
74
|
*/
|
|
62
|
-
constructor(model =
|
|
75
|
+
constructor(model = DEFAULT_GEMINI_MODEL, configOverrides = {}) {
|
|
63
76
|
super(model);
|
|
64
77
|
|
|
65
78
|
// Command precedence: ENV > config > default
|
|
@@ -690,7 +703,7 @@ class GeminiProvider extends AIProvider {
|
|
|
690
703
|
}
|
|
691
704
|
|
|
692
705
|
static getDefaultModel() {
|
|
693
|
-
return
|
|
706
|
+
return DEFAULT_GEMINI_MODEL;
|
|
694
707
|
}
|
|
695
708
|
|
|
696
709
|
static getInstallInstructions() {
|
package/src/ai/prompts/config.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Defines tier mappings for the prompt system.
|
|
6
6
|
* Note: Provider-specific model-to-tier mappings are defined in each provider's
|
|
7
|
-
* getModels() method.
|
|
7
|
+
* getModels() method. The tier is persisted on each analysis_runs record at creation time.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -21,6 +21,11 @@ const TIER_ALIASES = {
|
|
|
21
21
|
*/
|
|
22
22
|
const TIERS = ['fast', 'balanced', 'thorough'];
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* All accepted tier values (internal tiers + user-facing aliases)
|
|
26
|
+
*/
|
|
27
|
+
const VALID_TIERS = [...TIERS, ...Object.keys(TIER_ALIASES)];
|
|
28
|
+
|
|
24
29
|
/**
|
|
25
30
|
* Prompt types (analysis levels)
|
|
26
31
|
*/
|
|
@@ -44,6 +49,7 @@ function resolveTier(tierOrAlias) {
|
|
|
44
49
|
module.exports = {
|
|
45
50
|
TIER_ALIASES,
|
|
46
51
|
TIERS,
|
|
52
|
+
VALID_TIERS,
|
|
47
53
|
PROMPT_TYPES,
|
|
48
54
|
resolveTier
|
|
49
55
|
};
|