@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
|
@@ -200,6 +200,16 @@ class RepoSettingsPage {
|
|
|
200
200
|
});
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
+
// Chat instructions textarea
|
|
204
|
+
const chatTextarea = document.getElementById('chat-instructions');
|
|
205
|
+
if (chatTextarea) {
|
|
206
|
+
chatTextarea.addEventListener('input', () => {
|
|
207
|
+
this.currentSettings.default_chat_instructions = chatTextarea.value;
|
|
208
|
+
this.updateChatCharCount(chatTextarea.value.length);
|
|
209
|
+
this.checkForChanges();
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
203
213
|
// Analysis mode segmented control
|
|
204
214
|
const modeToggle = document.getElementById('analysis-mode-toggle');
|
|
205
215
|
if (modeToggle) {
|
|
@@ -814,7 +824,8 @@ class RepoSettingsPage {
|
|
|
814
824
|
default_tab: settings.default_tab || 'single',
|
|
815
825
|
default_council_id: settings.default_council_id || null,
|
|
816
826
|
default_instructions: settings.default_instructions || '',
|
|
817
|
-
local_path: settings.local_path || null
|
|
827
|
+
local_path: settings.local_path || null,
|
|
828
|
+
default_chat_instructions: settings.default_chat_instructions || ''
|
|
818
829
|
};
|
|
819
830
|
|
|
820
831
|
// Set current settings
|
|
@@ -832,7 +843,8 @@ class RepoSettingsPage {
|
|
|
832
843
|
default_tab: 'single',
|
|
833
844
|
default_council_id: null,
|
|
834
845
|
default_instructions: '',
|
|
835
|
-
local_path: null
|
|
846
|
+
local_path: null,
|
|
847
|
+
default_chat_instructions: ''
|
|
836
848
|
};
|
|
837
849
|
this.currentSettings = { ...this.originalSettings };
|
|
838
850
|
this.updateUI();
|
|
@@ -887,6 +899,13 @@ class RepoSettingsPage {
|
|
|
887
899
|
this.updateCharCount(textarea.value.length);
|
|
888
900
|
}
|
|
889
901
|
|
|
902
|
+
// Update chat instructions textarea
|
|
903
|
+
const chatTextarea = document.getElementById('chat-instructions');
|
|
904
|
+
if (chatTextarea) {
|
|
905
|
+
chatTextarea.value = this.currentSettings.default_chat_instructions || '';
|
|
906
|
+
this.updateChatCharCount(chatTextarea.value.length);
|
|
907
|
+
}
|
|
908
|
+
|
|
890
909
|
// Update local path display
|
|
891
910
|
this.updateLocalPathDisplay();
|
|
892
911
|
}
|
|
@@ -923,6 +942,13 @@ class RepoSettingsPage {
|
|
|
923
942
|
}
|
|
924
943
|
}
|
|
925
944
|
|
|
945
|
+
updateChatCharCount(count) {
|
|
946
|
+
const charCountEl = document.getElementById('chat-char-count');
|
|
947
|
+
if (charCountEl) {
|
|
948
|
+
charCountEl.textContent = count;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
|
|
926
952
|
checkForChanges() {
|
|
927
953
|
// Use nullish coalescing to normalize null/undefined for consistent comparison
|
|
928
954
|
const providerChanged = (this.currentSettings.default_provider ?? null) !== (this.originalSettings.default_provider ?? null);
|
|
@@ -930,8 +956,9 @@ class RepoSettingsPage {
|
|
|
930
956
|
const tabChanged = (this.currentSettings.default_tab ?? 'single') !== (this.originalSettings.default_tab ?? 'single');
|
|
931
957
|
const councilChanged = (this.currentSettings.default_council_id ?? null) !== (this.originalSettings.default_council_id ?? null);
|
|
932
958
|
const instructionsChanged = (this.currentSettings.default_instructions ?? '') !== (this.originalSettings.default_instructions ?? '');
|
|
959
|
+
const chatInstructionsChanged = (this.currentSettings.default_chat_instructions ?? '') !== (this.originalSettings.default_chat_instructions ?? '');
|
|
933
960
|
|
|
934
|
-
this.hasUnsavedChanges = providerChanged || modelChanged || tabChanged || councilChanged || instructionsChanged;
|
|
961
|
+
this.hasUnsavedChanges = providerChanged || modelChanged || tabChanged || councilChanged || instructionsChanged || chatInstructionsChanged;
|
|
935
962
|
|
|
936
963
|
// Show/hide action bar
|
|
937
964
|
const actionBar = document.getElementById('action-bar');
|
|
@@ -965,7 +992,8 @@ class RepoSettingsPage {
|
|
|
965
992
|
default_model: this.currentSettings.default_model,
|
|
966
993
|
default_tab: this.currentSettings.default_tab,
|
|
967
994
|
default_council_id: this.currentSettings.default_council_id,
|
|
968
|
-
default_instructions: this.currentSettings.default_instructions
|
|
995
|
+
default_instructions: this.currentSettings.default_instructions,
|
|
996
|
+
default_chat_instructions: this.currentSettings.default_chat_instructions
|
|
969
997
|
})
|
|
970
998
|
});
|
|
971
999
|
|
|
@@ -1039,7 +1067,8 @@ class RepoSettingsPage {
|
|
|
1039
1067
|
default_tab: null,
|
|
1040
1068
|
default_council_id: null,
|
|
1041
1069
|
default_instructions: '',
|
|
1042
|
-
local_path: null
|
|
1070
|
+
local_path: null,
|
|
1071
|
+
default_chat_instructions: ''
|
|
1043
1072
|
})
|
|
1044
1073
|
});
|
|
1045
1074
|
|
|
@@ -1054,7 +1083,8 @@ class RepoSettingsPage {
|
|
|
1054
1083
|
default_tab: 'single',
|
|
1055
1084
|
default_council_id: null,
|
|
1056
1085
|
default_instructions: '',
|
|
1057
|
-
local_path: null
|
|
1086
|
+
local_path: null,
|
|
1087
|
+
default_chat_instructions: ''
|
|
1058
1088
|
};
|
|
1059
1089
|
this.currentSettings = { ...this.originalSettings };
|
|
1060
1090
|
this.hasUnsavedChanges = false;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
/**
|
|
3
|
+
* Canonical category-to-emoji mapping for AI suggestion types.
|
|
4
|
+
* Used by SuggestionManager and FileCommentManager to format adopted comments.
|
|
5
|
+
*
|
|
6
|
+
* Canonical types from src/ai/prompts/shared/output-schema.js:
|
|
7
|
+
* bug|improvement|praise|suggestion|design|performance|security|code-style
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
(function() {
|
|
11
|
+
const CATEGORY_EMOJI_MAP = {
|
|
12
|
+
'bug': '\u{1F41B}', // bug
|
|
13
|
+
'improvement': '\u{1F4A1}', // lightbulb
|
|
14
|
+
'praise': '\u{2B50}', // star
|
|
15
|
+
'suggestion': '\u{1F4AC}', // speech bubble
|
|
16
|
+
'design': '\u{1F4D0}', // triangular ruler
|
|
17
|
+
'performance': '\u{26A1}', // high voltage
|
|
18
|
+
'security': '\u{1F512}', // lock
|
|
19
|
+
'code-style': '\u{1F3A8}', // artist palette
|
|
20
|
+
'style': '\u{1F3A8}' // artist palette (alias for code-style)
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const DEFAULT_EMOJI = '\u{1F4AC}'; // speech bubble
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get emoji for a suggestion category
|
|
27
|
+
* @param {string} category - Category name
|
|
28
|
+
* @returns {string} Emoji character
|
|
29
|
+
*/
|
|
30
|
+
function getEmoji(category) {
|
|
31
|
+
return CATEGORY_EMOJI_MAP[category] || DEFAULT_EMOJI;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Export to global scope
|
|
35
|
+
window.CategoryEmoji = {
|
|
36
|
+
MAP: CATEGORY_EMOJI_MAP,
|
|
37
|
+
DEFAULT: DEFAULT_EMOJI,
|
|
38
|
+
getEmoji
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
|
|
42
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
43
|
+
module.exports = { CATEGORY_EMOJI_MAP: window.CategoryEmoji.MAP, DEFAULT_EMOJI: window.CategoryEmoji.DEFAULT, getEmoji: window.CategoryEmoji.getEmoji };
|
|
44
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
/**
|
|
3
|
+
* Timestamp parsing utility for consistent UTC interpretation.
|
|
4
|
+
*
|
|
5
|
+
* SQLite's CURRENT_TIMESTAMP produces strings like "2024-01-20 15:30:00"
|
|
6
|
+
* without a timezone indicator. JavaScript's Date() would interpret these
|
|
7
|
+
* as local time, but they are actually UTC. This helper ensures correct
|
|
8
|
+
* UTC parsing across the entire frontend.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
(function () {
|
|
12
|
+
/**
|
|
13
|
+
* Parse a timestamp string, ensuring UTC interpretation for SQLite timestamps.
|
|
14
|
+
* @param {string} timestamp - Timestamp string (ISO 8601 or SQLite format)
|
|
15
|
+
* @returns {Date} Parsed Date object (Invalid Date when input is falsy)
|
|
16
|
+
*/
|
|
17
|
+
function parseTimestamp(timestamp) {
|
|
18
|
+
if (!timestamp) return new Date(NaN);
|
|
19
|
+
|
|
20
|
+
// If the timestamp already has timezone info (ends with Z or +/-offset), parse as-is
|
|
21
|
+
if (/Z$|[+-]\d{2}:\d{2}$/.test(timestamp)) {
|
|
22
|
+
return new Date(timestamp);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// SQLite CURRENT_TIMESTAMP format: "YYYY-MM-DD HH:MM:SS" (no timezone, but is UTC)
|
|
26
|
+
// Append 'Z' to interpret as UTC
|
|
27
|
+
return new Date(timestamp + 'Z');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Export to global scope
|
|
31
|
+
window.parseTimestamp = parseTimestamp;
|
|
32
|
+
})();
|
package/public/local.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">
|
|
@@ -286,7 +296,7 @@
|
|
|
286
296
|
<!-- File Tree Sidebar (Left) -->
|
|
287
297
|
<aside class="sidebar files-sidebar" id="files-sidebar">
|
|
288
298
|
<div class="sidebar-header">
|
|
289
|
-
<span class="sidebar-title">
|
|
299
|
+
<span class="sidebar-title">File Navigator</span>
|
|
290
300
|
<div style="display: flex; align-items: center; gap: 8px;">
|
|
291
301
|
<span class="sidebar-count" id="sidebar-file-count">0</span>
|
|
292
302
|
<button class="sidebar-collapse-btn" id="sidebar-collapse-btn" title="Close panel">
|
|
@@ -364,10 +374,19 @@
|
|
|
364
374
|
</svg>
|
|
365
375
|
<span class="btn-text">Analyze</span>
|
|
366
376
|
</button>
|
|
367
|
-
<button class="btn btn-sm btn-icon" id="
|
|
377
|
+
<button class="btn btn-sm btn-icon" id="chat-toggle-btn" title="Toggle Chat panel">
|
|
378
|
+
<svg class="chat-icon" viewBox="0 0 16 16" fill="currentColor" width="14" height="14">
|
|
379
|
+
<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"/>
|
|
380
|
+
</svg>
|
|
381
|
+
</button>
|
|
382
|
+
<button class="btn btn-sm btn-icon" id="panel-layout-toggle" title="Switch panel layout" style="display: none;">
|
|
368
383
|
<svg viewBox="0 0 16 16" fill="currentColor" width="14" height="14">
|
|
369
|
-
<path d="
|
|
370
|
-
|
|
384
|
+
<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"/>
|
|
385
|
+
</svg>
|
|
386
|
+
</button>
|
|
387
|
+
<button class="btn btn-sm btn-icon" id="ai-panel-toggle" title="Toggle Review panel">
|
|
388
|
+
<svg viewBox="0 0 16 16" width="16" height="16" fill="currentColor">
|
|
389
|
+
<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"/>
|
|
371
390
|
</svg>
|
|
372
391
|
</button>
|
|
373
392
|
</div>
|
|
@@ -377,86 +396,90 @@
|
|
|
377
396
|
</div>
|
|
378
397
|
</main>
|
|
379
398
|
|
|
380
|
-
<!-- AI
|
|
381
|
-
<
|
|
382
|
-
|
|
383
|
-
<
|
|
384
|
-
<div class="ai-panel
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
<
|
|
399
|
+
<!-- Right Panel Group (AI Panel + Chat) -->
|
|
400
|
+
<div class="right-panel-group" id="right-panel-group">
|
|
401
|
+
<!-- AI Analysis Panel (Right) -->
|
|
402
|
+
<aside class="ai-panel" id="ai-panel">
|
|
403
|
+
<div class="resize-handle resize-handle-left" data-panel="ai-panel"></div>
|
|
404
|
+
<div class="ai-panel-header">
|
|
405
|
+
<div class="ai-panel-title">
|
|
406
|
+
<button class="ai-avatar-small ai-summary-btn" id="ai-summary-btn" aria-label="View AI summary" title="View AI Summary">
|
|
407
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" width="14" height="14">
|
|
408
|
+
<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"/>
|
|
409
|
+
<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"/>
|
|
410
|
+
</svg>
|
|
411
|
+
</button>
|
|
412
|
+
<span>Review</span>
|
|
413
|
+
</div>
|
|
414
|
+
<button class="ai-panel-close" id="ai-panel-close" title="Close panel">
|
|
415
|
+
<svg viewBox="0 0 16 16" fill="currentColor" width="14" height="14">
|
|
416
|
+
<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"/>
|
|
389
417
|
</svg>
|
|
390
418
|
</button>
|
|
391
|
-
<span>Review</span>
|
|
392
419
|
</div>
|
|
393
|
-
<button class="ai-panel-close" id="ai-panel-close" title="Close panel">
|
|
394
|
-
<svg viewBox="0 0 16 16" fill="currentColor" width="14" height="14">
|
|
395
|
-
<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"/>
|
|
396
|
-
</svg>
|
|
397
|
-
</button>
|
|
398
|
-
</div>
|
|
399
420
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
</svg>
|
|
407
|
-
<span>No AI analysis yet</span>
|
|
408
|
-
</div>
|
|
409
|
-
|
|
410
|
-
<!-- Selector (hidden until analysis exists) -->
|
|
411
|
-
<div class="analysis-context-selector" id="analysis-context-selector" style="display: none;">
|
|
412
|
-
<button class="analysis-context-btn" id="analysis-context-btn">
|
|
413
|
-
<span class="analysis-context-label" id="analysis-context-label">--</span>
|
|
414
|
-
<svg class="dropdown-caret" width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
|
|
415
|
-
<path d="M2.5 4.5L6 8L9.5 4.5" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
|
421
|
+
<!-- Analysis Context Section -->
|
|
422
|
+
<div class="analysis-context" id="analysis-context">
|
|
423
|
+
<!-- Empty state -->
|
|
424
|
+
<div class="analysis-context-empty" id="analysis-context-empty">
|
|
425
|
+
<svg class="analysis-context-empty-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
426
|
+
<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"/>
|
|
416
427
|
</svg>
|
|
417
|
-
|
|
418
|
-
|
|
428
|
+
<span>No AI analysis yet</span>
|
|
429
|
+
</div>
|
|
419
430
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
431
|
+
<!-- Selector (hidden until analysis exists) -->
|
|
432
|
+
<div class="analysis-context-selector" id="analysis-context-selector" style="display: none;">
|
|
433
|
+
<button class="analysis-context-btn" id="analysis-context-btn">
|
|
434
|
+
<span class="analysis-context-label" id="analysis-context-label">--</span>
|
|
435
|
+
<svg class="dropdown-caret" width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
|
|
436
|
+
<path d="M2.5 4.5L6 8L9.5 4.5" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
|
437
|
+
</svg>
|
|
438
|
+
</button>
|
|
424
439
|
</div>
|
|
425
|
-
|
|
426
|
-
|
|
440
|
+
|
|
441
|
+
<!-- Split-panel dropdown (hidden by default) -->
|
|
442
|
+
<div class="analysis-context-dropdown" id="analysis-context-dropdown">
|
|
443
|
+
<div class="analysis-run-list" id="analysis-context-list">
|
|
444
|
+
<!-- Populated by JavaScript -->
|
|
445
|
+
</div>
|
|
446
|
+
<div class="analysis-preview-panel" id="analysis-context-preview">
|
|
447
|
+
<!-- Populated by JavaScript on hover -->
|
|
448
|
+
</div>
|
|
427
449
|
</div>
|
|
428
450
|
</div>
|
|
429
|
-
</div>
|
|
430
451
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
452
|
+
<!-- Segment Control -->
|
|
453
|
+
<div class="segment-control" id="segment-control">
|
|
454
|
+
<div class="segment-control-inner">
|
|
455
|
+
<button class="segment-btn active" data-segment="ai">AI <span class="segment-count">(0)</span></button>
|
|
456
|
+
<button class="segment-btn" data-segment="comments">User <span class="segment-count">(0)</span></button>
|
|
457
|
+
<button class="segment-btn" data-segment="all">All <span class="segment-count">(0)</span></button>
|
|
458
|
+
</div>
|
|
437
459
|
</div>
|
|
438
|
-
</div>
|
|
439
|
-
|
|
440
|
-
<!-- Level Filter -->
|
|
441
|
-
<div class="level-filter" id="level-filter">
|
|
442
|
-
<button class="level-pill active" data-level="final" title="Curated suggestions from all levels">Overall</button>
|
|
443
|
-
<button class="level-pill" data-level="1" title="Line-level analysis">Line</button>
|
|
444
|
-
<button class="level-pill" data-level="2" title="File-level analysis">File</button>
|
|
445
|
-
<button class="level-pill" data-level="3" title="Codebase-level analysis">Codebase</button>
|
|
446
|
-
</div>
|
|
447
460
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
<
|
|
461
|
+
<!-- Level Filter -->
|
|
462
|
+
<div class="level-filter" id="level-filter">
|
|
463
|
+
<button class="level-pill active" data-level="final" title="Curated suggestions from all levels">Overall</button>
|
|
464
|
+
<button class="level-pill" data-level="1" title="Line-level analysis">Line</button>
|
|
465
|
+
<button class="level-pill" data-level="2" title="File-level analysis">File</button>
|
|
466
|
+
<button class="level-pill" data-level="3" title="Codebase-level analysis">Codebase</button>
|
|
452
467
|
</div>
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
468
|
+
|
|
469
|
+
<!-- Findings Summary -->
|
|
470
|
+
<div class="findings-summary" id="findings-summary">
|
|
471
|
+
<div class="findings-header">
|
|
472
|
+
<span class="findings-count" id="findings-count">0 items</span>
|
|
473
|
+
</div>
|
|
474
|
+
<div class="findings-list" id="findings-list">
|
|
475
|
+
<div class="findings-empty">
|
|
476
|
+
<p>No AI analysis yet. Click "Analyze" to get started.</p>
|
|
477
|
+
</div>
|
|
456
478
|
</div>
|
|
457
479
|
</div>
|
|
458
|
-
</
|
|
459
|
-
|
|
480
|
+
</aside>
|
|
481
|
+
<div id="chat-panel-container"></div>
|
|
482
|
+
</div>
|
|
460
483
|
</div>
|
|
461
484
|
</div>
|
|
462
485
|
|
|
@@ -476,12 +499,18 @@
|
|
|
476
499
|
<!-- Tier icons utility -->
|
|
477
500
|
<script src="/js/utils/tier-icons.js"></script>
|
|
478
501
|
|
|
502
|
+
<!-- Category emoji mapping -->
|
|
503
|
+
<script src="/js/utils/category-emoji.js"></script>
|
|
504
|
+
|
|
479
505
|
<!-- Suggestion UI utility -->
|
|
480
506
|
<script src="/js/utils/suggestion-ui.js"></script>
|
|
481
507
|
|
|
482
508
|
<!-- File order utility -->
|
|
483
509
|
<script src="/js/utils/file-order.js"></script>
|
|
484
510
|
|
|
511
|
+
<!-- Timestamp parsing utility -->
|
|
512
|
+
<script src="/js/utils/time.js"></script>
|
|
513
|
+
|
|
485
514
|
<!-- Components -->
|
|
486
515
|
<script src="/js/components/Toast.js"></script>
|
|
487
516
|
<script src="/js/components/ConfirmDialog.js"></script>
|
|
@@ -512,6 +541,14 @@
|
|
|
512
541
|
<script src="/js/modules/file-comment-manager.js"></script>
|
|
513
542
|
<script src="/js/modules/panel-resizer.js"></script>
|
|
514
543
|
<script src="/js/modules/analysis-history.js"></script>
|
|
544
|
+
<script src="/js/modules/diff-context.js"></script>
|
|
545
|
+
<script src="/js/modules/file-list-merger.js"></script>
|
|
546
|
+
|
|
547
|
+
<!-- Chat Panel Component -->
|
|
548
|
+
<script src="/js/components/ChatPanel.js"></script>
|
|
549
|
+
|
|
550
|
+
<!-- Panel Group Component -->
|
|
551
|
+
<script src="/js/components/PanelGroup.js"></script>
|
|
515
552
|
|
|
516
553
|
<!-- Local Mode Configuration -->
|
|
517
554
|
<script>
|