@in-the-loop-labs/pair-review 3.0.6 → 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 +113 -29
- 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 +152 -15
- 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
package/public/js/local.js
CHANGED
|
@@ -73,7 +73,15 @@ class LocalManager {
|
|
|
73
73
|
const autoAnalyze = new URLSearchParams(window.location.search).get('analyze');
|
|
74
74
|
if (autoAnalyze === 'true' && !window.prManager.isAnalyzing) {
|
|
75
75
|
try {
|
|
76
|
-
|
|
76
|
+
// Fetch repo settings so we honour the repository's default provider/council
|
|
77
|
+
const manager = window.prManager;
|
|
78
|
+
const [repoSettings, reviewSettings] = await Promise.all([
|
|
79
|
+
manager.fetchRepoSettings().catch(() => null),
|
|
80
|
+
manager.fetchLastReviewSettings().catch(() => ({ custom_instructions: '', last_council_id: null }))
|
|
81
|
+
]);
|
|
82
|
+
const config = await manager._buildDefaultAnalysisConfig(repoSettings, reviewSettings);
|
|
83
|
+
|
|
84
|
+
await this.startLocalAnalysis(null, config);
|
|
77
85
|
} finally {
|
|
78
86
|
const cleanUrl = new URL(window.location);
|
|
79
87
|
cleanUrl.searchParams.delete('analyze');
|
|
@@ -260,10 +268,11 @@ class LocalManager {
|
|
|
260
268
|
? manager._stalenessPromise
|
|
261
269
|
: self._fetchLocalStaleness();
|
|
262
270
|
manager._stalenessPromise = null; // consume it
|
|
263
|
-
const [staleResult, repoSettings, reviewSettings] = await Promise.all([
|
|
271
|
+
const [staleResult, repoSettings, reviewSettings, appConfig] = await Promise.all([
|
|
264
272
|
staleCheckWithTimeout,
|
|
265
273
|
manager.fetchRepoSettings().catch(() => null),
|
|
266
|
-
manager.fetchLastReviewSettings().catch(() => ({ custom_instructions: '', last_council_id: null }))
|
|
274
|
+
manager.fetchLastReviewSettings().catch(() => ({ custom_instructions: '', last_council_id: null })),
|
|
275
|
+
fetch('/api/config').then(r => r.ok ? r.json() : {}).catch(() => ({}))
|
|
267
276
|
]);
|
|
268
277
|
console.debug(`[Analyze] parallel-fetch (stale+settings): ${Math.round(performance.now() - _tParallel0)}ms`);
|
|
269
278
|
|
|
@@ -329,7 +338,9 @@ class LocalManager {
|
|
|
329
338
|
repoInstructions: repoSettings?.default_instructions || '',
|
|
330
339
|
lastInstructions: lastInstructions,
|
|
331
340
|
lastCouncilId,
|
|
332
|
-
defaultCouncilId: repoSettings?.default_council_id || null
|
|
341
|
+
defaultCouncilId: repoSettings?.default_council_id || null,
|
|
342
|
+
hasPr: false,
|
|
343
|
+
hasGithubToken: Boolean(appConfig.has_github_token)
|
|
333
344
|
});
|
|
334
345
|
|
|
335
346
|
if (!config) {
|
|
@@ -376,7 +387,8 @@ class LocalManager {
|
|
|
376
387
|
null,
|
|
377
388
|
{
|
|
378
389
|
configType: data.status?.isCouncil ? (data.status.configType || 'advanced') : 'single',
|
|
379
|
-
enabledLevels: data.status?.enabledLevels || [1, 2, 3]
|
|
390
|
+
enabledLevels: data.status?.enabledLevels || [1, 2, 3],
|
|
391
|
+
noLevels: data.status?.noLevels || false
|
|
380
392
|
}
|
|
381
393
|
);
|
|
382
394
|
}
|
|
@@ -480,6 +492,60 @@ class LocalManager {
|
|
|
480
492
|
});
|
|
481
493
|
};
|
|
482
494
|
|
|
495
|
+
// Base branch override for stack-aware diff in local mode
|
|
496
|
+
manager.currentBaseOverride = null;
|
|
497
|
+
|
|
498
|
+
// Render the base branch selector dropdown for stacked branches.
|
|
499
|
+
// When a local review has stack_data with 3+ entries, the user can pick
|
|
500
|
+
// which ancestor branch to diff against.
|
|
501
|
+
// Render the base branch selector when a Graphite stack has multiple ancestors.
|
|
502
|
+
// When shown, the selector replaces the static base branch text in the toolbar.
|
|
503
|
+
manager.renderBaseBranchSelector = function(pr) {
|
|
504
|
+
const selectorWrap = document.getElementById('base-branch-selector-wrap');
|
|
505
|
+
const sel = document.getElementById('base-branch-select');
|
|
506
|
+
const staticBase = document.getElementById('toolbar-base-branch-static');
|
|
507
|
+
if (!selectorWrap || !sel) return;
|
|
508
|
+
|
|
509
|
+
// Hide selector if no stack data or fewer than 3 entries (need at least 2 ancestors to switch between)
|
|
510
|
+
if (!pr.stack_data || pr.stack_data.length < 3) {
|
|
511
|
+
selectorWrap.setAttribute('hidden', '');
|
|
512
|
+
if (staticBase) staticBase.removeAttribute('hidden');
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Ancestors = all stack entries except the last (current branch)
|
|
517
|
+
const ancestors = pr.stack_data.slice(0, -1);
|
|
518
|
+
|
|
519
|
+
// Build options using createElement for XSS safety
|
|
520
|
+
sel.innerHTML = '';
|
|
521
|
+
for (const entry of ancestors) {
|
|
522
|
+
const option = document.createElement('option');
|
|
523
|
+
option.value = entry.branch;
|
|
524
|
+
option.textContent = entry.prNumber ? `${entry.branch} (#${entry.prNumber})` : entry.branch;
|
|
525
|
+
if (entry.branch === pr.base_branch) {
|
|
526
|
+
option.selected = true;
|
|
527
|
+
}
|
|
528
|
+
sel.appendChild(option);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// Show selector, hide static text
|
|
532
|
+
selectorWrap.removeAttribute('hidden');
|
|
533
|
+
if (staticBase) staticBase.setAttribute('hidden', '');
|
|
534
|
+
|
|
535
|
+
// Wire up change listener (idempotent via data-listener-added pattern)
|
|
536
|
+
if (!sel.hasAttribute('data-listener-added')) {
|
|
537
|
+
sel.setAttribute('data-listener-added', 'true');
|
|
538
|
+
sel.addEventListener('change', async () => {
|
|
539
|
+
manager.currentBaseOverride = sel.value;
|
|
540
|
+
// If selection matches the original base, clear the override
|
|
541
|
+
if (sel.value === manager.currentPR.base_branch) {
|
|
542
|
+
manager.currentBaseOverride = null;
|
|
543
|
+
}
|
|
544
|
+
await self.loadLocalDiff();
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
|
|
483
549
|
console.log('PRManager patched for local mode');
|
|
484
550
|
}
|
|
485
551
|
|
|
@@ -509,7 +575,8 @@ class LocalManager {
|
|
|
509
575
|
councilId: config.councilId || undefined,
|
|
510
576
|
councilConfig: config.councilConfig || undefined,
|
|
511
577
|
configType: config.configType || 'advanced',
|
|
512
|
-
customInstructions: config.customInstructions || null
|
|
578
|
+
customInstructions: config.customInstructions || null,
|
|
579
|
+
excludePrevious: config.excludePrevious || undefined
|
|
513
580
|
};
|
|
514
581
|
} else {
|
|
515
582
|
analyzeUrl = `/api/local/${this.reviewId}/analyses`;
|
|
@@ -519,7 +586,8 @@ class LocalManager {
|
|
|
519
586
|
tier: config.tier || 'balanced',
|
|
520
587
|
customInstructions: config.customInstructions || null,
|
|
521
588
|
enabledLevels: config.enabledLevels || [1, 2, 3],
|
|
522
|
-
skipLevel3: config.skipLevel3 || false
|
|
589
|
+
skipLevel3: config.skipLevel3 || false,
|
|
590
|
+
excludePrevious: config.excludePrevious || undefined
|
|
523
591
|
};
|
|
524
592
|
}
|
|
525
593
|
|
|
@@ -556,7 +624,8 @@ class LocalManager {
|
|
|
556
624
|
config.isCouncil ? config.councilName : null,
|
|
557
625
|
{
|
|
558
626
|
configType: config.isCouncil ? (config.configType || 'advanced') : 'single',
|
|
559
|
-
enabledLevels: config.enabledLevels || [1, 2, 3]
|
|
627
|
+
enabledLevels: config.enabledLevels || [1, 2, 3],
|
|
628
|
+
noLevels: config.noLevels || false
|
|
560
629
|
}
|
|
561
630
|
);
|
|
562
631
|
}
|
|
@@ -647,7 +716,7 @@ class LocalManager {
|
|
|
647
716
|
try {
|
|
648
717
|
// Show loading state
|
|
649
718
|
refreshBtn.disabled = true;
|
|
650
|
-
refreshBtn.classList.add('
|
|
719
|
+
refreshBtn.classList.add('refreshing');
|
|
651
720
|
|
|
652
721
|
const response = await fetch(`/api/local/${this.reviewId}/refresh`, {
|
|
653
722
|
method: 'POST'
|
|
@@ -698,7 +767,7 @@ class LocalManager {
|
|
|
698
767
|
// Reset button state
|
|
699
768
|
if (refreshBtn) {
|
|
700
769
|
refreshBtn.disabled = false;
|
|
701
|
-
refreshBtn.classList.remove('
|
|
770
|
+
refreshBtn.classList.remove('refreshing');
|
|
702
771
|
}
|
|
703
772
|
}
|
|
704
773
|
}
|
|
@@ -799,6 +868,13 @@ class LocalManager {
|
|
|
799
868
|
);
|
|
800
869
|
}
|
|
801
870
|
|
|
871
|
+
// Reset base branch override before reloading diff so the fetch uses the default base
|
|
872
|
+
manager.currentBaseOverride = null;
|
|
873
|
+
const baseSel = document.getElementById('base-branch-select');
|
|
874
|
+
if (baseSel && manager.currentPR?.base_branch) {
|
|
875
|
+
baseSel.value = manager.currentPR.base_branch;
|
|
876
|
+
}
|
|
877
|
+
|
|
802
878
|
// Reload the diff display
|
|
803
879
|
await this.loadLocalDiff();
|
|
804
880
|
|
|
@@ -947,7 +1023,8 @@ class LocalManager {
|
|
|
947
1023
|
head_sha: reviewData.localHeadSha,
|
|
948
1024
|
shaAbbrevLength: reviewData.shaAbbrevLength || 7,
|
|
949
1025
|
reviewType: 'local',
|
|
950
|
-
localPath: reviewData.localPath
|
|
1026
|
+
localPath: reviewData.localPath,
|
|
1027
|
+
stack_data: reviewData.stackData || null
|
|
951
1028
|
};
|
|
952
1029
|
|
|
953
1030
|
// Re-initialize DiffOptionsDropdown with scope options
|
|
@@ -1131,33 +1208,61 @@ class LocalManager {
|
|
|
1131
1208
|
pathText.title = fullPath;
|
|
1132
1209
|
}
|
|
1133
1210
|
|
|
1134
|
-
// Update branch name
|
|
1211
|
+
// Update branch name in header badge
|
|
1135
1212
|
const branchText = document.getElementById('local-branch-text');
|
|
1136
1213
|
if (branchText) {
|
|
1137
1214
|
branchText.textContent = reviewData.branch || 'unknown';
|
|
1138
1215
|
}
|
|
1139
1216
|
|
|
1217
|
+
// Wire up header branch copy button
|
|
1218
|
+
const branchCopy = document.getElementById('local-branch-copy');
|
|
1219
|
+
if (branchCopy && !branchCopy.hasAttribute('data-listener-added')) {
|
|
1220
|
+
branchCopy.setAttribute('data-listener-added', 'true');
|
|
1221
|
+
branchCopy.addEventListener('click', async (e) => {
|
|
1222
|
+
e.stopPropagation();
|
|
1223
|
+
const branch = branchText ? branchText.textContent : '';
|
|
1224
|
+
if (!branch || branch === '--' || branch === 'unknown') return;
|
|
1225
|
+
try {
|
|
1226
|
+
await navigator.clipboard.writeText(branch);
|
|
1227
|
+
branchCopy.classList.add('copied');
|
|
1228
|
+
setTimeout(() => branchCopy.classList.remove('copied'), 2000);
|
|
1229
|
+
} catch (err) {
|
|
1230
|
+
console.error('Failed to copy branch name:', err);
|
|
1231
|
+
}
|
|
1232
|
+
});
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1140
1235
|
// Set descriptive tab title
|
|
1141
1236
|
if (window.tabTitle && reviewData.branch) {
|
|
1142
1237
|
window.tabTitle.setBase(reviewData.branch);
|
|
1143
1238
|
}
|
|
1144
1239
|
|
|
1145
|
-
// Show base branch
|
|
1240
|
+
// Show base branch in toolbar when branch is in scope
|
|
1146
1241
|
const LS = window.LocalScope;
|
|
1147
1242
|
const scopeStart = this.scopeStart || (LS ? LS.DEFAULT_SCOPE.start : 'unstaged');
|
|
1148
1243
|
const scopeEnd = this.scopeEnd || (LS ? LS.DEFAULT_SCOPE.end : 'untracked');
|
|
1149
1244
|
const hasBranch = LS ? LS.scopeIncludes(scopeStart, scopeEnd, 'branch') : false;
|
|
1150
1245
|
|
|
1246
|
+
// Toolbar base branch display (static text, selector is wired separately)
|
|
1247
|
+
const toolbarBaseWrap = document.getElementById('toolbar-base-branch-wrap');
|
|
1248
|
+
const toolbarBaseStatic = document.getElementById('toolbar-base-branch-static');
|
|
1249
|
+
const toolbarBaseText = document.getElementById('toolbar-base-branch-text');
|
|
1250
|
+
if (hasBranch && reviewData.baseBranch) {
|
|
1251
|
+
if (toolbarBaseText) toolbarBaseText.textContent = reviewData.baseBranch;
|
|
1252
|
+
if (toolbarBaseWrap) toolbarBaseWrap.removeAttribute('hidden');
|
|
1253
|
+
} else {
|
|
1254
|
+
if (toolbarBaseWrap) toolbarBaseWrap.setAttribute('hidden', '');
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
// Hide header branch display — toolbar now shows branch info
|
|
1151
1258
|
const branchVs = document.getElementById('local-branch-vs');
|
|
1152
1259
|
const baseBranchEl = document.getElementById('local-base-branch');
|
|
1153
1260
|
const baseBranchText = document.getElementById('local-base-branch-text');
|
|
1154
|
-
if (
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
if (branchVs) branchVs.style.display = 'none';
|
|
1160
|
-
if (baseBranchEl) baseBranchEl.style.display = 'none';
|
|
1261
|
+
if (branchVs) branchVs.style.display = 'none';
|
|
1262
|
+
if (baseBranchEl) baseBranchEl.style.display = 'none';
|
|
1263
|
+
// Keep baseBranchText updated for data purposes even though header is hidden
|
|
1264
|
+
if (baseBranchText && reviewData.baseBranch) {
|
|
1265
|
+
baseBranchText.textContent = reviewData.baseBranch;
|
|
1161
1266
|
}
|
|
1162
1267
|
|
|
1163
1268
|
// Update refresh button tooltip based on scope
|
|
@@ -1167,29 +1272,6 @@ class LocalManager {
|
|
|
1167
1272
|
refreshBtn.title = `Refresh diff (${scopeLabel})`;
|
|
1168
1273
|
}
|
|
1169
1274
|
|
|
1170
|
-
// Update branch name (toolbar) and wire up copy button
|
|
1171
|
-
const branchName = document.getElementById('pr-branch-name');
|
|
1172
|
-
if (branchName) {
|
|
1173
|
-
branchName.textContent = reviewData.branch || 'unknown';
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
const branchCopy = document.getElementById('pr-branch-copy');
|
|
1177
|
-
if (branchCopy && !branchCopy.hasAttribute('data-listener-added')) {
|
|
1178
|
-
branchCopy.setAttribute('data-listener-added', 'true');
|
|
1179
|
-
branchCopy.addEventListener('click', async (e) => {
|
|
1180
|
-
e.stopPropagation();
|
|
1181
|
-
const branch = branchName ? branchName.textContent : '';
|
|
1182
|
-
if (!branch || branch === '--' || branch === 'unknown') return;
|
|
1183
|
-
try {
|
|
1184
|
-
await navigator.clipboard.writeText(branch);
|
|
1185
|
-
branchCopy.classList.add('copied');
|
|
1186
|
-
setTimeout(() => branchCopy.classList.remove('copied'), 2000);
|
|
1187
|
-
} catch (err) {
|
|
1188
|
-
console.error('Failed to copy branch name:', err);
|
|
1189
|
-
}
|
|
1190
|
-
});
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
1275
|
// Update commit SHA and wire up copy button
|
|
1194
1276
|
const commitSha = document.getElementById('pr-commit-sha');
|
|
1195
1277
|
if (commitSha && reviewData.localHeadSha) {
|
|
@@ -1255,6 +1337,12 @@ class LocalManager {
|
|
|
1255
1337
|
settingsLink.style.display = 'none';
|
|
1256
1338
|
}
|
|
1257
1339
|
}
|
|
1340
|
+
|
|
1341
|
+
// Render base branch selector for stacked branches
|
|
1342
|
+
const manager = window.prManager;
|
|
1343
|
+
if (manager?.renderBaseBranchSelector) {
|
|
1344
|
+
manager.renderBaseBranchSelector(manager.currentPR);
|
|
1345
|
+
}
|
|
1258
1346
|
}
|
|
1259
1347
|
|
|
1260
1348
|
/**
|
|
@@ -1301,10 +1389,11 @@ class LocalManager {
|
|
|
1301
1389
|
const manager = window.prManager;
|
|
1302
1390
|
|
|
1303
1391
|
try {
|
|
1304
|
-
|
|
1305
|
-
if (manager.hideWhitespace)
|
|
1306
|
-
|
|
1307
|
-
|
|
1392
|
+
const params = new URLSearchParams();
|
|
1393
|
+
if (manager.hideWhitespace) params.set('w', '1');
|
|
1394
|
+
if (manager.currentBaseOverride) params.set('base', manager.currentBaseOverride);
|
|
1395
|
+
const queryString = params.toString();
|
|
1396
|
+
const diffUrl = `/api/local/${this.reviewId}/diff${queryString ? '?' + queryString : ''}`;
|
|
1308
1397
|
const response = await fetch(diffUrl);
|
|
1309
1398
|
|
|
1310
1399
|
if (!response.ok) {
|
|
@@ -1475,6 +1564,11 @@ class LocalManager {
|
|
|
1475
1564
|
: `Local Changes - ${manager.currentPR.head_branch}`;
|
|
1476
1565
|
}
|
|
1477
1566
|
|
|
1567
|
+
// Reset base branch override on scope change (base branch context may differ)
|
|
1568
|
+
if (manager) {
|
|
1569
|
+
manager.currentBaseOverride = null;
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1478
1572
|
// Update header and reload diff
|
|
1479
1573
|
this.updateLocalHeader(this.localData);
|
|
1480
1574
|
await this.loadLocalDiff();
|
|
@@ -482,6 +482,7 @@ class SuggestionManager {
|
|
|
482
482
|
${suggestion.type === 'praise'
|
|
483
483
|
? `<span class="praise-badge" title="Nice Work"><svg viewBox="0 0 16 16"><path d="M8 .25a.75.75 0 01.673.418l1.882 3.815 4.21.612a.75.75 0 01.416 1.279l-3.046 2.97.719 4.192a.75.75 0 01-1.088.791L8 12.347l-3.766 1.98a.75.75 0 01-1.088-.79l.72-4.194L.818 6.374a.75.75 0 01.416-1.28l4.21-.611L7.327.668A.75.75 0 018 .25z"/></svg>Nice Work</span>`
|
|
484
484
|
: `<span class="ai-suggestion-badge" data-type="${suggestion.type}" title="${this.getTypeDescription(suggestion.type)}"><svg viewBox="0 0 16 16" fill="currentColor" width="12" height="12"><path d="M9.6 2.279a.426.426 0 0 1 .8 0l.407 1.112a6.386 6.386 0 0 0 3.802 3.802l1.112.407a.426.426 0 0 1 0 .8l-1.112.407a6.386 6.386 0 0 0-3.802 3.802l-.407 1.112a.426.426 0 0 1-.8 0l-.407-1.112a6.386 6.386 0 0 0-3.802-3.802L4.279 8.4a.426.426 0 0 1 0-.8l1.112-.407a6.386 6.386 0 0 0 3.802-3.802L9.6 2.279Zm-4.267 8.837a.178.178 0 0 1 .334 0l.169.464a2.662 2.662 0 0 0 1.584 1.584l.464.169a.178.178 0 0 1 0 .334l-.464.169a2.662 2.662 0 0 0-1.584 1.584l-.169.464a.178.178 0 0 1-.334 0l-.169-.464a2.662 2.662 0 0 0-1.584-1.584l-.464-.169a.178.178 0 0 1 0-.334l.464-.169a2.662 2.662 0 0 0 1.584-1.584l.169-.464ZM2.8.14a.213.213 0 0 1 .4 0l.203.556a3.2 3.2 0 0 0 1.901 1.901l.556.203a.213.213 0 0 1 0 .4l-.556.203a3.2 3.2 0 0 0-1.901 1.901L3.2 5.86a.213.213 0 0 1-.4 0l-.203-.556A3.2 3.2 0 0 0 .696 3.403L.14 3.2a.213.213 0 0 1 0-.4l.556-.203A3.2 3.2 0 0 0 2.597.696L2.8.14Z"/></svg>AI Suggestion</span>`}
|
|
485
|
+
${suggestion.severity ? `<span class="severity-badge severity-${suggestion.severity}">${escapeHtml(suggestion.severity.toUpperCase())}</span>` : ''}
|
|
485
486
|
${categoryLabel ? `<span class="ai-suggestion-category">${escapeHtml(categoryLabel)}</span>` : ''}
|
|
486
487
|
<span class="ai-title">${escapeHtml(suggestion.title || '')}</span>
|
|
487
488
|
</div>
|
|
@@ -497,7 +498,7 @@ class SuggestionManager {
|
|
|
497
498
|
${suggestion.type === 'praise'
|
|
498
499
|
? `<span class="praise-badge" title="Nice Work"><svg viewBox="0 0 16 16"><path d="M8 .25a.75.75 0 01.673.418l1.882 3.815 4.21.612a.75.75 0 01.416 1.279l-3.046 2.97.719 4.192a.75.75 0 01-1.088.791L8 12.347l-3.766 1.98a.75.75 0 01-1.088-.79l.72-4.194L.818 6.374a.75.75 0 01.416-1.28l4.21-.611L7.327.668A.75.75 0 018 .25z"/></svg>Nice Work</span>`
|
|
499
500
|
: `<span class="ai-suggestion-badge collapsed" data-type="${suggestion.type}" title="${this.getTypeDescription(suggestion.type)}"><svg viewBox="0 0 16 16" fill="currentColor" width="10" height="10"><path d="M9.6 2.279a.426.426 0 0 1 .8 0l.407 1.112a6.386 6.386 0 0 0 3.802 3.802l1.112.407a.426.426 0 0 1 0 .8l-1.112.407a6.386 6.386 0 0 0-3.802 3.802l-.407 1.112a.426.426 0 0 1-.8 0l-.407-1.112a6.386 6.386 0 0 0-3.802-3.802L4.279 8.4a.426.426 0 0 1 0-.8l1.112-.407a6.386 6.386 0 0 0 3.802-3.802L9.6 2.279Zm-4.267 8.837a.178.178 0 0 1 .334 0l.169.464a2.662 2.662 0 0 0 1.584 1.584l.464.169a.178.178 0 0 1 0 .334l-.464.169a2.662 2.662 0 0 0-1.584 1.584l-.169.464a.178.178 0 0 1-.334 0l-.169-.464a2.662 2.662 0 0 0-1.584-1.584l-.464-.169a.178.178 0 0 1 0-.334l.464-.169a2.662 2.662 0 0 0 1.584-1.584l.169-.464ZM2.8.14a.213.213 0 0 1 .4 0l.203.556a3.2 3.2 0 0 0 1.901 1.901l.556.203a.213.213 0 0 1 0 .4l-.556.203a3.2 3.2 0 0 0-1.901 1.901L3.2 5.86a.213.213 0 0 1-.4 0l-.203-.556A3.2 3.2 0 0 0 .696 3.403L.14 3.2a.213.213 0 0 1 0-.4l.556-.203A3.2 3.2 0 0 0 2.597.696L2.8.14Z"/></svg>AI Suggestion</span>`}
|
|
500
|
-
|
|
501
|
+
${suggestion.severity ? `<span class="severity-badge severity-${suggestion.severity}">${escapeHtml(suggestion.severity.toUpperCase())}</span>` : ''}
|
|
501
502
|
<span class="collapsed-title">${escapeHtml(suggestion.title || '')}</span>
|
|
502
503
|
<div class="ai-suggestion-header-right">
|
|
503
504
|
${suggestion.reasoning && suggestion.reasoning.length > 0 ? `
|
package/public/js/pr.js
CHANGED
|
@@ -398,6 +398,51 @@ class PRManager {
|
|
|
398
398
|
}
|
|
399
399
|
}
|
|
400
400
|
|
|
401
|
+
/**
|
|
402
|
+
* Build analysis config from repo defaults (no modal interaction).
|
|
403
|
+
* Used by auto-analyze (--ai) to honour the repository's default provider/council.
|
|
404
|
+
* When the default is a council, fetches the council config from the server so the
|
|
405
|
+
* progress modal can render the voice/level layout.
|
|
406
|
+
* @param {Object|null} repoSettings - Repo settings from fetchRepoSettings()
|
|
407
|
+
* @param {Object} reviewSettings - Review settings from fetchLastReviewSettings()
|
|
408
|
+
* @returns {Promise<Object>} Config object suitable for startAnalysis / startLocalAnalysis
|
|
409
|
+
*/
|
|
410
|
+
async _buildDefaultAnalysisConfig(repoSettings, reviewSettings) {
|
|
411
|
+
const defaultTab = repoSettings?.default_tab || 'single';
|
|
412
|
+
const councilId = repoSettings?.default_council_id || reviewSettings?.last_council_id || null;
|
|
413
|
+
|
|
414
|
+
if ((defaultTab === 'council' || defaultTab === 'advanced') && councilId) {
|
|
415
|
+
// Fetch the full council config so the progress modal can render correctly
|
|
416
|
+
let councilConfig = null;
|
|
417
|
+
let councilName = null;
|
|
418
|
+
try {
|
|
419
|
+
const resp = await fetch(`/api/councils/${councilId}`);
|
|
420
|
+
if (resp.ok) {
|
|
421
|
+
const data = await resp.json();
|
|
422
|
+
councilConfig = data.council?.config || null;
|
|
423
|
+
councilName = data.council?.name || null;
|
|
424
|
+
}
|
|
425
|
+
} catch (e) {
|
|
426
|
+
console.warn('Failed to fetch council config for auto-analyze:', e);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return {
|
|
430
|
+
isCouncil: true,
|
|
431
|
+
councilId,
|
|
432
|
+
councilConfig,
|
|
433
|
+
councilName,
|
|
434
|
+
configType: defaultTab,
|
|
435
|
+
customInstructions: null
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
return {
|
|
440
|
+
provider: repoSettings?.default_provider || 'claude',
|
|
441
|
+
model: repoSettings?.default_model || 'opus',
|
|
442
|
+
customInstructions: null
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
401
446
|
/**
|
|
402
447
|
* Auto-trigger analysis if ?analyze=true is present in the URL.
|
|
403
448
|
* Skips refresh if data was just loaded fresh by loadPR (to avoid redundant fetches).
|
|
@@ -428,7 +473,14 @@ class PRManager {
|
|
|
428
473
|
}
|
|
429
474
|
}
|
|
430
475
|
|
|
431
|
-
|
|
476
|
+
// Fetch repo settings so we honour the repository's default provider/council
|
|
477
|
+
const [repoSettings, reviewSettings] = await Promise.all([
|
|
478
|
+
this.fetchRepoSettings().catch(() => null),
|
|
479
|
+
this.fetchLastReviewSettings().catch(() => ({ custom_instructions: '', last_council_id: null }))
|
|
480
|
+
]);
|
|
481
|
+
const config = await this._buildDefaultAnalysisConfig(repoSettings, reviewSettings);
|
|
482
|
+
|
|
483
|
+
await this.startAnalysis(owner, repo, prNumber, null, config);
|
|
432
484
|
} finally {
|
|
433
485
|
this._autoAnalyzeRequested = false;
|
|
434
486
|
const cleanUrl = new URL(window.location);
|
|
@@ -667,10 +719,9 @@ class PRManager {
|
|
|
667
719
|
*/
|
|
668
720
|
async loadAndDisplayFiles(owner, repo, number) {
|
|
669
721
|
try {
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
}
|
|
722
|
+
const diffUrl = this.hideWhitespace
|
|
723
|
+
? `/api/pr/${owner}/${repo}/${number}/diff?w=1`
|
|
724
|
+
: `/api/pr/${owner}/${repo}/${number}/diff`;
|
|
674
725
|
const response = await fetch(diffUrl);
|
|
675
726
|
|
|
676
727
|
if (response.ok) {
|
|
@@ -4112,7 +4163,8 @@ class PRManager {
|
|
|
4112
4163
|
null,
|
|
4113
4164
|
{
|
|
4114
4165
|
configType: data.status?.isCouncil ? (data.status.configType || 'advanced') : 'single',
|
|
4115
|
-
enabledLevels: data.status?.enabledLevels || [1, 2, 3]
|
|
4166
|
+
enabledLevels: data.status?.enabledLevels || [1, 2, 3],
|
|
4167
|
+
noLevels: data.status?.noLevels || false
|
|
4116
4168
|
}
|
|
4117
4169
|
);
|
|
4118
4170
|
}
|
|
@@ -4223,10 +4275,11 @@ class PRManager {
|
|
|
4223
4275
|
: this._fetchStaleness(owner, repo, number);
|
|
4224
4276
|
this._stalenessPromise = null; // consume it
|
|
4225
4277
|
|
|
4226
|
-
const [staleResult, repoSettings, reviewSettings] = await Promise.all([
|
|
4278
|
+
const [staleResult, repoSettings, reviewSettings, appConfig] = await Promise.all([
|
|
4227
4279
|
staleCheckWithTimeout,
|
|
4228
4280
|
this.fetchRepoSettings(),
|
|
4229
|
-
this.fetchLastReviewSettings()
|
|
4281
|
+
this.fetchLastReviewSettings(),
|
|
4282
|
+
fetch('/api/config').then(r => r.ok ? r.json() : {}).catch(() => ({}))
|
|
4230
4283
|
]);
|
|
4231
4284
|
console.debug(`[Analyze] parallel-fetch (stale+settings): ${Math.round(performance.now() - _tParallel0)}ms`);
|
|
4232
4285
|
|
|
@@ -4300,7 +4353,9 @@ class PRManager {
|
|
|
4300
4353
|
repoInstructions: repoSettings?.default_instructions || '',
|
|
4301
4354
|
lastInstructions: lastInstructions,
|
|
4302
4355
|
lastCouncilId,
|
|
4303
|
-
defaultCouncilId: repoSettings?.default_council_id || null
|
|
4356
|
+
defaultCouncilId: repoSettings?.default_council_id || null,
|
|
4357
|
+
hasPr: true,
|
|
4358
|
+
hasGithubToken: Boolean(appConfig.has_github_token)
|
|
4304
4359
|
});
|
|
4305
4360
|
|
|
4306
4361
|
// If user cancelled, do nothing
|
|
@@ -4368,7 +4423,8 @@ class PRManager {
|
|
|
4368
4423
|
councilId: config.councilId || undefined,
|
|
4369
4424
|
councilConfig: config.councilConfig || undefined,
|
|
4370
4425
|
configType: config.configType || 'advanced',
|
|
4371
|
-
customInstructions: config.customInstructions || null
|
|
4426
|
+
customInstructions: config.customInstructions || null,
|
|
4427
|
+
excludePrevious: config.excludePrevious || undefined
|
|
4372
4428
|
};
|
|
4373
4429
|
} else {
|
|
4374
4430
|
analyzeUrl = `/api/pr/${owner}/${repo}/${number}/analyses`;
|
|
@@ -4378,7 +4434,8 @@ class PRManager {
|
|
|
4378
4434
|
tier: config.tier || 'balanced',
|
|
4379
4435
|
customInstructions: config.customInstructions || null,
|
|
4380
4436
|
enabledLevels: config.enabledLevels || [1, 2, 3],
|
|
4381
|
-
skipLevel3: config.skipLevel3 || false
|
|
4437
|
+
skipLevel3: config.skipLevel3 || false,
|
|
4438
|
+
excludePrevious: config.excludePrevious || undefined
|
|
4382
4439
|
};
|
|
4383
4440
|
}
|
|
4384
4441
|
|
|
@@ -4419,7 +4476,8 @@ class PRManager {
|
|
|
4419
4476
|
config.isCouncil ? config.councilName : null,
|
|
4420
4477
|
{
|
|
4421
4478
|
configType: config.isCouncil ? (config.configType || 'advanced') : 'single',
|
|
4422
|
-
enabledLevels: config.enabledLevels || [1, 2, 3]
|
|
4479
|
+
enabledLevels: config.enabledLevels || [1, 2, 3],
|
|
4480
|
+
noLevels: config.noLevels || false
|
|
4423
4481
|
}
|
|
4424
4482
|
);
|
|
4425
4483
|
}
|
|
@@ -4669,6 +4727,7 @@ class PRManager {
|
|
|
4669
4727
|
|
|
4670
4728
|
this._hideStaleBadge();
|
|
4671
4729
|
this._stalenessPromise = null;
|
|
4730
|
+
|
|
4672
4731
|
console.log('PR refreshed successfully');
|
|
4673
4732
|
}
|
|
4674
4733
|
} catch (error) {
|
|
@@ -635,12 +635,12 @@ class RepoSettingsPage {
|
|
|
635
635
|
return;
|
|
636
636
|
}
|
|
637
637
|
|
|
638
|
-
const
|
|
638
|
+
const modelIcon = model.icon || (window.getTierIcon ? window.getTierIcon(model.tier) : '');
|
|
639
639
|
|
|
640
640
|
container.innerHTML = `
|
|
641
641
|
<div class="model-card selected settings-model-card-static" data-tier="${this.escapeHtml(model.tier || '')}">
|
|
642
642
|
<div class="model-badge ${this.escapeHtml(model.badgeClass || '')}">${this.escapeHtml(model.badge || '')}</div>
|
|
643
|
-
<div class="model-icon">${
|
|
643
|
+
<div class="model-icon">${modelIcon}</div>
|
|
644
644
|
<div class="model-info">
|
|
645
645
|
<span class="model-name">${this.escapeHtml(model.name)}</span>
|
|
646
646
|
<span class="model-tagline">${this.escapeHtml(model.tagline || '')}</span>
|
package/public/local.html
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
window.__pairReview.chatProvider = config.chat_provider || 'pi';
|
|
21
21
|
window.__pairReview.chatProviders = chatProviders;
|
|
22
22
|
window.__pairReview.chatSpinner = config.chat_spinner || 'dots';
|
|
23
|
+
window.__pairReview.chatEnterToSend = config.chat_enter_to_send !== false;
|
|
23
24
|
document.documentElement.setAttribute('data-chat', state);
|
|
24
25
|
const shortcutsState = config.chat_enable_shortcuts === false ? 'disabled' : 'enabled';
|
|
25
26
|
document.documentElement.setAttribute('data-chat-shortcuts', shortcutsState);
|
|
@@ -40,6 +41,7 @@
|
|
|
40
41
|
<!-- PR Display Styles -->
|
|
41
42
|
<link rel="stylesheet" href="/css/pr.css">
|
|
42
43
|
<link rel="stylesheet" href="/css/ai-summary-modal.css">
|
|
44
|
+
<link rel="stylesheet" href="/css/analysis-config.css">
|
|
43
45
|
<link rel="stylesheet" href="/css/styles.css">
|
|
44
46
|
|
|
45
47
|
<!-- Highlight.js for syntax highlighting -->
|
|
@@ -128,6 +130,14 @@
|
|
|
128
130
|
text-overflow: ellipsis;
|
|
129
131
|
}
|
|
130
132
|
|
|
133
|
+
.local-branch-badge .toolbar-copy-btn {
|
|
134
|
+
opacity: 0;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.local-branch-badge:hover .toolbar-copy-btn {
|
|
138
|
+
opacity: 1;
|
|
139
|
+
}
|
|
140
|
+
|
|
131
141
|
.local-branch-vs {
|
|
132
142
|
flex-shrink: 0;
|
|
133
143
|
}
|
|
@@ -288,6 +298,12 @@
|
|
|
288
298
|
<path d="M11.75 2.5a.75.75 0 100 1.5.75.75 0 000-1.5zm-2.25.75a2.25 2.25 0 113 2.122V6A2.5 2.5 0 0110 8.5H6a1 1 0 00-1 1v1.128a2.251 2.251 0 11-1.5 0V5.372a2.25 2.25 0 111.5 0v1.836A2.492 2.492 0 016 7h4a1 1 0 001-1v-.628A2.25 2.25 0 019.5 3.25zM4.25 12a.75.75 0 100 1.5.75.75 0 000-1.5zM3.5 3.25a.75.75 0 111.5 0 .75.75 0 01-1.5 0z"/>
|
|
289
299
|
</svg>
|
|
290
300
|
<span id="local-branch-text">--</span>
|
|
301
|
+
<button type="button" class="local-branch-copy toolbar-copy-btn" id="local-branch-copy" title="Copy branch name" aria-label="Copy branch name">
|
|
302
|
+
<svg viewBox="0 0 16 16" fill="currentColor" width="10" height="10">
|
|
303
|
+
<path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path>
|
|
304
|
+
<path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path>
|
|
305
|
+
</svg>
|
|
306
|
+
</button>
|
|
291
307
|
</span>
|
|
292
308
|
<span class="local-branch-vs" id="local-branch-vs" style="display: none; font-size: 11px; color: var(--color-text-tertiary); margin: 0 4px;">vs</span>
|
|
293
309
|
<span class="local-branch-badge" id="local-base-branch" style="display: none;">
|
|
@@ -309,9 +325,13 @@
|
|
|
309
325
|
<div class="header-right">
|
|
310
326
|
<div class="header-icon-group">
|
|
311
327
|
<button class="btn btn-icon" id="local-refresh-btn" title="Refresh diff from directory">
|
|
312
|
-
<svg viewBox="0 0 16 16" fill="currentColor" width="16" height="16">
|
|
328
|
+
<svg class="refresh-icon" viewBox="0 0 16 16" fill="currentColor" width="16" height="16">
|
|
313
329
|
<path d="M1.705 8.005a.75.75 0 0 1 .834.656 5.5 5.5 0 0 0 9.592 2.97l-1.204-1.204a.25.25 0 0 1 .177-.427h3.646a.25.25 0 0 1 .25.25v3.646a.25.25 0 0 1-.427.177l-1.38-1.38A7.002 7.002 0 0 1 1.05 8.84a.75.75 0 0 1 .656-.834ZM8 2.5a5.487 5.487 0 0 0-4.131 1.869l1.204 1.204A.25.25 0 0 1 4.896 6H1.25A.25.25 0 0 1 1 5.75V2.104a.25.25 0 0 1 .427-.177l1.38 1.38A7.002 7.002 0 0 1 14.95 7.16a.75.75 0 1 1-1.49.178A5.5 5.5 0 0 0 8 2.5Z"/>
|
|
314
330
|
</svg>
|
|
331
|
+
<svg class="spinner-icon" viewBox="0 0 16 16" fill="currentColor" width="16" height="16">
|
|
332
|
+
<path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z" opacity="0.25"/>
|
|
333
|
+
<path d="M8 0a8 8 0 0 1 8 8h-2A6 6 0 0 0 8 2V0Z"/>
|
|
334
|
+
</svg>
|
|
315
335
|
</button>
|
|
316
336
|
<button class="btn btn-icon" id="theme-toggle" title="Toggle theme">
|
|
317
337
|
<svg class="theme-icon-light" viewBox="0 0 16 16" fill="currentColor" width="16" height="16">
|
|
@@ -362,17 +382,18 @@
|
|
|
362
382
|
</svg>
|
|
363
383
|
</button>
|
|
364
384
|
<div class="toolbar-meta" id="toolbar-meta">
|
|
365
|
-
<span
|
|
366
|
-
<
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
<button type="button" class="toolbar-branch-copy toolbar-copy-btn" id="pr-branch-copy" title="Copy branch name" aria-label="Copy branch name">
|
|
371
|
-
<svg viewBox="0 0 16 16" fill="currentColor" width="10" height="10">
|
|
372
|
-
<path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path>
|
|
373
|
-
<path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path>
|
|
385
|
+
<span id="toolbar-base-branch-wrap" class="toolbar-base-branch-wrap" hidden>
|
|
386
|
+
<span class="base-branch-vs">base:</span>
|
|
387
|
+
<span id="toolbar-base-branch-static" class="toolbar-base-branch-static">
|
|
388
|
+
<svg viewBox="0 0 16 16" fill="currentColor" width="12" height="12">
|
|
389
|
+
<path d="M11.75 2.5a.75.75 0 100 1.5.75.75 0 000-1.5zm-2.25.75a2.25 2.25 0 113 2.122V6A2.5 2.5 0 0110 8.5H6a1 1 0 00-1 1v1.128a2.251 2.251 0 11-1.5 0V5.372a2.25 2.25 0 111.5 0v1.836A2.492 2.492 0 016 7h4a1 1 0 001-1v-.628A2.25 2.25 0 019.5 3.25zM4.25 12a.75.75 0 100 1.5.75.75 0 000-1.5zM3.5 3.25a.75.75 0 111.5 0 .75.75 0 01-1.5 0z"/>
|
|
374
390
|
</svg>
|
|
375
|
-
|
|
391
|
+
<span id="toolbar-base-branch-text"></span>
|
|
392
|
+
</span>
|
|
393
|
+
<span id="base-branch-selector-wrap" class="base-branch-selector-wrap" hidden>
|
|
394
|
+
<label for="base-branch-select" class="sr-only">Compare against</label>
|
|
395
|
+
<select id="base-branch-select" class="base-branch-select" title="Change base branch for diff"></select>
|
|
396
|
+
</span>
|
|
376
397
|
</span>
|
|
377
398
|
<span class="toolbar-separator"></span>
|
|
378
399
|
<span class="toolbar-stat toolbar-stat-additions" id="pr-additions">+0</span>
|
package/public/pr.html
CHANGED
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
window.__pairReview.share = config.share || null;
|
|
29
29
|
window.__pairReview.enableGraphite = config.enable_graphite === true;
|
|
30
30
|
window.__pairReview.chatSpinner = config.chat_spinner || 'dots';
|
|
31
|
+
window.__pairReview.chatEnterToSend = config.chat_enter_to_send !== false;
|
|
31
32
|
document.documentElement.setAttribute('data-chat', state);
|
|
32
33
|
const shortcutsState = config.chat_enable_shortcuts === false ? 'disabled' : 'enabled';
|
|
33
34
|
document.documentElement.setAttribute('data-chat-shortcuts', shortcutsState);
|
|
@@ -48,6 +49,7 @@
|
|
|
48
49
|
<!-- PR Display Styles -->
|
|
49
50
|
<link rel="stylesheet" href="/css/pr.css">
|
|
50
51
|
<link rel="stylesheet" href="/css/ai-summary-modal.css">
|
|
52
|
+
<link rel="stylesheet" href="/css/analysis-config.css">
|
|
51
53
|
<link rel="stylesheet" href="/css/styles.css">
|
|
52
54
|
|
|
53
55
|
<!-- Highlight.js for syntax highlighting -->
|