@in-the-loop-labs/pair-review 3.2.2 → 3.3.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 (46) hide show
  1. package/README.md +7 -6
  2. package/package.json +5 -4
  3. package/plugin/.claude-plugin/plugin.json +1 -1
  4. package/plugin-code-critic/.claude-plugin/plugin.json +1 -1
  5. package/plugin-code-critic/skills/analyze/references/orchestration-balanced.md +9 -1
  6. package/plugin-code-critic/skills/analyze/references/orchestration-fast.md +8 -1
  7. package/plugin-code-critic/skills/analyze/references/orchestration-thorough.md +8 -7
  8. package/public/css/repo-settings.css +347 -0
  9. package/public/index.html +46 -9
  10. package/public/js/components/AIPanel.js +79 -37
  11. package/public/js/components/DiffOptionsDropdown.js +84 -1
  12. package/public/js/index.js +31 -6
  13. package/public/js/modules/analysis-history.js +11 -7
  14. package/public/js/pr.js +22 -0
  15. package/public/js/repo-settings.js +334 -6
  16. package/public/repo-settings.html +29 -0
  17. package/src/ai/analyzer.js +28 -19
  18. package/src/ai/claude-cli.js +2 -0
  19. package/src/ai/claude-provider.js +4 -1
  20. package/src/ai/prompts/baseline/consolidation/balanced.js +6 -4
  21. package/src/ai/prompts/baseline/consolidation/fast.js +6 -2
  22. package/src/ai/prompts/baseline/consolidation/thorough.js +7 -6
  23. package/src/ai/prompts/baseline/orchestration/balanced.js +13 -1
  24. package/src/ai/prompts/baseline/orchestration/fast.js +12 -1
  25. package/src/ai/prompts/baseline/orchestration/thorough.js +8 -7
  26. package/src/ai/provider.js +7 -6
  27. package/src/chat/session-manager.js +6 -3
  28. package/src/config.js +230 -38
  29. package/src/database.js +766 -38
  30. package/src/git/worktree-pool-lifecycle.js +674 -0
  31. package/src/git/worktree-pool-usage.js +216 -0
  32. package/src/git/worktree.js +46 -13
  33. package/src/main.js +185 -26
  34. package/src/routes/analyses.js +48 -26
  35. package/src/routes/chat.js +27 -3
  36. package/src/routes/config.js +17 -5
  37. package/src/routes/executable-analysis.js +38 -19
  38. package/src/routes/local.js +19 -6
  39. package/src/routes/mcp.js +13 -2
  40. package/src/routes/pr.js +72 -29
  41. package/src/routes/setup.js +41 -4
  42. package/src/routes/stack-analysis.js +29 -10
  43. package/src/routes/worktrees.js +294 -9
  44. package/src/server.js +20 -3
  45. package/src/setup/pr-setup.js +161 -27
  46. package/src/ws/server.js +51 -1
package/README.md CHANGED
@@ -746,28 +746,29 @@ These commands update your MCP configuration in `~/.claude/settings.json` (user-
746
746
  ### Prerequisites
747
747
 
748
748
  - Node.js 20.0.0 or higher
749
+ - [pnpm](https://pnpm.io/) 10.x
749
750
  - Git
750
751
 
751
752
  ### Running Locally
752
753
 
753
754
  ```bash
754
755
  # Install dependencies
755
- npm install
756
+ pnpm install
756
757
 
757
758
  # Run tests
758
- npm test
759
+ pnpm test
759
760
 
760
761
  # Run tests in watch mode
761
- npm run test:watch
762
+ pnpm run test:watch
762
763
 
763
764
  # Run E2E tests
764
- npm run test:e2e
765
+ pnpm run test:e2e
765
766
 
766
767
  # Run E2E tests with visible browser
767
- npm run test:e2e:headed
768
+ pnpm run test:e2e:headed
768
769
 
769
770
  # Start development server
770
- npm run dev
771
+ pnpm run dev
771
772
  ```
772
773
 
773
774
  ### Architecture
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@in-the-loop-labs/pair-review",
3
- "version": "3.2.2",
3
+ "version": "3.3.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": {
@@ -32,8 +32,8 @@
32
32
  "test:e2e:debug": "playwright test --debug",
33
33
  "generate:skill-prompts": "node scripts/generate-skill-prompts.js",
34
34
  "changeset": "changeset",
35
- "version": "changeset version && npm install --package-lock-only && node scripts/sync-plugin-versions.js && git add package.json package-lock.json CHANGELOG.md .changeset .claude-plugin/marketplace.json plugin/.claude-plugin/plugin.json plugin-code-critic/.claude-plugin/plugin.json && git commit -m \"RELEASING: v$(node -p \"require('./package.json').version\")\"",
36
- "release": "npm whoami > /dev/null || { echo 'Error: Not logged in to npm. Run: npm login'; exit 1; } && npm run version && changeset tag && npm publish && git push && git push --tags"
35
+ "version": "changeset version && pnpm install --lockfile-only && node scripts/sync-plugin-versions.js && git add package.json pnpm-lock.yaml CHANGELOG.md .changeset .claude-plugin/marketplace.json plugin/.claude-plugin/plugin.json plugin-code-critic/.claude-plugin/plugin.json && git commit -m \"RELEASING: v$(node -p \"require('./package.json').version\")\"",
36
+ "release": "npm whoami > /dev/null || { echo 'Error: Not logged in to npm. Run: npm login'; exit 1; } && pnpm run version && changeset tag && npm publish && git push && git push --tags"
37
37
  },
38
38
  "keywords": [
39
39
  "code-review",
@@ -71,7 +71,8 @@
71
71
  "simple-git": "^3.19.1",
72
72
  "update-notifier": "^5.1.0",
73
73
  "uuid": "^11.1.0",
74
- "ws": "^8.19.0"
74
+ "ws": "^8.19.0",
75
+ "zod": "^4.3.6"
75
76
  },
76
77
  "devDependencies": {
77
78
  "@changesets/cli": "^2.29.8",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pair-review",
3
- "version": "3.2.2",
3
+ "version": "3.3.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",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-critic",
3
- "version": "3.2.2",
3
+ "version": "3.3.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",
@@ -97,6 +97,14 @@ Prioritize suggestions in this order:
97
97
  - **Preserve reviewer autonomy** - you're a pair programming partner, not an enforcer
98
98
  - **Provide context** for why each suggestion matters to the reviewer
99
99
 
100
+ ## Summary Structure
101
+ The summary field should synthesize the findings, but it should not be one big paragraph.
102
+ - Start with 1-2 sentences describing the overall assessment
103
+ - Then include a markdown bullet list using "- " bullets for the key specific points
104
+ - After the bullets, add extra sentences or short paragraphs only when needed for requested context or follow-up detail
105
+ - Focus on WHAT was found, not HOW it was found
106
+ - Write as if a single reviewer produced this analysis
107
+
100
108
  ## Output Format
101
109
 
102
110
  **>>> CRITICAL: Output ONLY valid JSON. No markdown, no ```json blocks. Start with { end with }. <<<**
@@ -126,7 +134,7 @@ Output JSON with this structure:
126
134
  "confidence": 0.0-1.0,
127
135
  "reasoning": ["Step-by-step reasoning explaining why this issue was flagged (optional)"]
128
136
  }],
129
- "summary": "Brief summary of the key findings and their significance to the reviewer. Focus on WHAT was found, not HOW it was found. Do NOT mention 'orchestration', 'levels', 'merged from Level 1/2/3' etc. Write as if a single reviewer produced this analysis."
137
+ "summary": "Formatted markdown summary following the Summary Structure guidance above."
130
138
  }
131
139
 
132
140
  ### GitHub Suggestion Syntax
@@ -76,6 +76,13 @@ Max 2-3 praise items. Prefer line-level over file-level. Include actionable sugg
76
76
  ### Framing
77
77
  Use "Consider...", "Worth noting..." - guidance not mandates.
78
78
 
79
+ ### Summary
80
+ The summary field should be markdown, not one big paragraph.
81
+ - Start with 1-2 sentences describing the overall assessment
82
+ - Then include a markdown bullet list using "- " bullets for the key specific points
83
+ - After the bullets, add extra sentences or short paragraphs only when needed for requested context or follow-up detail
84
+ - Write as a single reviewer; do not mention levels or orchestration
85
+
79
86
  ## JSON Schema
80
87
  {
81
88
  "level": "orchestrated",
@@ -99,7 +106,7 @@ Use "Consider...", "Worth noting..." - guidance not mandates.
99
106
  "suggestion": "How to fix (omit for praise)",
100
107
  "confidence": 0.0-1.0
101
108
  }],
102
- "summary": "Key findings as if from single reviewer (no mention of levels/orchestration)"
109
+ "summary": "Formatted markdown summary following the Summary guidance above."
103
110
  }
104
111
 
105
112
  ### GitHub Suggestion Syntax
@@ -212,20 +212,21 @@ Frame all suggestions as guidance for a human reviewer, not automated mandates:
212
212
  Note: Confidence is about certainty of value, not severity. A minor improvement suggestion can have high confidence if you're sure it's helpful.
213
213
 
214
214
  ## Summary Synthesis Guidance
215
- The summary field is not a list of findings - it's a synthesis that helps the reviewer see the forest, not just the trees.
215
+ The summary field should help the reviewer see the forest, not just the trees, but it should not be one big paragraph.
216
216
 
217
217
  **Effective Summary Approach:**
218
- - **Synthesize, don't summarize**: Identify the overarching narrative of this PR's quality and concerns
219
- - **Lead with the most important insight**: What single thing should the reviewer understand first?
220
- - **Connect the dots**: How do individual findings relate to each other or to a common theme?
221
- - **Calibrate severity**: Is this PR fundamentally sound with minor issues, or does it have structural problems?
218
+ - **Start with 1-2 sentences of overall assessment**: Identify the overarching narrative of this PR's quality and concerns
219
+ - **Then use a markdown bullet list with "- " bullets**: Capture the key specific points the reviewer should track
220
+ - **Connect the dots**: Make the overview and bullets feel like one coherent review
221
+ - **Calibrate severity**: Make clear whether this PR is fundamentally sound with minor issues or has structural problems
222
+ - **After the bullets, add extra sentences or short paragraphs only when needed**: Use them for requested context, caveats, or follow-up detail
222
223
  - **Respect reviewer time**: A good summary lets the reviewer decide where to focus attention
223
224
 
224
225
  **Summary Anti-patterns to Avoid:**
225
226
  - Listing findings ("Found 3 bugs, 2 improvements, 1 praise...")
226
227
  - Implementation details ("Merged Level 1 and Level 2 suggestions...")
227
228
  - Vague platitudes ("This PR has some issues to consider...")
228
- - Excessive length (2-3 sentences is ideal)
229
+ - A single unbroken paragraph with no bullets
229
230
 
230
231
  ## Output Format
231
232
 
@@ -256,7 +257,7 @@ Output JSON with this structure:
256
257
  "confidence": 0.0-1.0,
257
258
  "reasoning": ["Step-by-step reasoning explaining why this issue was flagged"]
258
259
  }],
259
- "summary": "Brief summary of the key findings and their significance to the reviewer. Focus on WHAT was found, not HOW it was found. Do NOT mention 'orchestration', 'levels', 'merged from Level 1/2/3' etc. Write as if a single reviewer produced this analysis."
260
+ "summary": "Formatted markdown summary following the Summary Synthesis Guidance above."
260
261
  }
261
262
 
262
263
  ### GitHub Suggestion Syntax
@@ -893,6 +893,331 @@ html, body {
893
893
  font-size: 12px;
894
894
  }
895
895
 
896
+ /* ============================================
897
+ Worktrees Section
898
+ ============================================ */
899
+
900
+ @keyframes worktree-spin {
901
+ from { transform: rotate(0deg); }
902
+ to { transform: rotate(360deg); }
903
+ }
904
+
905
+ .worktree-icon-spin {
906
+ animation: worktree-spin 1s linear infinite;
907
+ }
908
+
909
+ .worktree-pool-config {
910
+ display: flex;
911
+ flex-direction: column;
912
+ gap: 12px;
913
+ padding: 12px 16px;
914
+ background: var(--color-bg-primary);
915
+ border: 1px solid var(--color-border-primary);
916
+ border-radius: 8px;
917
+ }
918
+
919
+ .worktree-pool-config-items {
920
+ display: flex;
921
+ align-items: flex-end;
922
+ gap: 24px;
923
+ }
924
+
925
+ .worktree-pool-config-item {
926
+ display: flex;
927
+ flex-direction: column;
928
+ gap: 4px;
929
+ }
930
+
931
+ .worktree-pool-config-label {
932
+ font-size: 11px;
933
+ color: var(--color-text-muted);
934
+ text-transform: uppercase;
935
+ letter-spacing: 0.04em;
936
+ }
937
+
938
+ .worktree-pool-input-group {
939
+ display: flex;
940
+ align-items: center;
941
+ gap: 6px;
942
+ }
943
+
944
+ .worktree-pool-input {
945
+ width: 72px;
946
+ padding: 4px 8px;
947
+ font-size: 14px;
948
+ color: var(--color-text-primary);
949
+ background: var(--color-bg-secondary);
950
+ border: 1px solid var(--color-border-primary);
951
+ border-radius: 6px;
952
+ outline: none;
953
+ transition: border-color 0.15s ease;
954
+ }
955
+
956
+ .worktree-pool-input:focus {
957
+ border-color: var(--color-accent-primary);
958
+ box-shadow: 0 0 0 2px rgba(var(--color-accent-primary-rgb, 31, 111, 235), 0.15);
959
+ }
960
+
961
+ .worktree-pool-input::placeholder {
962
+ color: var(--color-text-muted);
963
+ }
964
+
965
+ .worktree-pool-input-note {
966
+ font-size: 12px;
967
+ color: var(--color-text-muted);
968
+ }
969
+
970
+ .worktree-list {
971
+ display: flex;
972
+ flex-direction: column;
973
+ gap: 8px;
974
+ margin-top: 16px;
975
+ }
976
+
977
+ .worktree-item {
978
+ display: flex;
979
+ flex-direction: column;
980
+ gap: 6px;
981
+ padding: 10px 14px;
982
+ background: var(--color-bg-primary);
983
+ border: 1px solid var(--color-border-primary);
984
+ border-radius: 8px;
985
+ transition: background 0.15s ease;
986
+ }
987
+
988
+ .worktree-item:hover {
989
+ background: var(--color-bg-tertiary);
990
+ }
991
+
992
+ .worktree-item-top {
993
+ display: flex;
994
+ align-items: center;
995
+ justify-content: space-between;
996
+ gap: 12px;
997
+ }
998
+
999
+ .worktree-item-bottom {
1000
+ padding-left: 2px;
1001
+ }
1002
+
1003
+ .worktree-item-left {
1004
+ display: flex;
1005
+ align-items: center;
1006
+ gap: 10px;
1007
+ flex-wrap: wrap;
1008
+ min-width: 0;
1009
+ }
1010
+
1011
+ .worktree-item-right {
1012
+ display: flex;
1013
+ align-items: center;
1014
+ gap: 10px;
1015
+ flex-shrink: 0;
1016
+ }
1017
+
1018
+ .worktree-pool-badge {
1019
+ display: inline-flex;
1020
+ align-items: center;
1021
+ padding: 2px 8px;
1022
+ font-size: 11px;
1023
+ font-weight: 600;
1024
+ letter-spacing: 0.03em;
1025
+ border-radius: 10px;
1026
+ white-space: nowrap;
1027
+ background: rgba(14, 165, 233, 0.12);
1028
+ color: #0284c7;
1029
+ }
1030
+
1031
+ [data-theme="dark"] .worktree-pool-badge {
1032
+ background: rgba(56, 189, 248, 0.15);
1033
+ color: #38bdf8;
1034
+ }
1035
+
1036
+ .worktree-adhoc-badge {
1037
+ display: inline-flex;
1038
+ align-items: center;
1039
+ padding: 2px 8px;
1040
+ font-size: 11px;
1041
+ font-weight: 600;
1042
+ letter-spacing: 0.03em;
1043
+ border-radius: 10px;
1044
+ white-space: nowrap;
1045
+ background: var(--color-bg-tertiary);
1046
+ color: var(--color-text-tertiary);
1047
+ }
1048
+
1049
+ .worktree-pr-info {
1050
+ font-size: 14px;
1051
+ font-weight: 500;
1052
+ color: var(--color-text-primary);
1053
+ }
1054
+
1055
+ .worktree-path {
1056
+ font-family: 'SF Mono', 'Monaco', 'Menlo', 'Consolas', monospace;
1057
+ font-size: 12px;
1058
+ color: var(--color-text-tertiary);
1059
+ word-break: break-all;
1060
+ }
1061
+
1062
+ .worktree-status {
1063
+ display: inline-flex;
1064
+ align-items: center;
1065
+ gap: 5px;
1066
+ font-size: 12px;
1067
+ font-weight: 500;
1068
+ white-space: nowrap;
1069
+ }
1070
+
1071
+ .worktree-status--available {
1072
+ color: #16a34a;
1073
+ }
1074
+
1075
+ [data-theme="dark"] .worktree-status--available {
1076
+ color: #4ade80;
1077
+ }
1078
+
1079
+ .worktree-status--in-use {
1080
+ color: #d97706;
1081
+ }
1082
+
1083
+ [data-theme="dark"] .worktree-status--in-use {
1084
+ color: #fbbf24;
1085
+ }
1086
+
1087
+ .worktree-status--switching {
1088
+ color: #2563eb;
1089
+ }
1090
+
1091
+ [data-theme="dark"] .worktree-status--switching {
1092
+ color: #60a5fa;
1093
+ }
1094
+
1095
+ .worktree-status--creating {
1096
+ color: #2563eb;
1097
+ }
1098
+
1099
+ [data-theme="dark"] .worktree-status--creating {
1100
+ color: #60a5fa;
1101
+ }
1102
+
1103
+ .worktree-timestamp {
1104
+ font-size: 12px;
1105
+ color: var(--color-text-muted);
1106
+ white-space: nowrap;
1107
+ }
1108
+
1109
+ .worktree-delete-btn {
1110
+ display: inline-flex;
1111
+ align-items: center;
1112
+ justify-content: center;
1113
+ width: 28px;
1114
+ height: 28px;
1115
+ padding: 0;
1116
+ background: transparent;
1117
+ border: 1px solid transparent;
1118
+ border-radius: 6px;
1119
+ color: var(--color-text-tertiary);
1120
+ cursor: pointer;
1121
+ transition: all 0.15s ease;
1122
+ }
1123
+
1124
+ .worktree-delete-btn:hover {
1125
+ background: rgba(239, 68, 68, 0.1);
1126
+ border-color: rgba(239, 68, 68, 0.3);
1127
+ color: var(--color-danger);
1128
+ }
1129
+
1130
+ .worktree-disk-warning {
1131
+ display: inline-flex;
1132
+ align-items: center;
1133
+ gap: 4px;
1134
+ padding: 2px 8px;
1135
+ font-size: 11px;
1136
+ font-weight: 500;
1137
+ border-radius: 10px;
1138
+ white-space: nowrap;
1139
+ background: var(--color-warning-bg);
1140
+ border: 1px solid var(--color-warning-border);
1141
+ color: var(--color-warning-text);
1142
+ }
1143
+
1144
+ .worktree-actions {
1145
+ display: flex;
1146
+ justify-content: flex-end;
1147
+ margin-top: 16px;
1148
+ }
1149
+
1150
+ .worktree-delete-all-btn {
1151
+ display: inline-flex;
1152
+ align-items: center;
1153
+ gap: 6px;
1154
+ padding: 6px 12px;
1155
+ background: transparent;
1156
+ border: 1px solid var(--color-danger);
1157
+ border-radius: 8px;
1158
+ font-size: 12px;
1159
+ font-weight: 500;
1160
+ color: var(--color-danger);
1161
+ cursor: pointer;
1162
+ transition: all 0.15s ease;
1163
+ }
1164
+
1165
+ .worktree-delete-all-btn:hover {
1166
+ background: var(--color-danger);
1167
+ color: white;
1168
+ }
1169
+
1170
+ .worktree-empty {
1171
+ padding: 24px 16px;
1172
+ text-align: center;
1173
+ font-size: 14px;
1174
+ font-style: italic;
1175
+ color: var(--color-text-muted);
1176
+ }
1177
+
1178
+ .worktree-pool-hint {
1179
+ display: flex;
1180
+ align-items: center;
1181
+ gap: 6px;
1182
+ margin-top: 12px;
1183
+ font-size: 12px;
1184
+ color: var(--color-text-muted);
1185
+ }
1186
+
1187
+ .worktree-pool-hint svg {
1188
+ flex-shrink: 0;
1189
+ }
1190
+
1191
+ [data-theme="dark"] .worktree-pool-config {
1192
+ background: var(--color-bg-secondary);
1193
+ border-color: var(--color-border-secondary);
1194
+ }
1195
+
1196
+ [data-theme="dark"] .worktree-pool-input {
1197
+ background: var(--color-bg-tertiary);
1198
+ border-color: var(--color-border-secondary);
1199
+ color: var(--color-text-primary);
1200
+ }
1201
+
1202
+ [data-theme="dark"] .worktree-item {
1203
+ background: var(--color-bg-secondary);
1204
+ border-color: var(--color-border-secondary);
1205
+ }
1206
+
1207
+ [data-theme="dark"] .worktree-item:hover {
1208
+ background: var(--color-bg-tertiary);
1209
+ }
1210
+
1211
+ [data-theme="dark"] .worktree-adhoc-badge {
1212
+ background: rgba(255, 255, 255, 0.08);
1213
+ color: var(--color-text-secondary);
1214
+ }
1215
+
1216
+ [data-theme="dark"] .worktree-delete-btn:hover {
1217
+ background: rgba(248, 81, 73, 0.15);
1218
+ border-color: rgba(248, 81, 73, 0.3);
1219
+ }
1220
+
896
1221
  /* ============================================
897
1222
  Danger Zone
898
1223
  ============================================ */
@@ -1180,4 +1505,26 @@ html, body {
1180
1505
  .action-buttons .btn {
1181
1506
  flex: 1;
1182
1507
  }
1508
+
1509
+ /* Worktrees responsive */
1510
+ .worktree-pool-config-items {
1511
+ flex-wrap: wrap;
1512
+ gap: 12px;
1513
+ }
1514
+
1515
+ .worktree-item-top {
1516
+ flex-direction: column;
1517
+ align-items: flex-start;
1518
+ gap: 8px;
1519
+ }
1520
+
1521
+ .worktree-item-left {
1522
+ flex-wrap: wrap;
1523
+ }
1524
+
1525
+ .worktree-item-right {
1526
+ width: 100%;
1527
+ justify-content: flex-start;
1528
+ flex-wrap: wrap;
1529
+ }
1183
1530
  }
package/public/index.html CHANGED
@@ -473,17 +473,18 @@
473
473
  font-size: 14px;
474
474
  font-weight: 500;
475
475
  line-height: 20px;
476
- color: #ffffff;
477
- background-color: var(--ai-primary);
478
- border: none;
476
+ color: var(--ai-primary);
477
+ background-color: var(--ai-subtle);
478
+ border: 1px solid var(--ai-border);
479
479
  border-radius: var(--radius-md);
480
480
  cursor: pointer;
481
- transition: background-color var(--transition-fast);
481
+ transition: background-color var(--transition-fast), border-color var(--transition-fast);
482
482
  white-space: nowrap;
483
483
  }
484
484
 
485
485
  .start-review-btn:hover:not(:disabled) {
486
- background-color: #b45309;
486
+ background-color: var(--ai-glow);
487
+ border-color: var(--ai-primary);
487
488
  }
488
489
 
489
490
  .start-review-btn:disabled {
@@ -491,6 +492,36 @@
491
492
  cursor: not-allowed;
492
493
  }
493
494
 
495
+ .start-review-btn-primary {
496
+ color: #ffffff;
497
+ background-color: var(--ai-primary);
498
+ border-color: var(--ai-primary);
499
+ }
500
+
501
+ .start-review-btn-primary:hover:not(:disabled) {
502
+ background-color: #b45309;
503
+ border-color: #b45309;
504
+ }
505
+
506
+ [data-theme="dark"] .start-review-btn-primary:hover:not(:disabled) {
507
+ background-color: #d97706;
508
+ border-color: #d97706;
509
+ }
510
+
511
+ .start-review-btn-analyze {
512
+ transition: background-color var(--transition-fast), border-color var(--transition-fast), box-shadow 0.3s ease;
513
+ }
514
+
515
+ .start-review-btn-analyze:hover:not(:disabled) {
516
+ box-shadow: 0 0 8px rgba(217, 119, 6, 0.35), 0 0 20px rgba(251, 191, 36, 0.15);
517
+ animation: glow-pulse 2s ease-in-out infinite;
518
+ }
519
+
520
+ @keyframes glow-pulse {
521
+ 0%, 100% { box-shadow: 0 0 8px rgba(217, 119, 6, 0.35), 0 0 20px rgba(251, 191, 36, 0.15); }
522
+ 50% { box-shadow: 0 0 12px rgba(217, 119, 6, 0.5), 0 0 28px rgba(251, 191, 36, 0.25); }
523
+ }
524
+
494
525
  .btn-browse {
495
526
  background-color: var(--ai-subtle);
496
527
  color: var(--ai-primary);
@@ -1330,8 +1361,11 @@
1330
1361
  autocomplete="off"
1331
1362
  spellcheck="false"
1332
1363
  >
1333
- <button type="submit" class="start-review-btn" id="start-review-btn">
1334
- Start Review
1364
+ <button type="submit" class="start-review-btn start-review-btn-primary" id="start-review-btn" title="Open review without running analysis">
1365
+ Open
1366
+ </button>
1367
+ <button type="button" class="start-review-btn start-review-btn-analyze" id="analyze-review-btn" title="Open and analyze with default settings">
1368
+ Analyze
1335
1369
  </button>
1336
1370
  </form>
1337
1371
  <div class="start-review-error" id="start-review-error-pr"></div>
@@ -1386,8 +1420,11 @@
1386
1420
  <button type="button" class="start-review-btn btn-browse" id="browse-local-btn" title="Browse for directory">
1387
1421
  Browse
1388
1422
  </button>
1389
- <button type="submit" class="start-review-btn" id="start-local-btn">
1390
- Review Local
1423
+ <button type="submit" class="start-review-btn start-review-btn-primary" id="start-local-btn" title="Open review without running analysis">
1424
+ Open
1425
+ </button>
1426
+ <button type="button" class="start-review-btn start-review-btn-analyze" id="analyze-local-btn" title="Open and analyze with default settings">
1427
+ Analyze
1391
1428
  </button>
1392
1429
  </form>
1393
1430
  <div class="start-review-error" id="start-review-error-local"></div>