@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/css/pr.css
CHANGED
|
@@ -501,16 +501,19 @@
|
|
|
501
501
|
}
|
|
502
502
|
|
|
503
503
|
/* Refresh button spinner animation */
|
|
504
|
-
#refresh-pr .spinner-icon
|
|
504
|
+
#refresh-pr .spinner-icon,
|
|
505
|
+
#local-refresh-btn .spinner-icon {
|
|
505
506
|
display: none;
|
|
506
507
|
animation: spin 1s linear infinite;
|
|
507
508
|
}
|
|
508
509
|
|
|
509
|
-
#refresh-pr.refreshing .refresh-icon
|
|
510
|
+
#refresh-pr.refreshing .refresh-icon,
|
|
511
|
+
#local-refresh-btn.refreshing .refresh-icon {
|
|
510
512
|
display: none !important;
|
|
511
513
|
}
|
|
512
514
|
|
|
513
|
-
#refresh-pr.refreshing .spinner-icon
|
|
515
|
+
#refresh-pr.refreshing .spinner-icon,
|
|
516
|
+
#local-refresh-btn.refreshing .spinner-icon {
|
|
514
517
|
display: inline-block !important;
|
|
515
518
|
}
|
|
516
519
|
|
|
@@ -1871,6 +1874,8 @@ tr.newly-expanded .d2h-code-line-ctn {
|
|
|
1871
1874
|
display: flex;
|
|
1872
1875
|
align-items: center;
|
|
1873
1876
|
gap: 8px;
|
|
1877
|
+
min-width: 0;
|
|
1878
|
+
overflow: hidden;
|
|
1874
1879
|
}
|
|
1875
1880
|
|
|
1876
1881
|
/* Category label badge for AI suggestions - HIDDEN in favor of unified AI Suggestion badge (issue pair_review-pqb) */
|
|
@@ -1889,11 +1894,16 @@ tr.newly-expanded .d2h-code-line-ctn {
|
|
|
1889
1894
|
font-weight: 600;
|
|
1890
1895
|
background: var(--ai-subtle, rgba(245, 158, 11, 0.1));
|
|
1891
1896
|
color: var(--ai-primary, #f59e0b);
|
|
1897
|
+
white-space: nowrap;
|
|
1898
|
+
flex-shrink: 1;
|
|
1899
|
+
min-width: 0;
|
|
1900
|
+
overflow: hidden;
|
|
1892
1901
|
}
|
|
1893
1902
|
|
|
1894
1903
|
.ai-suggestion-badge svg {
|
|
1895
1904
|
width: 14px;
|
|
1896
1905
|
height: 14px;
|
|
1906
|
+
flex-shrink: 0;
|
|
1897
1907
|
opacity: 0.8;
|
|
1898
1908
|
}
|
|
1899
1909
|
|
|
@@ -1924,6 +1934,7 @@ tr.newly-expanded .d2h-code-line-ctn {
|
|
|
1924
1934
|
background: var(--ai-subtle, rgba(245, 158, 11, 0.1));
|
|
1925
1935
|
border-radius: var(--radius-sm, 4px);
|
|
1926
1936
|
flex-shrink: 0;
|
|
1937
|
+
white-space: nowrap;
|
|
1927
1938
|
}
|
|
1928
1939
|
|
|
1929
1940
|
/* Type-specific colors - using CSS variables for theme support */
|
|
@@ -2074,6 +2085,10 @@ tr.newly-expanded .d2h-code-line-ctn {
|
|
|
2074
2085
|
.ai-title {
|
|
2075
2086
|
font-weight: 600;
|
|
2076
2087
|
color: var(--color-text-primary);
|
|
2088
|
+
overflow: hidden;
|
|
2089
|
+
text-overflow: ellipsis;
|
|
2090
|
+
white-space: nowrap;
|
|
2091
|
+
min-width: 0;
|
|
2077
2092
|
}
|
|
2078
2093
|
|
|
2079
2094
|
/* Confidence display removed to match cleaner prototype design (issue pair_review-7g5) */
|
|
@@ -6466,6 +6481,96 @@ body:not([data-theme="dark"]) .theme-icon-light {
|
|
|
6466
6481
|
text-overflow: ellipsis;
|
|
6467
6482
|
}
|
|
6468
6483
|
|
|
6484
|
+
/* Accessible visually-hidden utility */
|
|
6485
|
+
.sr-only {
|
|
6486
|
+
position: absolute;
|
|
6487
|
+
width: 1px;
|
|
6488
|
+
height: 1px;
|
|
6489
|
+
padding: 0;
|
|
6490
|
+
margin: -1px;
|
|
6491
|
+
overflow: hidden;
|
|
6492
|
+
clip: rect(0, 0, 0, 0);
|
|
6493
|
+
white-space: nowrap;
|
|
6494
|
+
border: 0;
|
|
6495
|
+
}
|
|
6496
|
+
|
|
6497
|
+
/* Base branch selector */
|
|
6498
|
+
.toolbar-base-branch-wrap {
|
|
6499
|
+
display: none;
|
|
6500
|
+
align-items: center;
|
|
6501
|
+
}
|
|
6502
|
+
|
|
6503
|
+
.toolbar-base-branch-wrap:not([hidden]) {
|
|
6504
|
+
display: inline-flex;
|
|
6505
|
+
}
|
|
6506
|
+
|
|
6507
|
+
.base-branch-selector-wrap {
|
|
6508
|
+
display: none;
|
|
6509
|
+
align-items: center;
|
|
6510
|
+
}
|
|
6511
|
+
|
|
6512
|
+
.base-branch-selector-wrap:not([hidden]) {
|
|
6513
|
+
display: inline-flex;
|
|
6514
|
+
}
|
|
6515
|
+
|
|
6516
|
+
.base-branch-vs {
|
|
6517
|
+
font-size: 0.75rem;
|
|
6518
|
+
color: var(--color-text-tertiary);
|
|
6519
|
+
margin: 0 6px;
|
|
6520
|
+
}
|
|
6521
|
+
|
|
6522
|
+
.toolbar-base-branch-static[hidden] {
|
|
6523
|
+
display: none;
|
|
6524
|
+
}
|
|
6525
|
+
|
|
6526
|
+
.toolbar-base-branch-static {
|
|
6527
|
+
display: inline-flex;
|
|
6528
|
+
align-items: center;
|
|
6529
|
+
gap: 4px;
|
|
6530
|
+
padding: 2px 8px;
|
|
6531
|
+
background-color: var(--color-bg-tertiary);
|
|
6532
|
+
border: 1px solid var(--color-border-primary);
|
|
6533
|
+
border-radius: 6px;
|
|
6534
|
+
font-family: var(--font-mono);
|
|
6535
|
+
font-size: 11px;
|
|
6536
|
+
color: var(--color-text-primary);
|
|
6537
|
+
white-space: nowrap;
|
|
6538
|
+
overflow: hidden;
|
|
6539
|
+
text-overflow: ellipsis;
|
|
6540
|
+
max-width: 260px;
|
|
6541
|
+
}
|
|
6542
|
+
|
|
6543
|
+
.toolbar-base-branch-static svg {
|
|
6544
|
+
color: var(--color-text-tertiary);
|
|
6545
|
+
flex-shrink: 0;
|
|
6546
|
+
}
|
|
6547
|
+
|
|
6548
|
+
.toolbar-base-branch-static span {
|
|
6549
|
+
overflow: hidden;
|
|
6550
|
+
text-overflow: ellipsis;
|
|
6551
|
+
}
|
|
6552
|
+
|
|
6553
|
+
.base-branch-select {
|
|
6554
|
+
font-size: 11px;
|
|
6555
|
+
padding: 2px 8px;
|
|
6556
|
+
background: var(--color-bg-tertiary);
|
|
6557
|
+
border: 1px solid var(--color-border-primary);
|
|
6558
|
+
border-radius: 6px;
|
|
6559
|
+
color: var(--color-text-primary);
|
|
6560
|
+
cursor: pointer;
|
|
6561
|
+
max-width: 260px;
|
|
6562
|
+
font-family: var(--font-mono);
|
|
6563
|
+
}
|
|
6564
|
+
|
|
6565
|
+
.base-branch-select:hover {
|
|
6566
|
+
background: var(--color-bg-secondary);
|
|
6567
|
+
}
|
|
6568
|
+
|
|
6569
|
+
.base-branch-select:focus {
|
|
6570
|
+
outline: 2px solid var(--color-accent-primary);
|
|
6571
|
+
outline-offset: -2px;
|
|
6572
|
+
}
|
|
6573
|
+
|
|
6469
6574
|
/* Shared copy button styles for toolbar (branch + commit) */
|
|
6470
6575
|
.toolbar-copy-btn {
|
|
6471
6576
|
display: inline-flex;
|
|
@@ -8943,12 +9048,24 @@ body.resizing * {
|
|
|
8943
9048
|
}
|
|
8944
9049
|
|
|
8945
9050
|
/* Category label for AI findings */
|
|
9051
|
+
.finding-meta {
|
|
9052
|
+
display: flex;
|
|
9053
|
+
align-items: center;
|
|
9054
|
+
gap: 4px;
|
|
9055
|
+
}
|
|
9056
|
+
|
|
8946
9057
|
.finding-category {
|
|
8947
9058
|
font-size: 0.6875rem;
|
|
8948
9059
|
color: var(--color-text-tertiary);
|
|
8949
9060
|
text-transform: capitalize;
|
|
8950
9061
|
}
|
|
8951
9062
|
|
|
9063
|
+
.finding-meta .severity-badge {
|
|
9064
|
+
margin-left: 0;
|
|
9065
|
+
font-size: 0.6rem;
|
|
9066
|
+
padding: 0 4px;
|
|
9067
|
+
}
|
|
9068
|
+
|
|
8952
9069
|
/* Star icon for praise findings */
|
|
8953
9070
|
.finding-star {
|
|
8954
9071
|
display: flex;
|
|
@@ -9659,7 +9776,7 @@ body.resizing * {
|
|
|
9659
9776
|
.instructions-container {
|
|
9660
9777
|
display: flex;
|
|
9661
9778
|
flex-direction: column;
|
|
9662
|
-
gap:
|
|
9779
|
+
gap: 4px;
|
|
9663
9780
|
}
|
|
9664
9781
|
|
|
9665
9782
|
.repo-instructions-banner {
|
|
@@ -10186,6 +10303,18 @@ body.resizing * {
|
|
|
10186
10303
|
min-width: 90px;
|
|
10187
10304
|
}
|
|
10188
10305
|
|
|
10306
|
+
.executable-note {
|
|
10307
|
+
font-size: 11px;
|
|
10308
|
+
color: var(--fg-muted, #656d76);
|
|
10309
|
+
font-style: italic;
|
|
10310
|
+
white-space: nowrap;
|
|
10311
|
+
}
|
|
10312
|
+
|
|
10313
|
+
.vc-levels-disabled-note {
|
|
10314
|
+
margin-top: 12px;
|
|
10315
|
+
margin-bottom: 0;
|
|
10316
|
+
}
|
|
10317
|
+
|
|
10189
10318
|
.btn-icon {
|
|
10190
10319
|
box-sizing: border-box;
|
|
10191
10320
|
width: 28px;
|
|
@@ -12758,3 +12887,61 @@ body.resizing * {
|
|
|
12758
12887
|
opacity: 0.4;
|
|
12759
12888
|
cursor: not-allowed;
|
|
12760
12889
|
}
|
|
12890
|
+
|
|
12891
|
+
/* Severity badges for executable provider suggestions */
|
|
12892
|
+
.severity-badge {
|
|
12893
|
+
display: inline-flex;
|
|
12894
|
+
font-size: 11px;
|
|
12895
|
+
padding: 1px 6px;
|
|
12896
|
+
border-radius: 3px;
|
|
12897
|
+
font-weight: 500;
|
|
12898
|
+
margin-left: 4px;
|
|
12899
|
+
white-space: nowrap;
|
|
12900
|
+
flex-shrink: 0;
|
|
12901
|
+
width: fit-content;
|
|
12902
|
+
}
|
|
12903
|
+
|
|
12904
|
+
.severity-critical {
|
|
12905
|
+
background: #fde8e8;
|
|
12906
|
+
color: #d32f2f;
|
|
12907
|
+
}
|
|
12908
|
+
|
|
12909
|
+
.severity-medium {
|
|
12910
|
+
background: #fff3e0;
|
|
12911
|
+
color: #ef6c00;
|
|
12912
|
+
}
|
|
12913
|
+
|
|
12914
|
+
.severity-minor {
|
|
12915
|
+
background: #fff8e1;
|
|
12916
|
+
color: #f9a825;
|
|
12917
|
+
}
|
|
12918
|
+
|
|
12919
|
+
[data-theme="dark"] .severity-critical {
|
|
12920
|
+
background: #3d1c1c;
|
|
12921
|
+
color: #ef9a9a;
|
|
12922
|
+
}
|
|
12923
|
+
|
|
12924
|
+
[data-theme="dark"] .severity-medium {
|
|
12925
|
+
background: #3d2e1c;
|
|
12926
|
+
color: #ffcc80;
|
|
12927
|
+
}
|
|
12928
|
+
|
|
12929
|
+
[data-theme="dark"] .severity-minor {
|
|
12930
|
+
background: #3d3a1c;
|
|
12931
|
+
color: #fff176;
|
|
12932
|
+
}
|
|
12933
|
+
|
|
12934
|
+
/* Note shown when executable provider is selected (no level toggles) */
|
|
12935
|
+
.executable-provider-note {
|
|
12936
|
+
padding: 8px 12px;
|
|
12937
|
+
background: var(--bg-tertiary, #f6f8fa);
|
|
12938
|
+
border-radius: 6px;
|
|
12939
|
+
font-size: 13px;
|
|
12940
|
+
color: var(--fg-muted, #656d76);
|
|
12941
|
+
margin-top: 8px;
|
|
12942
|
+
}
|
|
12943
|
+
|
|
12944
|
+
[data-theme="dark"] .executable-provider-note {
|
|
12945
|
+
background: rgba(56, 139, 253, 0.1);
|
|
12946
|
+
color: var(--color-text-secondary, #8b949e);
|
|
12947
|
+
}
|
package/public/index.html
CHANGED
|
@@ -685,6 +685,25 @@
|
|
|
685
685
|
text-align: right;
|
|
686
686
|
}
|
|
687
687
|
|
|
688
|
+
/* Analysis-in-progress spinner for index page rows */
|
|
689
|
+
.index-analysis-spinner {
|
|
690
|
+
display: inline-block;
|
|
691
|
+
width: 12px;
|
|
692
|
+
height: 12px;
|
|
693
|
+
border: 2px solid var(--ai-primary);
|
|
694
|
+
border-top-color: transparent;
|
|
695
|
+
border-radius: 50%;
|
|
696
|
+
animation: index-spin 0.8s linear infinite;
|
|
697
|
+
margin-right: 6px;
|
|
698
|
+
vertical-align: middle;
|
|
699
|
+
flex-shrink: 0;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
@keyframes index-spin {
|
|
703
|
+
0% { transform: rotate(0deg); }
|
|
704
|
+
100% { transform: rotate(360deg); }
|
|
705
|
+
}
|
|
706
|
+
|
|
688
707
|
.local-table .btn-repo-settings {
|
|
689
708
|
margin-right: 4px;
|
|
690
709
|
}
|
|
@@ -1430,6 +1449,7 @@
|
|
|
1430
1449
|
</div>
|
|
1431
1450
|
</div>
|
|
1432
1451
|
|
|
1452
|
+
<script src="/js/ws-client.js"></script>
|
|
1433
1453
|
<script src="/js/components/Toast.js"></script>
|
|
1434
1454
|
<script src="/js/index.js"></script>
|
|
1435
1455
|
</body>
|
|
@@ -1219,7 +1219,7 @@ class AIPanel {
|
|
|
1219
1219
|
${indicator}
|
|
1220
1220
|
<div class="finding-content">
|
|
1221
1221
|
<span class="finding-title">${this.escapeHtml(title)}</span>
|
|
1222
|
-
${category ? `<span class="finding-category">${this.escapeHtml(category)}</span>` : ''}
|
|
1222
|
+
${category || finding.severity ? `<span class="finding-meta">${category ? `<span class="finding-category">${this.escapeHtml(category)}</span>` : ''}${finding.severity ? `<span class="severity-badge severity-${finding.severity}">${this.escapeHtml(finding.severity.toUpperCase())}</span>` : ''}</span>` : ''}
|
|
1223
1223
|
${fileName ? `<span class="finding-location">${this.escapeHtml(fileName)}</span>` : ''}
|
|
1224
1224
|
</div>
|
|
1225
1225
|
</button>
|
|
@@ -289,7 +289,7 @@ class AdvancedConfigTab {
|
|
|
289
289
|
'2': { enabled: true, voices: [] },
|
|
290
290
|
'3': { enabled: true, voices: [] }
|
|
291
291
|
},
|
|
292
|
-
consolidation: { provider: this._defaultProvider || 'claude', model: this._defaultModel || 'sonnet', tier: 'balanced', timeout:
|
|
292
|
+
consolidation: { provider: this._defaultProvider || 'claude', model: this._defaultModel || 'sonnet', tier: 'balanced', timeout: this._getProviderDefaultTimeout(this._defaultProvider || 'claude') }
|
|
293
293
|
};
|
|
294
294
|
}
|
|
295
295
|
|
|
@@ -605,10 +605,11 @@ class AdvancedConfigTab {
|
|
|
605
605
|
}
|
|
606
606
|
});
|
|
607
607
|
|
|
608
|
-
// Provider change -> update model dropdowns
|
|
608
|
+
// Provider change -> update model dropdowns + timeout default
|
|
609
609
|
panel.addEventListener('change', (e) => {
|
|
610
610
|
if (e.target.classList.contains('voice-provider')) {
|
|
611
611
|
this._updateModelDropdown(e.target);
|
|
612
|
+
this._applyProviderDefaultTimeout(e.target);
|
|
612
613
|
}
|
|
613
614
|
// Model change -> update tier to match model's recommended tier
|
|
614
615
|
if (e.target.classList.contains('voice-model')) {
|
|
@@ -805,6 +806,7 @@ class AdvancedConfigTab {
|
|
|
805
806
|
const newProviderSelect = voiceList.querySelector(`.voice-provider[data-level="${level}"][data-index="${index}"]`);
|
|
806
807
|
if (newProviderSelect) {
|
|
807
808
|
this._populateProviderDropdown(newProviderSelect);
|
|
809
|
+
this._applyProviderDefaultTimeout(newProviderSelect);
|
|
808
810
|
}
|
|
809
811
|
|
|
810
812
|
// Update remove button visibility for this level
|
|
@@ -894,6 +896,16 @@ class AdvancedConfigTab {
|
|
|
894
896
|
iconBtn.classList.toggle('has-instructions', hasContent);
|
|
895
897
|
}
|
|
896
898
|
|
|
899
|
+
/**
|
|
900
|
+
* Get the default timeout for a provider, falling back to the static DEFAULT_TIMEOUT.
|
|
901
|
+
* @param {string} providerId - Provider ID (e.g., 'pi', 'claude')
|
|
902
|
+
* @returns {number} Default timeout in ms
|
|
903
|
+
*/
|
|
904
|
+
_getProviderDefaultTimeout(providerId) {
|
|
905
|
+
const provider = this.providers[providerId];
|
|
906
|
+
return provider?.defaultTimeout ?? AdvancedConfigTab.DEFAULT_TIMEOUT;
|
|
907
|
+
}
|
|
908
|
+
|
|
897
909
|
/**
|
|
898
910
|
* Update the clock/timeout icon styling to indicate non-default timeout.
|
|
899
911
|
* @param {Element} panel - The council panel element
|
|
@@ -906,7 +918,9 @@ class AdvancedConfigTab {
|
|
|
906
918
|
const iconBtn = wrapper?.querySelector(`.toggle-timeout-icon[data-level="${level}"][data-index="${index}"]`);
|
|
907
919
|
if (!iconBtn) return;
|
|
908
920
|
|
|
909
|
-
const
|
|
921
|
+
const providerId = wrapper?.querySelector('.voice-provider')?.value;
|
|
922
|
+
const defaultTimeout = this._getProviderDefaultTimeout(providerId);
|
|
923
|
+
const isNonDefault = parseInt(value, 10) !== defaultTimeout;
|
|
910
924
|
iconBtn.classList.toggle('has-custom-timeout', isNonDefault);
|
|
911
925
|
}
|
|
912
926
|
|
|
@@ -914,7 +928,10 @@ class AdvancedConfigTab {
|
|
|
914
928
|
const iconBtn = panel.querySelector('#adv-orchestration-timeout-toggle');
|
|
915
929
|
if (!iconBtn) return;
|
|
916
930
|
|
|
917
|
-
const
|
|
931
|
+
const orchRow = panel.querySelector('#orchestration-voice');
|
|
932
|
+
const providerId = orchRow?.querySelector('.voice-provider')?.value;
|
|
933
|
+
const defaultTimeout = this._getProviderDefaultTimeout(providerId);
|
|
934
|
+
const isNonDefault = parseInt(value, 10) !== defaultTimeout;
|
|
918
935
|
iconBtn.classList.toggle('has-custom-timeout', isNonDefault);
|
|
919
936
|
}
|
|
920
937
|
|
|
@@ -929,6 +946,48 @@ class AdvancedConfigTab {
|
|
|
929
946
|
iconBtn.classList.toggle('has-instructions', hasContent);
|
|
930
947
|
}
|
|
931
948
|
|
|
949
|
+
/**
|
|
950
|
+
* When a voice's provider changes, update its timeout to the new provider's default,
|
|
951
|
+
* preserving explicit user overrides via Math.max when the user had customized the value.
|
|
952
|
+
* @param {HTMLSelectElement} providerSelect - The provider dropdown that changed
|
|
953
|
+
*/
|
|
954
|
+
_applyProviderDefaultTimeout(providerSelect) {
|
|
955
|
+
const panel = this.modal.querySelector('#tab-panel-advanced');
|
|
956
|
+
if (!panel) return;
|
|
957
|
+
|
|
958
|
+
const providerId = providerSelect.value;
|
|
959
|
+
const newDefault = this._getProviderDefaultTimeout(providerId);
|
|
960
|
+
const oldProviderId = providerSelect.dataset.previousProvider;
|
|
961
|
+
const oldDefault = oldProviderId ? this._getProviderDefaultTimeout(oldProviderId) : null;
|
|
962
|
+
|
|
963
|
+
const isOrchestration = providerSelect.dataset.target === 'orchestration';
|
|
964
|
+
if (isOrchestration) {
|
|
965
|
+
const timeoutEl = panel.querySelector('#adv-orchestration-timeout');
|
|
966
|
+
if (timeoutEl) {
|
|
967
|
+
const currentValue = parseInt(timeoutEl.value, 10);
|
|
968
|
+
const resolvedTimeout = (oldDefault !== null && currentValue !== oldDefault)
|
|
969
|
+
? Math.max(currentValue, newDefault)
|
|
970
|
+
: newDefault;
|
|
971
|
+
timeoutEl.value = String(resolvedTimeout);
|
|
972
|
+
this._updateOrchestrationTimeoutIcon(panel, String(resolvedTimeout));
|
|
973
|
+
}
|
|
974
|
+
} else {
|
|
975
|
+
const { level, index } = providerSelect.dataset;
|
|
976
|
+
const wrapper = providerSelect.closest('.participant-wrapper');
|
|
977
|
+
const timeoutEl = wrapper?.querySelector('.adv-timeout');
|
|
978
|
+
if (timeoutEl) {
|
|
979
|
+
const currentValue = parseInt(timeoutEl.value, 10);
|
|
980
|
+
const resolvedTimeout = (oldDefault !== null && currentValue !== oldDefault)
|
|
981
|
+
? Math.max(currentValue, newDefault)
|
|
982
|
+
: newDefault;
|
|
983
|
+
timeoutEl.value = String(resolvedTimeout);
|
|
984
|
+
this._updateTimeoutIcon(panel, level, index, String(resolvedTimeout));
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
providerSelect.dataset.previousProvider = providerId;
|
|
989
|
+
}
|
|
990
|
+
|
|
932
991
|
// --- Dirty state tracking ---
|
|
933
992
|
|
|
934
993
|
_markDirty() {
|
|
@@ -1108,6 +1167,7 @@ class AdvancedConfigTab {
|
|
|
1108
1167
|
if (providerSelect) {
|
|
1109
1168
|
this._populateProviderDropdown(providerSelect);
|
|
1110
1169
|
providerSelect.value = voice.provider;
|
|
1170
|
+
providerSelect.dataset.previousProvider = voice.provider;
|
|
1111
1171
|
this._updateModelDropdown(providerSelect);
|
|
1112
1172
|
const modelSelect = row.querySelector('.voice-model');
|
|
1113
1173
|
if (modelSelect) modelSelect.value = voice.model;
|
|
@@ -1121,13 +1181,17 @@ class AdvancedConfigTab {
|
|
|
1121
1181
|
TimeoutSelect.mount(mount, { className: 'adv-timeout', title: 'Per-reviewer timeout' });
|
|
1122
1182
|
}
|
|
1123
1183
|
const timeoutEl = row?.querySelector('.adv-timeout');
|
|
1184
|
+
const providerDefaultTimeout = this._getProviderDefaultTimeout(voice.provider);
|
|
1124
1185
|
if (timeoutEl && voice.timeout) {
|
|
1125
1186
|
timeoutEl.value = String(voice.timeout);
|
|
1126
|
-
// Show the dropdown if non-default
|
|
1127
|
-
if (voice.timeout !==
|
|
1187
|
+
// Show the dropdown if non-default for this provider
|
|
1188
|
+
if (voice.timeout !== providerDefaultTimeout) {
|
|
1128
1189
|
timeoutEl.style.display = '';
|
|
1129
1190
|
}
|
|
1130
1191
|
this._updateTimeoutIcon(panel, String(level), String(i), String(voice.timeout));
|
|
1192
|
+
} else if (timeoutEl) {
|
|
1193
|
+
// No saved timeout — apply the provider's default
|
|
1194
|
+
timeoutEl.value = String(providerDefaultTimeout);
|
|
1131
1195
|
}
|
|
1132
1196
|
|
|
1133
1197
|
if (voice.customInstructions) {
|
|
@@ -1156,6 +1220,7 @@ class AdvancedConfigTab {
|
|
|
1156
1220
|
if (providerSelect) {
|
|
1157
1221
|
this._populateProviderDropdown(providerSelect);
|
|
1158
1222
|
providerSelect.value = consolSection.provider;
|
|
1223
|
+
providerSelect.dataset.previousProvider = consolSection.provider;
|
|
1159
1224
|
this._updateModelDropdown(providerSelect);
|
|
1160
1225
|
const modelSelect = orchRow.querySelector('.voice-model');
|
|
1161
1226
|
if (modelSelect) modelSelect.value = consolSection.model;
|
|
@@ -1166,13 +1231,18 @@ class AdvancedConfigTab {
|
|
|
1166
1231
|
|
|
1167
1232
|
// Restore consolidation timeout
|
|
1168
1233
|
const orchTimeoutSelect = panel.querySelector('#adv-orchestration-timeout');
|
|
1234
|
+
const orchProviderDefaultTimeout = this._getProviderDefaultTimeout(consolSection.provider);
|
|
1169
1235
|
if (orchTimeoutSelect && consolSection.timeout) {
|
|
1170
1236
|
orchTimeoutSelect.value = String(consolSection.timeout);
|
|
1171
|
-
// Show the dropdown if non-default
|
|
1172
|
-
if (consolSection.timeout !==
|
|
1237
|
+
// Show the dropdown if non-default for this provider
|
|
1238
|
+
if (consolSection.timeout !== orchProviderDefaultTimeout) {
|
|
1173
1239
|
orchTimeoutSelect.style.display = '';
|
|
1174
1240
|
}
|
|
1175
1241
|
this._updateOrchestrationTimeoutIcon(panel, String(consolSection.timeout));
|
|
1242
|
+
} else if (orchTimeoutSelect) {
|
|
1243
|
+
// No saved timeout — apply the provider's default
|
|
1244
|
+
orchTimeoutSelect.value = String(orchProviderDefaultTimeout);
|
|
1245
|
+
this._updateOrchestrationTimeoutIcon(panel, String(orchProviderDefaultTimeout));
|
|
1176
1246
|
}
|
|
1177
1247
|
|
|
1178
1248
|
// Restore consolidation custom instructions
|
|
@@ -1266,6 +1336,11 @@ class AdvancedConfigTab {
|
|
|
1266
1336
|
}
|
|
1267
1337
|
this._markClean();
|
|
1268
1338
|
await this.loadCouncils();
|
|
1339
|
+
const selector = this.modal.querySelector('#council-selector');
|
|
1340
|
+
if (selector) {
|
|
1341
|
+
selector.value = this.selectedCouncilId;
|
|
1342
|
+
selector.classList.remove('new-council-selected');
|
|
1343
|
+
}
|
|
1269
1344
|
}
|
|
1270
1345
|
|
|
1271
1346
|
/**
|