@in-the-loop-labs/pair-review 2.6.3 → 3.0.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.
Files changed (150) hide show
  1. package/.pi/extensions/task/index.ts +1 -1
  2. package/.pi/skills/review-roulette/SKILL.md +1 -1
  3. package/LICENSE +201 -674
  4. package/README.md +2 -2
  5. package/bin/pair-review.js +1 -1
  6. package/package.json +2 -2
  7. package/plugin/.claude-plugin/plugin.json +2 -2
  8. package/plugin-code-critic/.claude-plugin/plugin.json +2 -2
  9. package/plugin-code-critic/skills/analyze/scripts/git-diff-lines +1 -1
  10. package/public/css/ai-summary-modal.css +1 -1
  11. package/public/css/pr.css +194 -0
  12. package/public/index.html +168 -3
  13. package/public/js/components/AIPanel.js +17 -3
  14. package/public/js/components/AISummaryModal.js +1 -1
  15. package/public/js/components/AdvancedConfigTab.js +1 -1
  16. package/public/js/components/AnalysisConfigModal.js +1 -1
  17. package/public/js/components/ChatPanel.js +42 -7
  18. package/public/js/components/ConfirmDialog.js +22 -3
  19. package/public/js/components/CouncilProgressModal.js +14 -1
  20. package/public/js/components/DiffOptionsDropdown.js +411 -24
  21. package/public/js/components/EmojiPicker.js +1 -1
  22. package/public/js/components/KeyboardShortcuts.js +1 -1
  23. package/public/js/components/PanelGroup.js +1 -1
  24. package/public/js/components/PreviewModal.js +1 -1
  25. package/public/js/components/ReviewModal.js +1 -1
  26. package/public/js/components/SplitButton.js +1 -1
  27. package/public/js/components/StatusIndicator.js +1 -1
  28. package/public/js/components/SuggestionNavigator.js +13 -6
  29. package/public/js/components/TabTitle.js +96 -0
  30. package/public/js/components/TextInputDialog.js +1 -1
  31. package/public/js/components/TimeoutSelect.js +1 -1
  32. package/public/js/components/Toast.js +7 -1
  33. package/public/js/components/VoiceCentricConfigTab.js +1 -1
  34. package/public/js/index.js +649 -44
  35. package/public/js/local.js +570 -77
  36. package/public/js/modules/analysis-history.js +4 -3
  37. package/public/js/modules/comment-manager.js +6 -1
  38. package/public/js/modules/comment-minimizer.js +304 -0
  39. package/public/js/modules/diff-context.js +1 -1
  40. package/public/js/modules/diff-renderer.js +1 -1
  41. package/public/js/modules/file-comment-manager.js +1 -1
  42. package/public/js/modules/file-list-merger.js +1 -1
  43. package/public/js/modules/gap-coordinates.js +1 -1
  44. package/public/js/modules/hunk-parser.js +1 -1
  45. package/public/js/modules/line-tracker.js +1 -1
  46. package/public/js/modules/panel-resizer.js +1 -1
  47. package/public/js/modules/storage-cleanup.js +1 -1
  48. package/public/js/modules/suggestion-manager.js +1 -1
  49. package/public/js/pr.js +83 -7
  50. package/public/js/repo-settings.js +1 -1
  51. package/public/js/utils/category-emoji.js +1 -1
  52. package/public/js/utils/file-order.js +1 -1
  53. package/public/js/utils/markdown.js +1 -1
  54. package/public/js/utils/suggestion-ui.js +1 -1
  55. package/public/js/utils/tier-icons.js +1 -1
  56. package/public/js/utils/time.js +1 -1
  57. package/public/js/ws-client.js +1 -1
  58. package/public/local.html +14 -0
  59. package/public/pr.html +3 -0
  60. package/public/setup.html +1 -1
  61. package/src/ai/analyzer.js +18 -12
  62. package/src/ai/claude-cli.js +1 -1
  63. package/src/ai/claude-provider.js +1 -1
  64. package/src/ai/codex-provider.js +1 -1
  65. package/src/ai/copilot-provider.js +1 -1
  66. package/src/ai/cursor-agent-provider.js +1 -1
  67. package/src/ai/gemini-provider.js +1 -1
  68. package/src/ai/index.js +1 -1
  69. package/src/ai/opencode-provider.js +1 -1
  70. package/src/ai/pi-provider.js +1 -1
  71. package/src/ai/prompts/baseline/consolidation/balanced.js +1 -1
  72. package/src/ai/prompts/baseline/consolidation/fast.js +1 -1
  73. package/src/ai/prompts/baseline/consolidation/thorough.js +1 -1
  74. package/src/ai/prompts/baseline/level1/balanced.js +1 -1
  75. package/src/ai/prompts/baseline/level1/fast.js +1 -1
  76. package/src/ai/prompts/baseline/level1/thorough.js +1 -1
  77. package/src/ai/prompts/baseline/level2/balanced.js +1 -1
  78. package/src/ai/prompts/baseline/level2/fast.js +1 -1
  79. package/src/ai/prompts/baseline/level2/thorough.js +1 -1
  80. package/src/ai/prompts/baseline/level3/balanced.js +1 -1
  81. package/src/ai/prompts/baseline/level3/fast.js +1 -1
  82. package/src/ai/prompts/baseline/level3/thorough.js +1 -1
  83. package/src/ai/prompts/baseline/orchestration/balanced.js +1 -1
  84. package/src/ai/prompts/baseline/orchestration/fast.js +1 -1
  85. package/src/ai/prompts/baseline/orchestration/thorough.js +1 -1
  86. package/src/ai/prompts/config.js +1 -1
  87. package/src/ai/prompts/index.js +1 -1
  88. package/src/ai/prompts/line-number-guidance.js +1 -1
  89. package/src/ai/prompts/render-for-skill.js +1 -1
  90. package/src/ai/prompts/shared/diff-instructions.js +1 -1
  91. package/src/ai/prompts/shared/output-schema.js +1 -1
  92. package/src/ai/prompts/shared/valid-files.js +1 -1
  93. package/src/ai/prompts/sparse-checkout-guidance.js +1 -1
  94. package/src/ai/provider-availability.js +1 -1
  95. package/src/ai/provider.js +1 -1
  96. package/src/ai/stream-parser.js +1 -1
  97. package/src/chat/acp-bridge.js +1 -1
  98. package/src/chat/api-reference.js +1 -1
  99. package/src/chat/chat-providers.js +1 -1
  100. package/src/chat/claude-code-bridge.js +1 -1
  101. package/src/chat/codex-bridge.js +1 -1
  102. package/src/chat/pi-bridge.js +1 -1
  103. package/src/chat/prompt-builder.js +1 -1
  104. package/src/chat/session-manager.js +1 -1
  105. package/src/config.js +3 -1
  106. package/src/database.js +591 -40
  107. package/src/events/review-events.js +1 -1
  108. package/src/git/base-branch.js +173 -0
  109. package/src/git/gitattributes.js +1 -1
  110. package/src/git/sha-abbrev.js +35 -0
  111. package/src/git/worktree.js +1 -1
  112. package/src/github/client.js +33 -2
  113. package/src/github/parser.js +1 -1
  114. package/src/hooks/hook-runner.js +100 -0
  115. package/src/hooks/payloads.js +212 -0
  116. package/src/local-review.js +469 -130
  117. package/src/local-scope.js +58 -0
  118. package/src/main.js +56 -5
  119. package/src/mcp-stdio.js +1 -1
  120. package/src/protocol-handler.js +1 -1
  121. package/src/routes/analyses.js +74 -11
  122. package/src/routes/chat.js +34 -1
  123. package/src/routes/config.js +2 -1
  124. package/src/routes/context-files.js +1 -1
  125. package/src/routes/councils.js +1 -1
  126. package/src/routes/github-collections.js +1 -1
  127. package/src/routes/local.js +735 -69
  128. package/src/routes/mcp.js +21 -11
  129. package/src/routes/pr.js +91 -13
  130. package/src/routes/reviews.js +1 -1
  131. package/src/routes/setup.js +2 -1
  132. package/src/routes/shared.js +1 -1
  133. package/src/routes/worktrees.js +213 -149
  134. package/src/server.js +31 -1
  135. package/src/setup/local-setup.js +47 -6
  136. package/src/setup/pr-setup.js +29 -6
  137. package/src/utils/auto-context.js +1 -1
  138. package/src/utils/category-emoji.js +1 -1
  139. package/src/utils/comment-formatter.js +1 -1
  140. package/src/utils/diff-annotator.js +1 -1
  141. package/src/utils/diff-file-list.js +1 -1
  142. package/src/utils/instructions.js +1 -1
  143. package/src/utils/json-extractor.js +1 -1
  144. package/src/utils/line-validation.js +1 -1
  145. package/src/utils/logger.js +1 -1
  146. package/src/utils/paths.js +1 -1
  147. package/src/utils/safe-parse-json.js +1 -1
  148. package/src/utils/stats-calculator.js +1 -1
  149. package/src/ws/index.js +1 -1
  150. package/src/ws/server.js +1 -1
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  > Your AI-powered code review partner - Close the feedback loop between you and AI coding agents
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@in-the-loop-labs/pair-review)](https://www.npmjs.com/package/@in-the-loop-labs/pair-review)
6
- [![License: GPL-3.0](https://img.shields.io/badge/License-GPL%203.0-blue.svg)](LICENSE)
6
+ [![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
7
7
  [![Node.js >= 20](https://img.shields.io/badge/node-%3E%3D20-brightgreen)](https://nodejs.org)
8
8
 
9
9
  [GitHub Repository](https://github.com/in-the-loop-labs/pair-review)
@@ -819,7 +819,7 @@ Contributions welcome! Please:
819
819
 
820
820
  ## License
821
821
 
822
- GPL-3.0 License - see LICENSE file for details
822
+ Apache-2.0 License - see LICENSE file for details
823
823
 
824
824
  ---
825
825
 
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // SPDX-License-Identifier: GPL-3.0-or-later
2
+ // Copyright 2026 Tim Perkins (tjwp) | SPDX-License-Identifier: Apache-2.0
3
3
 
4
4
  const path = require('path');
5
5
  const { spawn } = require('child_process');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@in-the-loop-labs/pair-review",
3
- "version": "2.6.3",
3
+ "version": "3.0.0",
4
4
  "description": "Your AI-powered code review partner - Close the feedback loop with AI coding agents",
5
5
  "main": "src/server.js",
6
6
  "bin": {
@@ -50,7 +50,7 @@
50
50
  "gemini"
51
51
  ],
52
52
  "author": "Tim Perkins",
53
- "license": "GPL-3.0",
53
+ "license": "Apache-2.0",
54
54
  "repository": {
55
55
  "type": "git",
56
56
  "url": "git+https://github.com/in-the-loop-labs/pair-review.git"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pair-review",
3
- "version": "2.6.3",
3
+ "version": "3.0.0",
4
4
  "description": "pair-review app integration — Open PRs and local changes in the pair-review web UI, run server-side AI analysis, and address review feedback. Requires the pair-review MCP server.",
5
5
  "author": {
6
6
  "name": "in-the-loop-labs",
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "homepage": "https://github.com/in-the-loop-labs/pair-review",
10
10
  "repository": "https://github.com/in-the-loop-labs/pair-review",
11
- "license": "GPL-3.0-or-later",
11
+ "license": "Apache-2.0",
12
12
  "keywords": [
13
13
  "code-review",
14
14
  "pull-request",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-critic",
3
- "version": "2.6.3",
3
+ "version": "3.0.0",
4
4
  "description": "AI-powered code review analysis — Run three-level AI analysis and implement-review-fix loops directly in your coding agent. Works standalone, no server required.",
5
5
  "author": {
6
6
  "name": "in-the-loop-labs",
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "homepage": "https://github.com/in-the-loop-labs/pair-review",
10
10
  "repository": "https://github.com/in-the-loop-labs/pair-review",
11
- "license": "GPL-3.0-or-later",
11
+ "license": "Apache-2.0",
12
12
  "keywords": [
13
13
  "code-review",
14
14
  "ai",
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bash
2
- # SPDX-License-Identifier: GPL-3.0-or-later
2
+ # Copyright 2026 Tim Perkins (tjwp) | SPDX-License-Identifier: Apache-2.0
3
3
  #
4
4
  # git-diff-lines - Annotated diff with explicit line numbers
5
5
  #
@@ -1,4 +1,4 @@
1
- /* SPDX-License-Identifier: GPL-3.0-or-later */
1
+ /* Copyright 2026 Tim Perkins (tjwp) | SPDX-License-Identifier: Apache-2.0 */
2
2
  /**
3
3
  * AI Summary Modal Styles
4
4
  * Extracted from pr.css for better organization
package/public/css/pr.css CHANGED
@@ -2696,6 +2696,36 @@ tr.newly-expanded .d2h-code-line-ctn {
2696
2696
  justify-content: center;
2697
2697
  }
2698
2698
 
2699
+ /* When a secondary button is visible (3 buttons), widen and stack vertically.
2700
+ column-reverse puts Confirm (primary) on top, Cancel on bottom. */
2701
+ .confirm-dialog-container.has-secondary {
2702
+ min-width: 440px;
2703
+ }
2704
+
2705
+ .confirm-dialog-container.has-secondary .modal-footer {
2706
+ flex-direction: column-reverse;
2707
+ align-items: stretch;
2708
+ }
2709
+
2710
+ .confirm-dialog-container.has-secondary .modal-footer .btn {
2711
+ display: flex;
2712
+ flex-direction: column;
2713
+ align-items: center;
2714
+ }
2715
+
2716
+ /* Button description subtitles */
2717
+ .modal-footer .btn .btn-label {
2718
+ display: block;
2719
+ }
2720
+
2721
+ .modal-footer .btn .btn-desc {
2722
+ display: block;
2723
+ font-size: 12px;
2724
+ font-weight: normal;
2725
+ opacity: 0.7;
2726
+ margin-top: 2px;
2727
+ }
2728
+
2699
2729
  /* Dialogs spawned from within other modals need higher z-index */
2700
2730
  #text-input-dialog,
2701
2731
  #confirm-dialog {
@@ -7244,6 +7274,7 @@ body.resizing * {
7244
7274
  .diff-options-popover {
7245
7275
  position: fixed;
7246
7276
  z-index: 1100;
7277
+ min-width: 320px;
7247
7278
  background: var(--color-bg-primary);
7248
7279
  border: 1px solid var(--color-border-primary);
7249
7280
  border-radius: 8px;
@@ -7315,6 +7346,150 @@ body.resizing * {
7315
7346
  background: rgba(88, 166, 255, 0.15);
7316
7347
  }
7317
7348
 
7349
+ /* --------------------------------------------------------------------------
7350
+ Comment Minimize Mode
7351
+ -------------------------------------------------------------------------- */
7352
+
7353
+ /* When minimize mode is active, hide all inline comment and suggestion rows */
7354
+ .comments-minimized .user-comment-row,
7355
+ .comments-minimized .ai-suggestion-row {
7356
+ display: none;
7357
+ }
7358
+
7359
+ /* Per-line expansion override — clicking an indicator reveals that line's rows */
7360
+ .comments-minimized .user-comment-row.comment-expanded,
7361
+ .comments-minimized .ai-suggestion-row.comment-expanded {
7362
+ display: table-row;
7363
+ }
7364
+
7365
+ /* Indicator button on the right edge of diff code cells */
7366
+ .comment-indicator {
7367
+ position: absolute;
7368
+ right: 4px;
7369
+ top: 50%;
7370
+ transform: translateY(-50%);
7371
+ display: inline-flex;
7372
+ align-items: center;
7373
+ gap: 3px;
7374
+ padding: 2px 6px;
7375
+ border: 1px solid var(--color-border-primary);
7376
+ border-radius: 12px;
7377
+ background: var(--color-bg-secondary);
7378
+ cursor: pointer;
7379
+ font-size: 11px;
7380
+ line-height: 1;
7381
+ color: var(--color-text-secondary);
7382
+ opacity: 1;
7383
+ transition: background 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
7384
+ z-index: 2; /* must be below sticky file headers (z-index: 4) */
7385
+ }
7386
+
7387
+ .comment-indicator:hover {
7388
+ background: var(--color-bg-tertiary);
7389
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
7390
+ }
7391
+
7392
+ .comment-indicator.expanded {
7393
+ border-width: 2px;
7394
+ padding: 1px 5px; /* compensate for thicker border */
7395
+ }
7396
+
7397
+ .comment-indicator .indicator-icon {
7398
+ display: inline-flex;
7399
+ align-items: center;
7400
+ }
7401
+
7402
+ .comment-indicator .indicator-icon svg {
7403
+ display: block;
7404
+ }
7405
+
7406
+ .comment-indicator .indicator-user {
7407
+ color: var(--comment-primary, #8250df);
7408
+ }
7409
+
7410
+ .comment-indicator .indicator-adopted {
7411
+ color: var(--comment-primary, #8250df);
7412
+ }
7413
+
7414
+ .comment-indicator:has(.indicator-user),
7415
+ .comment-indicator:has(.indicator-adopted) {
7416
+ border-color: var(--comment-primary, #8250df);
7417
+ background: rgba(130, 80, 223, 0.06);
7418
+ }
7419
+
7420
+ .comment-indicator:has(.indicator-user):hover,
7421
+ .comment-indicator:has(.indicator-adopted):hover {
7422
+ background: rgba(130, 80, 223, 0.12);
7423
+ box-shadow: 0 1px 3px rgba(130, 80, 223, 0.15);
7424
+ }
7425
+
7426
+ .comment-indicator .indicator-ai {
7427
+ color: var(--ai-accent, #d97706);
7428
+ }
7429
+
7430
+ .comment-indicator:has(.indicator-ai) {
7431
+ border-color: var(--ai-accent, #d97706);
7432
+ background: rgba(217, 119, 6, 0.06);
7433
+ }
7434
+
7435
+ .comment-indicator:has(.indicator-ai):hover {
7436
+ background: rgba(217, 119, 6, 0.12);
7437
+ box-shadow: 0 1px 3px rgba(217, 119, 6, 0.15);
7438
+ }
7439
+
7440
+ .comment-indicator .indicator-count {
7441
+ font-weight: 600;
7442
+ font-size: 10px;
7443
+ min-width: 14px;
7444
+ text-align: center;
7445
+ }
7446
+
7447
+ /* Dark theme overrides */
7448
+ [data-theme="dark"] .comment-indicator {
7449
+ background: var(--color-bg-tertiary);
7450
+ border-color: var(--color-border-secondary);
7451
+ }
7452
+
7453
+ [data-theme="dark"] .comment-indicator:hover {
7454
+ background: var(--color-bg-primary);
7455
+ }
7456
+
7457
+ [data-theme="dark"] .comment-indicator:has(.indicator-user),
7458
+ [data-theme="dark"] .comment-indicator:has(.indicator-adopted) {
7459
+ border-color: var(--comment-primary, #a371f7);
7460
+ background: rgba(163, 113, 247, 0.1);
7461
+ }
7462
+
7463
+ [data-theme="dark"] .comment-indicator .indicator-user,
7464
+ [data-theme="dark"] .comment-indicator .indicator-adopted {
7465
+ color: var(--comment-primary, #a371f7);
7466
+ }
7467
+
7468
+ [data-theme="dark"] .comment-indicator:has(.indicator-user):hover,
7469
+ [data-theme="dark"] .comment-indicator:has(.indicator-adopted):hover {
7470
+ background: rgba(163, 113, 247, 0.18);
7471
+ box-shadow: 0 1px 3px rgba(163, 113, 247, 0.25);
7472
+ }
7473
+
7474
+ [data-theme="dark"] .comment-indicator:has(.indicator-ai) {
7475
+ border-color: var(--color-accent-ai, #fbbf24);
7476
+ background: rgba(251, 191, 36, 0.1);
7477
+ }
7478
+
7479
+ [data-theme="dark"] .comment-indicator .indicator-ai {
7480
+ color: var(--color-accent-ai, #fbbf24);
7481
+ }
7482
+
7483
+ [data-theme="dark"] .comment-indicator:has(.indicator-ai):hover {
7484
+ background: rgba(251, 191, 36, 0.18);
7485
+ box-shadow: 0 1px 3px rgba(251, 191, 36, 0.25);
7486
+ }
7487
+
7488
+ [data-theme="dark"] .comment-indicator.expanded {
7489
+ border-width: 2px;
7490
+ padding: 1px 5px;
7491
+ }
7492
+
7318
7493
  .ai-panel-header {
7319
7494
  display: flex;
7320
7495
  align-items: center;
@@ -11832,6 +12007,25 @@ body.resizing * {
11832
12007
  30% { opacity: 1; transform: scale(1); }
11833
12008
  }
11834
12009
 
12010
+ /* Loop logo spinner (easter egg: chat_spinner = "loop") */
12011
+ .chat-panel__loop-spinner {
12012
+ display: inline-flex;
12013
+ align-items: center;
12014
+ padding: 2px 0;
12015
+ }
12016
+
12017
+ .chat-panel__loop-spinner svg {
12018
+ width: 20px;
12019
+ height: 20px;
12020
+ color: var(--color-accent-ai, #8b5cf6);
12021
+ animation: loop-spin 1.4s linear infinite;
12022
+ }
12023
+
12024
+ @keyframes loop-spin {
12025
+ 0% { transform: rotate(0deg); }
12026
+ 100% { transform: rotate(360deg); }
12027
+ }
12028
+
11835
12029
  /* Blinking cursor during streaming */
11836
12030
  .chat-panel__cursor {
11837
12031
  display: inline-block;
package/public/index.html CHANGED
@@ -61,6 +61,7 @@
61
61
 
62
62
  --color-accent-primary: #0969da;
63
63
  --color-accent-hover: #0860ca;
64
+ --color-accent-subtle: rgba(9, 105, 218, 0.04);
64
65
  --color-accent-emphasis: #238636;
65
66
  --color-accent-emphasis-hover: #2ea043;
66
67
 
@@ -94,6 +95,7 @@
94
95
 
95
96
  --color-accent-primary: #58a6ff;
96
97
  --color-accent-hover: #1f6feb;
98
+ --color-accent-subtle: rgba(56, 139, 253, 0.06);
97
99
  --color-accent-emphasis: #238636;
98
100
  --color-accent-emphasis-hover: #2ea043;
99
101
 
@@ -687,7 +689,7 @@
687
689
  margin-right: 4px;
688
690
  }
689
691
 
690
- .btn-delete-worktree,
692
+ .btn-delete-review,
691
693
  .btn-repo-settings {
692
694
  display: inline-flex;
693
695
  align-items: center;
@@ -703,13 +705,13 @@
703
705
  transition: all var(--transition-fast);
704
706
  }
705
707
 
706
- .btn-delete-worktree:hover {
708
+ .btn-delete-review:hover {
707
709
  background-color: rgba(208, 36, 47, 0.08);
708
710
  border-color: rgba(208, 36, 47, 0.3);
709
711
  color: var(--color-danger);
710
712
  }
711
713
 
712
- [data-theme="dark"] .btn-delete-worktree:hover {
714
+ [data-theme="dark"] .btn-delete-review:hover {
713
715
  background-color: rgba(248, 81, 73, 0.1);
714
716
  border-color: rgba(248, 81, 73, 0.3);
715
717
  }
@@ -1053,6 +1055,168 @@
1053
1055
  color: var(--color-text-primary);
1054
1056
  }
1055
1057
 
1058
+ /* ─── Selection Mode ─────────────────────────────────────── */
1059
+
1060
+ /* Select toggle button — matches .btn-refresh sizing */
1061
+ .btn-select-toggle {
1062
+ display: inline-flex;
1063
+ align-items: center;
1064
+ gap: 6px;
1065
+ padding: 4px 12px;
1066
+ font-family: var(--font-sans);
1067
+ font-size: 12px;
1068
+ font-weight: 500;
1069
+ color: var(--color-text-secondary);
1070
+ background: transparent;
1071
+ border: 1px solid var(--color-border-primary);
1072
+ border-radius: var(--radius-md);
1073
+ cursor: pointer;
1074
+ transition: all var(--transition-fast);
1075
+ }
1076
+
1077
+ .btn-select-toggle:hover {
1078
+ background: var(--color-bg-secondary);
1079
+ color: var(--color-text-primary);
1080
+ }
1081
+
1082
+ .btn-select-toggle.active {
1083
+ background: var(--color-accent-subtle);
1084
+ border-color: var(--color-accent-primary);
1085
+ color: var(--color-accent-primary);
1086
+ }
1087
+
1088
+ /* Checkbox column */
1089
+ .col-select {
1090
+ width: 32px;
1091
+ text-align: center;
1092
+ padding: 6px 8px !important;
1093
+ }
1094
+
1095
+ .col-select input[type="checkbox"] {
1096
+ width: 15px;
1097
+ height: 15px;
1098
+ cursor: pointer;
1099
+ accent-color: var(--color-accent-primary);
1100
+ vertical-align: middle;
1101
+ }
1102
+
1103
+ /* Selected row highlight */
1104
+ .recent-reviews-table tbody tr.bulk-selected td {
1105
+ background-color: var(--color-accent-subtle);
1106
+ }
1107
+
1108
+ /* Hide per-row delete buttons in selection mode */
1109
+ .selection-mode .btn-delete-review,
1110
+ .selection-mode .btn-delete-session {
1111
+ display: none;
1112
+ }
1113
+
1114
+ /* Inline bulk action controls — appear next to Select button */
1115
+ .bulk-inline-actions {
1116
+ display: inline-flex;
1117
+ align-items: center;
1118
+ gap: 8px;
1119
+ }
1120
+
1121
+ .bulk-action-count {
1122
+ font-size: 12px;
1123
+ font-weight: 500;
1124
+ color: var(--color-text-secondary);
1125
+ }
1126
+
1127
+ .bulk-action-buttons {
1128
+ display: inline-flex;
1129
+ gap: 6px;
1130
+ }
1131
+
1132
+ .btn-bulk-delete {
1133
+ padding: 4px 12px;
1134
+ font-size: 12px;
1135
+ font-weight: 500;
1136
+ background: var(--color-danger);
1137
+ color: #ffffff;
1138
+ border: none;
1139
+ border-radius: var(--radius-sm);
1140
+ cursor: pointer;
1141
+ }
1142
+
1143
+ .btn-bulk-delete:hover:not(:disabled) {
1144
+ background: var(--color-danger-hover);
1145
+ }
1146
+
1147
+ .btn-bulk-delete:disabled {
1148
+ opacity: 0.4;
1149
+ cursor: default;
1150
+ }
1151
+
1152
+ .btn-bulk-open,
1153
+ .btn-bulk-analyze {
1154
+ padding: 4px 12px;
1155
+ font-size: 12px;
1156
+ font-weight: 500;
1157
+ background: var(--color-accent-primary);
1158
+ color: #ffffff;
1159
+ border: none;
1160
+ border-radius: var(--radius-sm);
1161
+ cursor: pointer;
1162
+ }
1163
+
1164
+ .btn-bulk-open:hover:not(:disabled),
1165
+ .btn-bulk-analyze:hover:not(:disabled) {
1166
+ opacity: 0.9;
1167
+ }
1168
+
1169
+ .btn-bulk-open:disabled,
1170
+ .btn-bulk-analyze:disabled {
1171
+ opacity: 0.4;
1172
+ cursor: default;
1173
+ }
1174
+
1175
+ .btn-bulk-cancel {
1176
+ padding: 4px 12px;
1177
+ font-size: 12px;
1178
+ font-weight: 500;
1179
+ background: transparent;
1180
+ color: var(--color-text-secondary);
1181
+ border: 1px solid var(--color-border-primary);
1182
+ border-radius: var(--radius-sm);
1183
+ cursor: pointer;
1184
+ }
1185
+
1186
+ .btn-bulk-cancel:hover {
1187
+ background: var(--color-bg-secondary);
1188
+ color: var(--color-text-primary);
1189
+ }
1190
+
1191
+ /* Confirmation state — hide normal action buttons, show confirm buttons */
1192
+ .bulk-inline-actions .bulk-confirm-buttons {
1193
+ display: none;
1194
+ gap: 6px;
1195
+ }
1196
+
1197
+ .bulk-inline-actions.confirming .bulk-action-buttons {
1198
+ display: none;
1199
+ }
1200
+
1201
+ .bulk-inline-actions.confirming .bulk-confirm-buttons {
1202
+ display: inline-flex;
1203
+ }
1204
+
1205
+ .bulk-inline-actions.confirming > .btn-bulk-cancel {
1206
+ display: none;
1207
+ }
1208
+
1209
+ /* Select mode header row (between form and table, for PR/Local tabs) */
1210
+ .select-mode-header {
1211
+ display: none;
1212
+ justify-content: flex-end;
1213
+ padding: 0 0 8px 0;
1214
+ }
1215
+
1216
+ .select-mode-header.visible {
1217
+ display: flex;
1218
+ }
1219
+
1056
1220
  /* Start review section spacing inside unified tabs */
1057
1221
  .tab-pane .start-review-section {
1058
1222
  max-width: 100%;
@@ -1266,6 +1430,7 @@
1266
1430
  </div>
1267
1431
  </div>
1268
1432
 
1433
+ <script src="/js/components/Toast.js"></script>
1269
1434
  <script src="/js/index.js"></script>
1270
1435
  </body>
1271
1436
  </html>
@@ -1,4 +1,4 @@
1
- // SPDX-License-Identifier: GPL-3.0-or-later
1
+ // Copyright 2026 Tim Perkins (tjwp) | SPDX-License-Identifier: Apache-2.0
2
2
  /**
3
3
  * AIPanel.js - AI Analysis Panel Component
4
4
  * Manages the right sidebar panel that displays AI analysis findings
@@ -1000,7 +1000,14 @@ class AIPanel {
1000
1000
  }
1001
1001
 
1002
1002
  if (targetSuggestion) {
1003
- targetSuggestion.scrollIntoView({ behavior: 'smooth', block: 'center' });
1003
+ const minimizer = window.prManager?.commentMinimizer;
1004
+ if (minimizer?.active) {
1005
+ // Comments are minimized — scroll to the parent diff line instead
1006
+ const diffRow = minimizer.findDiffRowFor(targetSuggestion);
1007
+ (diffRow || targetSuggestion).scrollIntoView({ behavior: 'smooth', block: 'center' });
1008
+ } else {
1009
+ targetSuggestion.scrollIntoView({ behavior: 'smooth', block: 'center' });
1010
+ }
1004
1011
  targetSuggestion.classList.add('current-suggestion');
1005
1012
  setTimeout(() => targetSuggestion.classList.remove('current-suggestion'), 2000);
1006
1013
  }
@@ -1061,7 +1068,14 @@ class AIPanel {
1061
1068
  }
1062
1069
 
1063
1070
  if (targetElement) {
1064
- targetElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
1071
+ const minimizer = window.prManager?.commentMinimizer;
1072
+ if (minimizer?.active && !isFileLevel) {
1073
+ // Comments are minimized — scroll to the parent diff line instead
1074
+ const diffRow = minimizer.findDiffRowFor(targetElement);
1075
+ (diffRow || targetElement).scrollIntoView({ behavior: 'smooth', block: 'center' });
1076
+ } else {
1077
+ targetElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
1078
+ }
1065
1079
  // Add highlight effect
1066
1080
  const commentDiv = isFileLevel ? targetElement : targetElement.querySelector('.user-comment');
1067
1081
  if (commentDiv) {
@@ -1,4 +1,4 @@
1
- // SPDX-License-Identifier: GPL-3.0-or-later
1
+ // Copyright 2026 Tim Perkins (tjwp) | SPDX-License-Identifier: Apache-2.0
2
2
  /**
3
3
  * AI Summary Modal Component
4
4
  * Displays the AI-generated analysis summary with stats and copy functionality
@@ -1,4 +1,4 @@
1
- // SPDX-License-Identifier: GPL-3.0-or-later
1
+ // Copyright 2026 Tim Perkins (tjwp) | SPDX-License-Identifier: Apache-2.0
2
2
  /**
3
3
  * Advanced (Level-Centric) Council Configuration Tab
4
4
  *
@@ -1,4 +1,4 @@
1
- // SPDX-License-Identifier: GPL-3.0-or-later
1
+ // Copyright 2026 Tim Perkins (tjwp) | SPDX-License-Identifier: Apache-2.0
2
2
  /**
3
3
  * AI Analysis Configuration Modal Component
4
4
  * Displays model selection, custom instructions, and presets before analysis