@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.
Files changed (63) hide show
  1. package/README.md +77 -4
  2. package/package.json +1 -1
  3. package/plugin/.claude-plugin/plugin.json +1 -1
  4. package/plugin/skills/review-requests/SKILL.md +4 -1
  5. package/plugin-code-critic/.claude-plugin/plugin.json +1 -1
  6. package/plugin-code-critic/skills/analyze/SKILL.md +4 -3
  7. package/public/css/pr.css +1962 -114
  8. package/public/js/CONVENTIONS.md +16 -0
  9. package/public/js/components/AIPanel.js +66 -0
  10. package/public/js/components/AnalysisConfigModal.js +2 -2
  11. package/public/js/components/ChatPanel.js +2955 -0
  12. package/public/js/components/CouncilProgressModal.js +12 -16
  13. package/public/js/components/KeyboardShortcuts.js +3 -0
  14. package/public/js/components/PanelGroup.js +723 -0
  15. package/public/js/components/PreviewModal.js +3 -8
  16. package/public/js/index.js +8 -0
  17. package/public/js/local.js +17 -615
  18. package/public/js/modules/analysis-history.js +19 -68
  19. package/public/js/modules/comment-manager.js +103 -20
  20. package/public/js/modules/diff-context.js +176 -0
  21. package/public/js/modules/diff-renderer.js +30 -0
  22. package/public/js/modules/file-comment-manager.js +126 -105
  23. package/public/js/modules/file-list-merger.js +64 -0
  24. package/public/js/modules/panel-resizer.js +25 -6
  25. package/public/js/modules/suggestion-manager.js +40 -125
  26. package/public/js/pr.js +1009 -159
  27. package/public/js/repo-settings.js +36 -6
  28. package/public/js/utils/category-emoji.js +44 -0
  29. package/public/js/utils/time.js +32 -0
  30. package/public/local.html +107 -70
  31. package/public/pr.html +107 -70
  32. package/public/repo-settings.html +32 -0
  33. package/src/ai/analyzer.js +5 -1
  34. package/src/ai/copilot-provider.js +39 -9
  35. package/src/ai/cursor-agent-provider.js +45 -11
  36. package/src/ai/gemini-provider.js +17 -4
  37. package/src/ai/prompts/config.js +7 -1
  38. package/src/ai/provider-availability.js +1 -1
  39. package/src/ai/provider.js +25 -37
  40. package/src/chat/CONVENTIONS.md +18 -0
  41. package/src/chat/pi-bridge.js +491 -0
  42. package/src/chat/prompt-builder.js +272 -0
  43. package/src/chat/session-manager.js +619 -0
  44. package/src/config.js +14 -0
  45. package/src/database.js +322 -15
  46. package/src/main.js +4 -17
  47. package/src/routes/analyses.js +721 -0
  48. package/src/routes/chat.js +655 -0
  49. package/src/routes/config.js +29 -8
  50. package/src/routes/context-files.js +274 -0
  51. package/src/routes/local.js +225 -1133
  52. package/src/routes/mcp.js +39 -30
  53. package/src/routes/pr.js +424 -58
  54. package/src/routes/reviews.js +1035 -0
  55. package/src/routes/shared.js +4 -29
  56. package/src/server.js +34 -12
  57. package/src/sse/review-events.js +46 -0
  58. package/src/utils/auto-context.js +88 -0
  59. package/src/utils/category-emoji.js +33 -0
  60. package/src/utils/diff-annotator.js +75 -1
  61. package/src/utils/diff-file-list.js +57 -0
  62. package/src/routes/analysis.js +0 -1600
  63. 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 SuggestionManager.CATEGORY_EMOJI_MAP[category] || '\u{1F4AC}';
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