@in-the-loop-labs/pair-review 2.3.3 → 2.4.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 (45) hide show
  1. package/.pi/skills/review-model-guidance/SKILL.md +1 -1
  2. package/.pi/skills/review-roulette/SKILL.md +1 -1
  3. package/README.md +15 -1
  4. package/package.json +2 -1
  5. package/plugin/.claude-plugin/plugin.json +1 -1
  6. package/plugin/skills/review-requests/SKILL.md +1 -1
  7. package/plugin-code-critic/.claude-plugin/plugin.json +1 -1
  8. package/public/css/pr.css +287 -14
  9. package/public/index.html +121 -57
  10. package/public/js/components/AIPanel.js +2 -1
  11. package/public/js/components/AdvancedConfigTab.js +2 -2
  12. package/public/js/components/AnalysisConfigModal.js +2 -2
  13. package/public/js/components/ChatPanel.js +187 -28
  14. package/public/js/components/CouncilProgressModal.js +4 -7
  15. package/public/js/components/SplitButton.js +66 -1
  16. package/public/js/components/VoiceCentricConfigTab.js +2 -2
  17. package/public/js/index.js +274 -21
  18. package/public/js/pr.js +194 -5
  19. package/public/local.html +8 -1
  20. package/public/pr.html +17 -2
  21. package/src/ai/codex-provider.js +14 -2
  22. package/src/ai/copilot-provider.js +1 -10
  23. package/src/ai/cursor-agent-provider.js +1 -10
  24. package/src/ai/gemini-provider.js +8 -17
  25. package/src/chat/acp-bridge.js +456 -0
  26. package/src/chat/api-reference.js +539 -0
  27. package/src/chat/chat-providers.js +290 -0
  28. package/src/chat/claude-code-bridge.js +499 -0
  29. package/src/chat/codex-bridge.js +601 -0
  30. package/src/chat/pi-bridge.js +56 -3
  31. package/src/chat/prompt-builder.js +12 -11
  32. package/src/chat/session-manager.js +110 -29
  33. package/src/config.js +4 -2
  34. package/src/database.js +50 -2
  35. package/src/github/client.js +43 -0
  36. package/src/routes/chat.js +60 -27
  37. package/src/routes/config.js +24 -1
  38. package/src/routes/github-collections.js +126 -0
  39. package/src/routes/mcp.js +2 -1
  40. package/src/routes/pr.js +166 -2
  41. package/src/routes/reviews.js +2 -1
  42. package/src/routes/shared.js +70 -49
  43. package/src/server.js +27 -1
  44. package/src/utils/safe-parse-json.js +19 -0
  45. package/.pi/skills/pair-review-api/SKILL.md +0 -448
@@ -78,7 +78,7 @@ Here are the higher-end models and their strengths for code review:
78
78
  files or functions.
79
79
 
80
80
  **Google**
81
- - **google/gemini-3-pro-preview**: Google's latest and most capable model (1M context).
81
+ - **google/gemini-3.1-pro-preview**: Google's latest and most capable model (1M context).
82
82
  Strong at cross-file analysis and understanding large codebases holistically.
83
83
  - **google/gemini-2.5-pro with thinking**: Excellent at large-context analysis — can
84
84
  reason over many files simultaneously with its 1M token context window. Good for
@@ -30,7 +30,7 @@ Example reasoning models you might see (provider/model format):
30
30
  - `openai/gpt-5.2-pro`
31
31
  - `google/gemini-2.5-pro` (with thinking)
32
32
  - `google/gemini-2.5-flash` (with thinking)
33
- - `google/gemini-3-pro-preview`
33
+ - `google/gemini-3.1-pro-preview`
34
34
  - `xai/grok-4`
35
35
 
36
36
  The exact list depends on which API keys are configured. Always check — do not
package/README.md CHANGED
@@ -248,7 +248,7 @@ pair-review loads configuration from multiple files, merged in order of increasi
248
248
  | 4 | `.pair-review/config.json` | Project-specific configuration (can be checked in) |
249
249
  | 5 (highest) | `.pair-review/config.local.json` | Personal project overrides (gitignored) |
250
250
 
251
- Nested objects (like `chat`, `providers`, `monorepos`) are deep-merged across layers — you only need to specify the keys you want to override.
251
+ Nested objects (like `chat`, `providers`, `chat_providers`, `monorepos`) are deep-merged across layers — you only need to specify the keys you want to override.
252
252
 
253
253
  **`config.local.json`** files are intended for personal overrides that should not be committed to version control. Add `config.local.json` to your `.gitignore`.
254
254
 
@@ -471,6 +471,20 @@ npm install -g @mariozechner/pi-coding-agent
471
471
 
472
472
  Configure your preferred models in `providers.pi.models` — see [AI Provider Configuration](#ai-provider-configuration) for details. Everything else in pair-review works without Pi installed.
473
473
 
474
+ **Chat provider command overrides:** To customize CLI commands for chat providers (e.g., to use a wrapper script), use the `chat_providers` config key:
475
+
476
+ ```json
477
+ {
478
+ "chat_providers": {
479
+ "claude": { "command": "devx", "args": ["claude", "--"] },
480
+ "codex": { "command": "devx", "args": ["codex", "--", "app-server"] },
481
+ "opencode-acp": { "command": "devx", "args": ["opencode", "acp"] }
482
+ }
483
+ }
484
+ ```
485
+
486
+ Available chat provider IDs: `pi`, `claude`, `codex`, `copilot-acp`, `gemini-acp`, `opencode-acp`, `cursor-acp`. Each supports `command`, `args` (replaces defaults), `extra_args` (appends), and `env` overrides.
487
+
474
488
  **Keyboard shortcut:** Press `p` then `c` to toggle the chat panel.
475
489
 
476
490
  ### Customization
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@in-the-loop-labs/pair-review",
3
- "version": "2.3.3",
3
+ "version": "2.4.1",
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": {
@@ -59,6 +59,7 @@
59
59
  },
60
60
  "homepage": "https://github.com/in-the-loop-labs/pair-review#readme",
61
61
  "dependencies": {
62
+ "@agentclientprotocol/sdk": "^0.14.1",
62
63
  "@modelcontextprotocol/sdk": "^1.25.3",
63
64
  "@octokit/rest": "^19.0.11",
64
65
  "better-sqlite3": "^11.8.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pair-review",
3
- "version": "2.3.3",
3
+ "version": "2.4.1",
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",
@@ -35,7 +35,7 @@ Each result provides `number`, `title`, `html_url`, and `repo` (as `owner/repo`)
35
35
 
36
36
  ### Phase 3: Open each PR in pair-review with auto-analysis
37
37
 
38
- **Limit**: Open at most **5** PRs. If more than 5 are found, open only the first 5 (most
38
+ **Limit**: Open at most **10** PRs. If more than 10 are found, open only the first 10 (most
39
39
  recently updated) and report how many were skipped.
40
40
 
41
41
  For each PR found (up to the limit), open it in the browser with the `?analyze=true` query parameter, which
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-critic",
3
- "version": "2.3.3",
3
+ "version": "2.4.1",
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",
package/public/css/pr.css CHANGED
@@ -5374,6 +5374,16 @@ tr.line-range-start .d2h-code-line-ctn {
5374
5374
  color: #1f883d;
5375
5375
  }
5376
5376
 
5377
+ .menu-item-icon {
5378
+ display: flex;
5379
+ align-items: center;
5380
+ margin-left: 8px;
5381
+ }
5382
+
5383
+ .menu-item-icon svg {
5384
+ /* vertical alignment handled by flex parent */
5385
+ }
5386
+
5377
5387
  .menu-item-text {
5378
5388
  flex: 1;
5379
5389
  }
@@ -5866,6 +5876,145 @@ body::before {
5866
5876
  text-align: center;
5867
5877
  }
5868
5878
 
5879
+ .pr-title-wrapper {
5880
+ display: flex;
5881
+ align-items: center;
5882
+ justify-content: center;
5883
+ gap: 2px;
5884
+ position: relative;
5885
+ }
5886
+
5887
+ .header .pr-description-toggle,
5888
+ [data-theme="dark"] .header .pr-description-toggle {
5889
+ flex-shrink: 0;
5890
+ background: transparent;
5891
+ border: none;
5892
+ color: var(--color-text-tertiary, #6e7681);
5893
+ opacity: 0.7;
5894
+ transition: opacity 0.15s ease, color 0.15s ease;
5895
+ }
5896
+
5897
+ .pr-description-toggle:hover {
5898
+ opacity: 1;
5899
+ color: var(--color-text-secondary, #8b949e);
5900
+ }
5901
+
5902
+ .pr-description-toggle.active {
5903
+ opacity: 1;
5904
+ color: var(--color-accent, #2f81f7);
5905
+ }
5906
+
5907
+ /* PR description popover */
5908
+ .pr-description-popover {
5909
+ position: absolute;
5910
+ top: calc(100% + 8px);
5911
+ left: 50%;
5912
+ transform: translateX(-50%);
5913
+ z-index: 1000;
5914
+ width: min(500px, 90vw);
5915
+ background: var(--color-bg-primary, #0d1117);
5916
+ border: 1px solid var(--color-border-primary, rgba(255, 255, 255, 0.1));
5917
+ border-radius: 8px;
5918
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4), 0 2px 8px rgba(0, 0, 0, 0.2);
5919
+ text-align: left;
5920
+ }
5921
+
5922
+ .pr-description-popover-arrow {
5923
+ position: absolute;
5924
+ top: -6px;
5925
+ left: 50%;
5926
+ margin-left: -6px;
5927
+ width: 12px;
5928
+ height: 12px;
5929
+ background: var(--color-bg-primary, #0d1117);
5930
+ border-top: 1px solid var(--color-border-primary, rgba(255, 255, 255, 0.1));
5931
+ border-left: 1px solid var(--color-border-primary, rgba(255, 255, 255, 0.1));
5932
+ transform: rotate(45deg);
5933
+ }
5934
+
5935
+ .pr-description-popover-header {
5936
+ display: flex;
5937
+ align-items: center;
5938
+ justify-content: space-between;
5939
+ padding: 8px 12px 8px 16px;
5940
+ border-bottom: 1px solid var(--color-border-secondary, rgba(255, 255, 255, 0.06));
5941
+ }
5942
+
5943
+ .pr-description-popover-title {
5944
+ font-size: 0.75rem;
5945
+ font-weight: 600;
5946
+ color: var(--color-text-primary, #e6edf3);
5947
+ text-transform: uppercase;
5948
+ letter-spacing: 0.05em;
5949
+ }
5950
+
5951
+ .pr-description-popover-close {
5952
+ display: flex;
5953
+ align-items: center;
5954
+ justify-content: center;
5955
+ width: 24px;
5956
+ height: 24px;
5957
+ padding: 0;
5958
+ border: none;
5959
+ border-radius: 4px;
5960
+ background: transparent;
5961
+ color: var(--color-text-tertiary, #6e7681);
5962
+ cursor: pointer;
5963
+ transition: all 0.15s ease;
5964
+ }
5965
+
5966
+ .pr-description-popover-close:hover {
5967
+ color: var(--color-text-secondary, #8b949e);
5968
+ background: var(--color-bg-tertiary, rgba(255, 255, 255, 0.04));
5969
+ }
5970
+
5971
+ .pr-description-popover-content {
5972
+ padding: 12px 16px;
5973
+ font-size: 0.8125rem;
5974
+ line-height: 1.6;
5975
+ color: var(--color-text-secondary, #8b949e);
5976
+ max-height: calc(60vh - 40px);
5977
+ overflow-y: auto;
5978
+ }
5979
+
5980
+ .pr-description-popover-content p {
5981
+ margin: 0 0 8px;
5982
+ }
5983
+
5984
+ .pr-description-popover-content p:last-child {
5985
+ margin-bottom: 0;
5986
+ }
5987
+
5988
+ .pr-description-popover-content ul,
5989
+ .pr-description-popover-content ol {
5990
+ margin: 4px 0 8px;
5991
+ padding-left: 20px;
5992
+ }
5993
+
5994
+ .pr-description-popover-content li {
5995
+ margin: 2px 0;
5996
+ }
5997
+
5998
+ .pr-description-popover-content code {
5999
+ padding: 2px 6px;
6000
+ background: var(--color-bg-tertiary, rgba(255, 255, 255, 0.04));
6001
+ border-radius: 3px;
6002
+ font-size: 0.75rem;
6003
+ }
6004
+
6005
+ .pr-description-popover-content pre {
6006
+ margin: 8px 0;
6007
+ padding: 8px 12px;
6008
+ background: var(--color-bg-tertiary, rgba(255, 255, 255, 0.04));
6009
+ border-radius: 6px;
6010
+ overflow-x: auto;
6011
+ }
6012
+
6013
+ .pr-description-popover-content pre code {
6014
+ padding: 0;
6015
+ background: none;
6016
+ }
6017
+
5869
6018
  .header-center .pr-title {
5870
6019
  font-size: 1rem;
5871
6020
  font-weight: 500;
@@ -10906,17 +11055,17 @@ body.resizing * {
10906
11055
  background: linear-gradient(to bottom, var(--chat-subtle), transparent);
10907
11056
  flex-shrink: 0;
10908
11057
  }
10909
- /* Session picker wrapper */
10910
- .chat-panel__session-picker {
11058
+ /* Provider picker */
11059
+ .chat-panel__provider-picker {
10911
11060
  position: relative;
10912
11061
  flex: 1;
10913
11062
  min-width: 0;
10914
11063
  }
10915
11064
 
10916
- .chat-panel__session-picker-btn {
11065
+ .chat-panel__provider-picker-btn {
10917
11066
  display: flex;
10918
11067
  align-items: center;
10919
- gap: 8px;
11068
+ gap: 6px;
10920
11069
  font-size: 13px;
10921
11070
  font-weight: 600;
10922
11071
  color: var(--chat-text);
@@ -10929,11 +11078,11 @@ body.resizing * {
10929
11078
  max-width: 100%;
10930
11079
  }
10931
11080
 
10932
- .chat-panel__session-picker-btn:hover {
11081
+ .chat-panel__provider-picker-btn:hover {
10933
11082
  background: var(--color-bg-tertiary, rgba(128, 128, 128, 0.1));
10934
11083
  }
10935
11084
 
10936
- .chat-panel__session-picker-btn svg:first-child {
11085
+ .chat-panel__provider-picker-btn svg:first-child {
10937
11086
  color: var(--chat-primary);
10938
11087
  flex-shrink: 0;
10939
11088
  }
@@ -10944,18 +11093,18 @@ body.resizing * {
10944
11093
  white-space: nowrap;
10945
11094
  }
10946
11095
 
10947
- .chat-panel__chevron-sep {
10948
- opacity: 0.4;
10949
- font-size: 13px;
10950
- }
10951
-
10952
- .chat-panel__chevron {
11096
+ .chat-panel__provider-chevron {
10953
11097
  flex-shrink: 0;
10954
11098
  opacity: 0.5;
11099
+ transition: transform 0.15s ease;
10955
11100
  }
10956
11101
 
10957
- /* Session dropdown flyout */
10958
- .chat-panel__session-dropdown {
11102
+ .chat-panel__provider-picker-btn--open .chat-panel__provider-chevron {
11103
+ transform: rotate(180deg);
11104
+ }
11105
+
11106
+ /* Provider dropdown */
11107
+ .chat-panel__provider-dropdown {
10959
11108
  position: absolute;
10960
11109
  top: calc(100% + 4px);
10961
11110
  left: 0;
@@ -10970,6 +11119,72 @@ body.resizing * {
10970
11119
  padding: 4px;
10971
11120
  }
10972
11121
 
11122
+ .chat-panel__provider-empty {
11123
+ padding: 16px;
11124
+ text-align: center;
11125
+ color: var(--color-text-tertiary);
11126
+ font-size: 12px;
11127
+ }
11128
+
11129
+ .chat-panel__provider-item {
11130
+ display: flex;
11131
+ align-items: center;
11132
+ justify-content: space-between;
11133
+ width: 100%;
11134
+ padding: 8px 12px;
11135
+ border: none;
11136
+ background: transparent;
11137
+ text-align: left;
11138
+ border-radius: 6px;
11139
+ cursor: pointer;
11140
+ transition: background 0.15s ease;
11141
+ font-size: 13px;
11142
+ color: var(--color-text-primary, #1f2328);
11143
+ }
11144
+
11145
+ .chat-panel__provider-item:hover:not([disabled]) {
11146
+ background: var(--color-bg-tertiary, rgba(128, 128, 128, 0.08));
11147
+ }
11148
+
11149
+ .chat-panel__provider-item--active {
11150
+ background: var(--color-bg-secondary, #f6f8fa);
11151
+ }
11152
+
11153
+ .chat-panel__provider-item--unavailable {
11154
+ opacity: 0.5;
11155
+ cursor: default;
11156
+ }
11157
+
11158
+ .chat-panel__provider-name {
11159
+ overflow: hidden;
11160
+ text-overflow: ellipsis;
11161
+ white-space: nowrap;
11162
+ }
11163
+
11164
+ .chat-panel__provider-check {
11165
+ flex-shrink: 0;
11166
+ color: var(--chat-primary, #0969da);
11167
+ }
11168
+
11169
+ /* Session picker wrapper (dropdown container) */
11170
+ .chat-panel__session-picker {
11171
+ position: relative;
11172
+ }
11173
+
11174
+ /* Session dropdown flyout — uses position:fixed to escape chat-panel overflow:hidden */
11175
+ .chat-panel__session-dropdown {
11176
+ position: fixed;
11177
+ width: 320px;
11178
+ background: var(--color-bg-primary, #fff);
11179
+ border: 1px solid var(--color-border-primary, #d0d7de);
11180
+ border-radius: 8px;
11181
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
11182
+ max-height: 300px;
11183
+ overflow-y: auto;
11184
+ z-index: 1000;
11185
+ padding: 4px;
11186
+ }
11187
+
10973
11188
  .chat-panel__session-empty {
10974
11189
  padding: 16px;
10975
11190
  text-align: center;
@@ -11025,6 +11240,24 @@ body.resizing * {
11025
11240
  color: var(--color-text-tertiary, #656d76);
11026
11241
  }
11027
11242
 
11243
+ .chat-panel__session-provider {
11244
+ display: inline-block;
11245
+ font-size: 10px;
11246
+ font-weight: 500;
11247
+ color: var(--color-text-secondary, #59636e);
11248
+ background: var(--color-bg-tertiary, rgba(128, 128, 128, 0.08));
11249
+ border-radius: 3px;
11250
+ padding: 0 4px;
11251
+ margin-right: 6px;
11252
+ line-height: 16px;
11253
+ vertical-align: baseline;
11254
+ }
11255
+
11256
+ [data-theme="dark"] .chat-panel__session-provider {
11257
+ color: var(--color-text-secondary, #8b949e);
11258
+ background: rgba(128, 128, 128, 0.15);
11259
+ }
11260
+
11028
11261
  /* Dark theme overrides */
11029
11262
  [data-theme="dark"] .chat-panel__session-dropdown {
11030
11263
  background: var(--color-bg-primary, #0d1117);
@@ -11040,6 +11273,46 @@ body.resizing * {
11040
11273
  color: var(--color-text-primary, #e6edf3);
11041
11274
  }
11042
11275
 
11276
+ /* Dark theme: provider dropdown */
11277
+ [data-theme="dark"] .chat-panel__provider-dropdown {
11278
+ background: var(--color-bg-primary, #0d1117);
11279
+ border-color: var(--color-border-primary, #30363d);
11280
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
11281
+ }
11282
+
11283
+ [data-theme="dark"] .chat-panel__provider-item {
11284
+ color: var(--color-text-primary, #e6edf3);
11285
+ }
11286
+
11287
+ [data-theme="dark"] .chat-panel__provider-item--active {
11288
+ background: var(--color-bg-secondary, #161b22);
11289
+ }
11290
+
11291
+ /* History button (icon-only, in actions) */
11292
+ .chat-panel__history-btn {
11293
+ display: flex;
11294
+ align-items: center;
11295
+ justify-content: center;
11296
+ width: 28px;
11297
+ height: 28px;
11298
+ border: none;
11299
+ background: transparent;
11300
+ color: var(--color-text-tertiary);
11301
+ border-radius: 6px;
11302
+ cursor: pointer;
11303
+ transition: background 0.15s ease, color 0.15s ease;
11304
+ }
11305
+
11306
+ .chat-panel__history-btn:hover {
11307
+ background: var(--color-bg-tertiary);
11308
+ color: var(--color-text-primary);
11309
+ }
11310
+
11311
+ .chat-panel__history-btn--open {
11312
+ background: var(--color-bg-tertiary);
11313
+ color: var(--color-text-primary);
11314
+ }
11315
+
11043
11316
  .chat-panel__actions {
11044
11317
  display: flex;
11045
11318
  align-items: center;
package/public/index.html CHANGED
@@ -542,55 +542,6 @@
542
542
  to { transform: rotate(360deg); }
543
543
  }
544
544
 
545
- /* Usage Info (shown when no reviews) */
546
- .usage-info {
547
- background-color: var(--color-bg-primary);
548
- border: 1px solid var(--color-border-primary);
549
- border-radius: var(--radius-lg);
550
- padding: 24px;
551
- text-align: left;
552
- max-width: 600px;
553
- width: 100%;
554
- margin-bottom: 32px;
555
- }
556
-
557
- .usage-info h3 {
558
- font-size: 16px;
559
- font-weight: 600;
560
- margin-bottom: 16px;
561
- color: var(--color-text-primary);
562
- }
563
-
564
- .usage-info p {
565
- color: var(--color-text-secondary);
566
- margin-bottom: 12px;
567
- }
568
-
569
- .usage-info code {
570
- background-color: var(--color-bg-secondary);
571
- padding: 2px 6px;
572
- border-radius: var(--radius-sm);
573
- font-family: var(--font-mono);
574
- font-size: 13px;
575
- }
576
-
577
- .usage-info pre {
578
- background-color: var(--color-bg-tertiary);
579
- color: var(--color-text-primary);
580
- padding: 16px;
581
- border-radius: var(--radius-md);
582
- margin: 12px 0;
583
- overflow-x: auto;
584
- font-family: var(--font-mono);
585
- font-size: 13px;
586
- line-height: 1.5;
587
- }
588
-
589
- .usage-info pre code {
590
- background: none;
591
- padding: 0;
592
- }
593
-
594
545
  /* Recent Reviews Section */
595
546
  .recent-reviews-section {
596
547
  width: 100%;
@@ -754,6 +705,28 @@
754
705
  color: var(--color-text-primary);
755
706
  }
756
707
 
708
+ .btn-github-link {
709
+ display: inline-flex;
710
+ align-items: center;
711
+ justify-content: center;
712
+ width: 32px;
713
+ height: 32px;
714
+ padding: 0;
715
+ background: transparent;
716
+ border: 1px solid transparent;
717
+ border-radius: var(--radius-md);
718
+ color: var(--color-text-tertiary);
719
+ cursor: pointer;
720
+ transition: all var(--transition-fast);
721
+ text-decoration: none;
722
+ }
723
+
724
+ .btn-github-link:hover {
725
+ background-color: var(--color-bg-secondary);
726
+ border-color: var(--color-border-primary);
727
+ color: var(--color-text-primary);
728
+ }
729
+
757
730
  .recent-reviews-empty {
758
731
  text-align: center;
759
732
  padding: 40px 20px;
@@ -870,6 +843,76 @@
870
843
  display: block;
871
844
  }
872
845
 
846
+ .tab-divider {
847
+ width: 1px;
848
+ height: 16px;
849
+ background: var(--color-border-secondary);
850
+ align-self: center;
851
+ margin: 0 4px;
852
+ }
853
+
854
+ .tab-pane-header {
855
+ display: flex;
856
+ justify-content: flex-end;
857
+ align-items: center;
858
+ gap: 8px;
859
+ margin-bottom: 12px;
860
+ }
861
+
862
+ .fetched-at-label {
863
+ font-size: 12px;
864
+ color: var(--color-fg-muted);
865
+ }
866
+
867
+ .btn-refresh {
868
+ display: inline-flex;
869
+ align-items: center;
870
+ justify-content: center;
871
+ width: 32px;
872
+ height: 32px;
873
+ padding: 0;
874
+ background: transparent;
875
+ border: 1px solid var(--color-border-primary);
876
+ border-radius: var(--radius-md);
877
+ color: var(--color-text-tertiary);
878
+ cursor: pointer;
879
+ transition: all var(--transition-fast);
880
+ }
881
+
882
+ .btn-refresh:hover {
883
+ background: var(--color-bg-secondary);
884
+ color: var(--color-text-primary);
885
+ }
886
+
887
+ .btn-refresh.refreshing {
888
+ pointer-events: none;
889
+ opacity: 0.6;
890
+ }
891
+
892
+ .btn-refresh.refreshing svg {
893
+ animation: spin 0.8s linear infinite;
894
+ }
895
+
896
+ .collection-pr-row {
897
+ cursor: pointer;
898
+ }
899
+
900
+ .collection-pr-row:hover {
901
+ background: var(--color-bg-secondary);
902
+ }
903
+
904
+ .collection-pr-number {
905
+ color: var(--ai-primary);
906
+ font-weight: 500;
907
+ font-family: var(--font-mono);
908
+ cursor: pointer;
909
+ }
910
+
911
+ .collection-pr-number:hover {
912
+ color: var(--ai-secondary);
913
+ text-decoration: underline;
914
+ }
915
+
873
916
  /* Local Reviews Table - tighter spacing */
874
917
  .recent-reviews-table.local-table th,
875
918
  .recent-reviews-table.local-table td {
@@ -1021,10 +1064,6 @@
1021
1064
  width: 100%;
1022
1065
  }
1023
1066
 
1024
- .usage-info {
1025
- padding: 20px;
1026
- }
1027
-
1028
1067
  .recent-reviews-table {
1029
1068
  font-size: 13px;
1030
1069
  }
@@ -1073,6 +1112,9 @@
1073
1112
  <div class="section-header" id="recent-reviews-header">
1074
1113
  <div class="tab-bar" id="unified-tab-bar">
1075
1114
  <button class="tab-btn active" data-tab="pr-tab" type="button">Pull Requests</button>
1115
+ <button class="tab-btn" data-tab="review-requests-tab" type="button">My Review Requests</button>
1116
+ <button class="tab-btn" data-tab="my-prs-tab" type="button">My PRs</button>
1117
+ <span class="tab-divider"></span>
1076
1118
  <button class="tab-btn" data-tab="local-tab" type="button">Local Reviews</button>
1077
1119
  </div>
1078
1120
  </div>
@@ -1104,6 +1146,32 @@
1104
1146
  </div>
1105
1147
  </div>
1106
1148
 
1149
+ <!-- My Review Requests Tab -->
1150
+ <div class="tab-pane" id="review-requests-tab">
1151
+ <div class="tab-pane-header">
1152
+ <span class="fetched-at-label" id="review-requests-fetched-at"></span>
1153
+ <button class="btn-refresh" id="refresh-review-requests" title="Refresh from GitHub">
1154
+ <svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor"><path d="M1.705 8.005a.75.75 0 0 1 .834.656 5.5 5.5 0 0 0 9.592 2.97l-1.204-1.204a.25.25 0 0 1 .177-.427h3.646a.25.25 0 0 1 .25.25v3.646a.25.25 0 0 1-.427.177l-1.38-1.38A7.002 7.002 0 0 1 1.05 8.84a.75.75 0 0 1 .656-.834ZM8 2.5a5.487 5.487 0 0 0-4.131 1.869l1.204 1.204A.25.25 0 0 1 4.896 6H1.25A.25.25 0 0 1 1 5.75V2.104a.25.25 0 0 1 .427-.177l1.38 1.38A7.002 7.002 0 0 1 14.95 7.16a.75.75 0 0 1-1.49.178A5.5 5.5 0 0 0 8 2.5Z"/></svg>
1155
+ </button>
1156
+ </div>
1157
+ <div id="review-requests-container" class="recent-reviews-loading">
1158
+ Loading...
1159
+ </div>
1160
+ </div>
1161
+
1162
+ <!-- My PRs Tab -->
1163
+ <div class="tab-pane" id="my-prs-tab">
1164
+ <div class="tab-pane-header">
1165
+ <span class="fetched-at-label" id="my-prs-fetched-at"></span>
1166
+ <button class="btn-refresh" id="refresh-my-prs" title="Refresh from GitHub">
1167
+ <svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor"><path d="M1.705 8.005a.75.75 0 0 1 .834.656 5.5 5.5 0 0 0 9.592 2.97l-1.204-1.204a.25.25 0 0 1 .177-.427h3.646a.25.25 0 0 1 .25.25v3.646a.25.25 0 0 1-.427.177l-1.38-1.38A7.002 7.002 0 0 1 1.05 8.84a.75.75 0 0 1 .656-.834ZM8 2.5a5.487 5.487 0 0 0-4.131 1.869l1.204 1.204A.25.25 0 0 1 4.896 6H1.25A.25.25 0 0 1 1 5.75V2.104a.25.25 0 0 1 .427-.177l1.38 1.38A7.002 7.002 0 0 1 14.95 7.16a.75.75 0 0 1-1.49.178A5.5 5.5 0 0 0 8 2.5Z"/></svg>
1168
+ </button>
1169
+ </div>
1170
+ <div id="my-prs-container" class="recent-reviews-loading">
1171
+ Loading...
1172
+ </div>
1173
+ </div>
1174
+
1107
1175
  <!-- Local Reviews Tab: Input + Listing -->
1108
1176
  <div class="tab-pane" id="local-tab">
1109
1177
  <div class="start-review-section">
@@ -1134,10 +1202,6 @@
1134
1202
  </div>
1135
1203
  </div>
1136
1204
  </div>
1137
-
1138
- <!-- Usage Info (shown when no reviews, hidden initially during loading) -->
1139
- <!-- Content is populated from help modal via JS to avoid duplication -->
1140
- <div class="usage-info loading-hidden" id="usage-info"></div>
1141
1205
  </div>
1142
1206
  </main>
1143
1207
  </div>
@@ -1432,7 +1432,8 @@ class AIPanel {
1432
1432
  */
1433
1433
  clearAllFindings() {
1434
1434
  this.findings = [];
1435
- this.comments = [];
1435
+ // NOTE: Do NOT clear this.comments here. User comments are independent
1436
+ // of AI analysis and must persist across analysis runs.
1436
1437
  this.currentIndex = -1; // Reset navigation
1437
1438
  this.updateSegmentCounts();
1438
1439
  this.renderFindings();