@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
|
@@ -5,26 +5,39 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
class SuggestionManager {
|
|
8
|
-
// Category to emoji mapping for formatting adopted comments
|
|
9
|
-
static CATEGORY_EMOJI_MAP = {
|
|
10
|
-
'bug': '\u{1F41B}', // bug
|
|
11
|
-
'improvement': '\u{1F4A1}', // lightbulb
|
|
12
|
-
'suggestion': '\u{1F4AD}', // thought balloon
|
|
13
|
-
'design': '\u{1F3D7}', // building construction
|
|
14
|
-
'performance': '\u{1F680}', // rocket
|
|
15
|
-
'security': '\u{1F512}', // lock
|
|
16
|
-
'code-style': '\u{1F3A8}', // artist palette
|
|
17
|
-
'style': '\u{1F3A8}', // artist palette (alias)
|
|
18
|
-
'praise': '\u{2B50}', // star
|
|
19
|
-
'comment': '\u{1F4AC}' // speech bubble
|
|
20
|
-
};
|
|
21
|
-
|
|
22
8
|
constructor(prManagerRef) {
|
|
23
9
|
// Reference to parent PRManager for API calls and state access
|
|
24
10
|
this.prManager = prManagerRef;
|
|
25
11
|
// Concurrency guard for displayAISuggestions
|
|
26
12
|
this._isDisplayingSuggestions = false;
|
|
27
13
|
|
|
14
|
+
// Event delegation for "Ask about this" chat button on suggestions
|
|
15
|
+
document.addEventListener('click', (e) => {
|
|
16
|
+
const chatBtn = e.target.closest('.ai-action-chat');
|
|
17
|
+
if (chatBtn && chatBtn.closest('.file-comments-zone')) return; // handled by FileCommentManager
|
|
18
|
+
if (chatBtn && !chatBtn.closest('.ai-suggestion')) return; // not a suggestion chat button
|
|
19
|
+
if (chatBtn && window.chatPanel) {
|
|
20
|
+
e.stopPropagation();
|
|
21
|
+
const suggestionDiv = chatBtn.closest('.ai-suggestion');
|
|
22
|
+
const suggestionData = suggestionDiv ? this.extractSuggestionData(suggestionDiv) : {};
|
|
23
|
+
window.chatPanel.open({
|
|
24
|
+
reviewId: this.prManager?.currentPR?.id,
|
|
25
|
+
suggestionId: chatBtn.dataset.suggestionId,
|
|
26
|
+
suggestionContext: {
|
|
27
|
+
title: chatBtn.dataset.title || suggestionData.suggestionTitle || '',
|
|
28
|
+
body: suggestionData.suggestionText || '',
|
|
29
|
+
type: suggestionData.suggestionType || '',
|
|
30
|
+
file: chatBtn.dataset.file || '',
|
|
31
|
+
line_start: suggestionDiv?.dataset?.lineNumber ? parseInt(suggestionDiv.dataset.lineNumber) : null,
|
|
32
|
+
line_end: null,
|
|
33
|
+
side: suggestionDiv?.dataset?.side || 'RIGHT',
|
|
34
|
+
reasoning: null
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
28
41
|
// Event delegation for reasoning brain icon popover (pinned to button)
|
|
29
42
|
document.addEventListener('click', (e) => {
|
|
30
43
|
const toggleBtn = e.target.closest('.btn-reasoning-toggle');
|
|
@@ -143,7 +156,7 @@ class SuggestionManager {
|
|
|
143
156
|
* @returns {string} Emoji character
|
|
144
157
|
*/
|
|
145
158
|
getCategoryEmoji(category) {
|
|
146
|
-
return
|
|
159
|
+
return window.CategoryEmoji?.getEmoji(category) || '\u{1F4AC}';
|
|
147
160
|
}
|
|
148
161
|
|
|
149
162
|
/**
|
|
@@ -487,13 +500,13 @@ class SuggestionManager {
|
|
|
487
500
|
${categoryLabel ? `<span class="ai-suggestion-category">${escapeHtml(categoryLabel)}</span>` : ''}
|
|
488
501
|
<span class="ai-title">${escapeHtml(suggestion.title || '')}</span>
|
|
489
502
|
</div>
|
|
490
|
-
${suggestion.reasoning && suggestion.reasoning.length > 0 ? `
|
|
491
503
|
<div class="ai-suggestion-header-right">
|
|
504
|
+
${suggestion.reasoning && suggestion.reasoning.length > 0 ? `
|
|
492
505
|
<button class="btn-reasoning-toggle" title="View reasoning" data-suggestion-id="${suggestion.id}" data-reasoning="${encodeURIComponent(JSON.stringify(suggestion.reasoning))}">
|
|
493
506
|
<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><path d="M21.33 12.91c.09 1.55-.62 3.04-1.89 3.95l.77 1.49c.23.45.26.98.06 1.45c-.19.47-.58.84-1.06 1l-.79.25a1.69 1.69 0 0 1-1.86-.55L14.44 18c-.89-.15-1.73-.53-2.44-1.1c-.5.15-1 .23-1.5.23c-.88 0-1.76-.27-2.5-.79c-.53.16-1.07.23-1.62.22c-.79.01-1.57-.15-2.3-.45a4.1 4.1 0 0 1-2.43-3.61c-.08-.72.04-1.45.35-2.11c-.29-.75-.32-1.57-.07-2.33C2.3 7.11 3 6.32 3.87 5.82c.58-1.69 2.21-2.82 4-2.7c1.6-1.5 4.05-1.66 5.83-.37c.42-.11.86-.17 1.3-.17c1.36-.03 2.65.57 3.5 1.64c2.04.53 3.5 2.35 3.58 4.47c.05 1.11-.25 2.2-.86 3.13c.07.36.11.72.11 1.09m-5-1.41c.57.07 1.02.5 1.02 1.07a1 1 0 0 1-1 1h-.63c-.32.9-.88 1.69-1.62 2.29c.25.09.51.14.77.21c5.13-.07 4.53-3.2 4.53-3.25a2.59 2.59 0 0 0-2.69-2.49a1 1 0 0 1-1-1a1 1 0 0 1 1-1c1.23.03 2.41.49 3.33 1.3c.05-.29.08-.59.08-.89c-.06-1.24-.62-2.32-2.87-2.53c-1.25-2.96-4.4-1.32-4.4-.4c-.03.23.21.72.25.75a1 1 0 0 1 1 1c0 .55-.45 1-1 1c-.53-.02-1.03-.22-1.43-.56c-.48.31-1.03.5-1.6.56c-.57.05-1.04-.35-1.07-.9a.97.97 0 0 1 .88-1.1c.16-.02.94-.14.94-.77c0-.66.25-1.29.68-1.79c-.92-.25-1.91.08-2.91 1.29C6.75 5 6 5.25 5.45 7.2C4.5 7.67 4 8 3.78 9c1.08-.22 2.19-.13 3.22.25c.5.19.78.75.59 1.29c-.19.52-.77.78-1.29.59c-.73-.32-1.55-.34-2.3-.06c-.32.27-.32.83-.32 1.27c0 .74.37 1.43 1 1.83c.53.27 1.12.41 1.71.4q-.225-.39-.39-.81a1.038 1.038 0 0 1 1.96-.68c.4 1.14 1.42 1.92 2.62 2.05c1.37-.07 2.59-.88 3.19-2.13c.23-1.38 1.34-1.5 2.56-1.5m2 7.47l-.62-1.3l-.71.16l1 1.25zm-4.65-8.61a1 1 0 0 0-.91-1.03c-.71-.04-1.4.2-1.93.67c-.57.58-.87 1.38-.84 2.19a1 1 0 0 0 1 1c.57 0 1-.45 1-1c0-.27.07-.54.23-.76c.12-.1.27-.15.43-.15c.55.03 1.02-.38 1.02-.92"/></svg>
|
|
494
507
|
</button>
|
|
508
|
+
` : ''}
|
|
495
509
|
</div>
|
|
496
|
-
` : ''}
|
|
497
510
|
</div>
|
|
498
511
|
<div class="ai-suggestion-collapsed-content">
|
|
499
512
|
${suggestion.type === 'praise'
|
|
@@ -507,6 +520,12 @@ class SuggestionManager {
|
|
|
507
520
|
<svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor"><path d="M21.33 12.91c.09 1.55-.62 3.04-1.89 3.95l.77 1.49c.23.45.26.98.06 1.45c-.19.47-.58.84-1.06 1l-.79.25a1.69 1.69 0 0 1-1.86-.55L14.44 18c-.89-.15-1.73-.53-2.44-1.1c-.5.15-1 .23-1.5.23c-.88 0-1.76-.27-2.5-.79c-.53.16-1.07.23-1.62.22c-.79.01-1.57-.15-2.3-.45a4.1 4.1 0 0 1-2.43-3.61c-.08-.72.04-1.45.35-2.11c-.29-.75-.32-1.57-.07-2.33C2.3 7.11 3 6.32 3.87 5.82c.58-1.69 2.21-2.82 4-2.7c1.6-1.5 4.05-1.66 5.83-.37c.42-.11.86-.17 1.3-.17c1.36-.03 2.65.57 3.5 1.64c2.04.53 3.5 2.35 3.58 4.47c.05 1.11-.25 2.2-.86 3.13c.07.36.11.72.11 1.09m-5-1.41c.57.07 1.02.5 1.02 1.07a1 1 0 0 1-1 1h-.63c-.32.9-.88 1.69-1.62 2.29c.25.09.51.14.77.21c5.13-.07 4.53-3.2 4.53-3.25a2.59 2.59 0 0 0-2.69-2.49a1 1 0 0 1-1-1a1 1 0 0 1 1-1c1.23.03 2.41.49 3.33 1.3c.05-.29.08-.59.08-.89c-.06-1.24-.62-2.32-2.87-2.53c-1.25-2.96-4.4-1.32-4.4-.4c-.03.23.21.72.25.75a1 1 0 0 1 1 1c0 .55-.45 1-1 1c-.53-.02-1.03-.22-1.43-.56c-.48.31-1.03.5-1.6.56c-.57.05-1.04-.35-1.07-.9a.97.97 0 0 1 .88-1.1c.16-.02.94-.14.94-.77c0-.66.25-1.29.68-1.79c-.92-.25-1.91.08-2.91 1.29C6.75 5 6 5.25 5.45 7.2C4.5 7.67 4 8 3.78 9c1.08-.22 2.19-.13 3.22.25c.5.19.78.75.59 1.29c-.19.52-.77.78-1.29.59c-.73-.32-1.55-.34-2.3-.06c-.32.27-.32.83-.32 1.27c0 .74.37 1.43 1 1.83c.53.27 1.12.41 1.71.4q-.225-.39-.39-.81a1.038 1.038 0 0 1 1.96-.68c.4 1.14 1.42 1.92 2.62 2.05c1.37-.07 2.59-.88 3.19-2.13c.23-1.38 1.34-1.5 2.56-1.5m2 7.47l-.62-1.3-.71.16l1 1.25zm-4.65-8.61a1 1 0 0 0-.91-1.03c-.71-.04-1.4.2-1.93.67c-.57.58-.87 1.38-.84 2.19a1 1 0 0 0 1 1c.57 0 1-.45 1-1c0-.27.07-.54.23-.76c.12-.1.27-.15.43-.15c.55.03 1.02-.38 1.02-.92"/></svg>
|
|
508
521
|
</button>
|
|
509
522
|
` : ''}
|
|
523
|
+
<button class="btn-collapsed-chat ai-action-chat" title="Chat about suggestion"
|
|
524
|
+
data-suggestion-id="${suggestion.id}"
|
|
525
|
+
data-file="${escapeHtml(suggestion.file || '')}"
|
|
526
|
+
data-title="${escapeHtml(suggestion.title || '')}">
|
|
527
|
+
<svg viewBox="0 0 16 16" fill="currentColor" width="14" height="14"><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"/></svg>
|
|
528
|
+
</button>
|
|
510
529
|
<button class="btn-restore" onclick="prManager.restoreSuggestion(${suggestion.id})" title="Show suggestion">
|
|
511
530
|
<svg class="octicon octicon-eye" viewBox="0 0 16 16" width="16" height="16">
|
|
512
531
|
<path fill-rule="evenodd" d="M1.679 7.932c.412-.621 1.242-1.75 2.366-2.717C5.175 4.242 6.527 3.5 8 3.5c1.473 0 2.824.742 3.955 1.715 1.124.967 1.954 2.096 2.366 2.717a.119.119 0 010 .136c-.412.621-1.242 1.75-2.366 2.717C10.825 11.758 9.473 12.5 8 12.5c-1.473 0-2.824-.742-3.955-1.715C2.92 9.818 2.09 8.69 1.679 8.068a.119.119 0 010-.136zM8 2c-1.981 0-3.67.992-4.933 2.078C1.797 5.169.88 6.423.43 7.1a1.619 1.619 0 000 1.798c.45.678 1.367 1.932 2.637 3.024C4.329 13.008 6.019 14 8 14c1.981 0 3.67-.992 4.933-2.078 1.27-1.091 2.187-2.345 2.637-3.023a1.619 1.619 0 000-1.798c-.45-.678-1.367-1.932-2.637-3.023C11.671 2.992 9.981 2 8 2zm0 8a2 2 0 100-4 2 2 0 000 4z"></path>
|
|
@@ -532,6 +551,10 @@ class SuggestionManager {
|
|
|
532
551
|
<svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M11.013 1.427a1.75 1.75 0 012.474 0l1.086 1.086a1.75 1.75 0 010 2.474l-8.61 8.61c-.21.21-.47.364-.756.445l-3.251.93a.75.75 0 01-.927-.928l.929-3.25a1.75 1.75 0 01.445-.758l8.61-8.61zm1.414 1.06a.25.25 0 00-.354 0L10.811 3.75l1.439 1.44 1.263-1.263a.25.25 0 000-.354l-1.086-1.086zM11.189 6.25L9.75 4.81l-6.286 6.287a.25.25 0 00-.064.108l-.558 1.953 1.953-.558a.249.249 0 00.108-.064l6.286-6.286z"></path></svg>
|
|
533
552
|
Edit
|
|
534
553
|
</button>
|
|
554
|
+
<button class="ai-action ai-action-chat" title="Chat about suggestion" data-suggestion-id="${suggestion.id}" data-file="${escapeHtml(suggestion.file || '')}" data-title="${escapeHtml(suggestion.title || '')}">
|
|
555
|
+
<svg viewBox="0 0 16 16" fill="currentColor" width="16" height="16"><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"/></svg>
|
|
556
|
+
Chat
|
|
557
|
+
</button>
|
|
535
558
|
<button class="ai-action ai-action-dismiss" onclick="prManager.dismissSuggestion(${suggestion.id})">
|
|
536
559
|
<svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M3.72 3.72a.75.75 0 011.06 0L8 6.94l3.22-3.22a.75.75 0 111.06 1.06L9.06 8l3.22 3.22a.75.75 0 11-1.06 1.06L8 9.06l-3.22 3.22a.75.75 0 01-1.06-1.06L6.94 8 3.72 4.78a.75.75 0 010-1.06z"></path></svg>
|
|
537
560
|
Dismiss
|
|
@@ -677,114 +700,6 @@ class SuggestionManager {
|
|
|
677
700
|
return { targetRow, suggestionRow, lineNumber, fileName, diffPosition, side, isFileLevel: false };
|
|
678
701
|
}
|
|
679
702
|
|
|
680
|
-
/**
|
|
681
|
-
* Helper function to update status and collapse AI suggestion
|
|
682
|
-
* @param {number} suggestionId - Suggestion ID
|
|
683
|
-
* @param {HTMLElement} suggestionRow - The suggestion row element
|
|
684
|
-
* @param {string} collapsedText - Text to show when collapsed
|
|
685
|
-
* @param {string} status - Status to set
|
|
686
|
-
*/
|
|
687
|
-
async collapseAISuggestion(suggestionId, suggestionRow, collapsedText = 'Suggestion adopted', status = 'dismissed') {
|
|
688
|
-
// Update the AI suggestion status via API
|
|
689
|
-
const response = await fetch(`/api/ai-suggestion/${suggestionId}/status`, {
|
|
690
|
-
method: 'POST',
|
|
691
|
-
headers: {
|
|
692
|
-
'Content-Type': 'application/json'
|
|
693
|
-
},
|
|
694
|
-
body: JSON.stringify({ status })
|
|
695
|
-
});
|
|
696
|
-
|
|
697
|
-
if (!response.ok) {
|
|
698
|
-
throw new Error('Failed to update suggestion status');
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
// Collapse the AI suggestion in the UI
|
|
702
|
-
// Use suggestionId (found by ID) not suggestionRow.querySelector('.ai-suggestion')
|
|
703
|
-
// because multiple suggestions can share the same row when they target the same line
|
|
704
|
-
if (suggestionRow) {
|
|
705
|
-
const suggestionDiv = suggestionRow.querySelector(`[data-suggestion-id="${suggestionId}"]`);
|
|
706
|
-
if (suggestionDiv) {
|
|
707
|
-
suggestionDiv.classList.add('collapsed');
|
|
708
|
-
// Update collapsed content text
|
|
709
|
-
const collapsedContent = suggestionDiv.querySelector('.collapsed-text');
|
|
710
|
-
if (collapsedContent) {
|
|
711
|
-
collapsedContent.textContent = collapsedText;
|
|
712
|
-
}
|
|
713
|
-
// Update restore button - should say "Show" since suggestion is now collapsed
|
|
714
|
-
const restoreButton = suggestionDiv.querySelector('.btn-restore');
|
|
715
|
-
if (restoreButton) {
|
|
716
|
-
restoreButton.title = 'Show suggestion';
|
|
717
|
-
const btnText = restoreButton.querySelector('.btn-text');
|
|
718
|
-
if (btnText) {
|
|
719
|
-
btnText.textContent = 'Show';
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
if (status === 'adopted') {
|
|
723
|
-
suggestionDiv.dataset.hiddenForAdoption = 'true';
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
/**
|
|
730
|
-
* Helper function to create user comment from AI suggestion
|
|
731
|
-
* @param {number} suggestionId - Suggestion ID
|
|
732
|
-
* @param {string} fileName - File name
|
|
733
|
-
* @param {string} lineNumber - Line number
|
|
734
|
-
* @param {string} suggestionText - Suggestion text
|
|
735
|
-
* @param {string} suggestionType - Suggestion type
|
|
736
|
-
* @param {string} suggestionTitle - Suggestion title
|
|
737
|
-
* @param {string} diffPosition - Diff position
|
|
738
|
-
* @param {string} side - Side (LEFT or RIGHT)
|
|
739
|
-
* @returns {Object} Created comment data
|
|
740
|
-
*/
|
|
741
|
-
async createUserCommentFromSuggestion(suggestionId, fileName, lineNumber, suggestionText, suggestionType, suggestionTitle, diffPosition, side) {
|
|
742
|
-
// Format the comment text with emoji and category prefix
|
|
743
|
-
const formattedText = this.formatAdoptedComment(suggestionText, suggestionType);
|
|
744
|
-
|
|
745
|
-
// Parse diff_position if it's a string (from dataset)
|
|
746
|
-
const parsedDiffPosition = diffPosition ? parseInt(diffPosition) : null;
|
|
747
|
-
|
|
748
|
-
const reviewId = this.prManager?.currentPR?.id;
|
|
749
|
-
const headSha = this.prManager?.currentPR?.head_sha;
|
|
750
|
-
|
|
751
|
-
const createResponse = await fetch('/api/user-comment', {
|
|
752
|
-
method: 'POST',
|
|
753
|
-
headers: {
|
|
754
|
-
'Content-Type': 'application/json'
|
|
755
|
-
},
|
|
756
|
-
body: JSON.stringify({
|
|
757
|
-
review_id: reviewId,
|
|
758
|
-
file: fileName,
|
|
759
|
-
line_start: parseInt(lineNumber),
|
|
760
|
-
line_end: parseInt(lineNumber),
|
|
761
|
-
diff_position: parsedDiffPosition, // For GitHub API line-level comments
|
|
762
|
-
side: side || 'RIGHT', // For GitHub API (LEFT for deleted, RIGHT for added/context)
|
|
763
|
-
body: formattedText,
|
|
764
|
-
parent_id: suggestionId, // Link to original AI suggestion
|
|
765
|
-
type: suggestionType, // Preserve the type
|
|
766
|
-
title: suggestionTitle, // Preserve the title
|
|
767
|
-
commit_sha: headSha // Anchor comment to PR head commit
|
|
768
|
-
})
|
|
769
|
-
});
|
|
770
|
-
|
|
771
|
-
if (!createResponse.ok) {
|
|
772
|
-
throw new Error('Failed to create user comment');
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
const result = await createResponse.json();
|
|
776
|
-
return {
|
|
777
|
-
id: result.commentId,
|
|
778
|
-
file: fileName,
|
|
779
|
-
line_start: parseInt(lineNumber),
|
|
780
|
-
body: formattedText,
|
|
781
|
-
type: suggestionType,
|
|
782
|
-
title: suggestionTitle,
|
|
783
|
-
parent_id: suggestionId,
|
|
784
|
-
diff_position: parsedDiffPosition, // Include for expanded context warning logic
|
|
785
|
-
created_at: new Date().toISOString()
|
|
786
|
-
};
|
|
787
|
-
}
|
|
788
703
|
}
|
|
789
704
|
|
|
790
705
|
// Make SuggestionManager available globally
|