@in-the-loop-labs/pair-review 3.9.0 → 4.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.
package/README.md CHANGED
@@ -65,7 +65,7 @@ pair-review is a local web application for keeping humans in the loop with AI co
65
65
  - **Local-First**: All data and processing happens on your machine - no cloud dependencies
66
66
  - **GitHub-Familiar UI**: Interface feels instantly familiar to GitHub users
67
67
  - **Human-in-the-Loop**: AI suggests, you decide
68
- - **Multiple AI Providers**: Support for Claude, Gemini, Codex, Copilot, OpenCode, Cursor, and Pi. Use your existing subscription!
68
+ - **Multiple AI Providers**: Support for Claude, Antigravity, Codex, Copilot, OpenCode, Cursor, and Pi. Use your existing subscription!
69
69
  - **Progressive**: Start simple with manual review, add AI analysis when you need it
70
70
 
71
71
  ## Workflows
@@ -437,7 +437,7 @@ pair-review supports several environment variables for customizing behavior:
437
437
  |----------|-------------|---------|
438
438
  | `GITHUB_TOKEN` | GitHub Personal Access Token (takes precedence over config file) | - |
439
439
  | `PAIR_REVIEW_CLAUDE_CMD` | Custom command to invoke Claude CLI | `claude` |
440
- | `PAIR_REVIEW_GEMINI_CMD` | Custom command to invoke Gemini CLI | `gemini` |
440
+ | `PAIR_REVIEW_ANTIGRAVITY_CMD` | Custom command to invoke Antigravity CLI | `agy` |
441
441
  | `PAIR_REVIEW_CODEX_CMD` | Custom command to invoke Codex CLI | `codex` |
442
442
  | `PAIR_REVIEW_COPILOT_CMD` | Custom command to invoke Copilot CLI | `copilot` |
443
443
  | `PAIR_REVIEW_OPENCODE_CMD` | Custom command to invoke OpenCode CLI | `opencode` |
@@ -466,8 +466,8 @@ PAIR_REVIEW_CLAUDE_CMD="/usr/local/bin/claude" pair-review 123
466
466
  # Use a wrapper command (supports multi-word commands)
467
467
  PAIR_REVIEW_CLAUDE_CMD="devx claude" pair-review 123
468
468
 
469
- # Use Gemini with npx
470
- PAIR_REVIEW_GEMINI_CMD="npx gemini" pair-review --local
469
+ # Use a custom path for the Antigravity CLI
470
+ PAIR_REVIEW_ANTIGRAVITY_CMD="/usr/local/bin/agy" pair-review --local
471
471
 
472
472
  # Force a specific model for this review
473
473
  PAIR_REVIEW_MODEL="opus" pair-review 123
@@ -491,7 +491,7 @@ Create a Personal Access Token (PAT) with these scopes:
491
491
  pair-review integrates with AI providers via their CLI tools:
492
492
 
493
493
  - **Claude**: Uses Claude Code CLI
494
- - **Gemini**: Uses Gemini CLI
494
+ - **Antigravity**: Uses the Antigravity CLI (`agy`), the successor to the Gemini CLI. Install it with `curl -fsSL https://antigravity.google/cli/install.sh | bash` (macOS/Linux; it is not an npm package) — see the [Antigravity docs](https://antigravity.google/docs). Antigravity is an analysis-only provider: it runs as an agentic reviewer in non-interactive print mode and has **no chat/ACP mode**.
495
495
  - **Codex**: Uses Codex CLI
496
496
  - **GitHub Copilot**: Uses Copilot CLI
497
497
  - **OpenCode**: Uses OpenCode CLI (requires model configuration)
@@ -502,7 +502,7 @@ You can select your preferred provider and model in the repository settings UI.
502
502
 
503
503
  #### Built-in vs. Configurable Providers
504
504
 
505
- Most providers (Claude, Gemini, Codex, Copilot) come with built-in model definitions. **OpenCode and Pi are different** - they have no built-in models and require you to configure which models to use.
505
+ Most providers (Claude, Antigravity, Codex, Copilot) come with built-in model definitions. **OpenCode and Pi are different** - they have no built-in models and require you to configure which models to use.
506
506
 
507
507
  #### Configuring Custom Models
508
508
 
@@ -648,7 +648,7 @@ The key difference from Review Council is consolidation order: Advanced consolid
648
648
 
649
649
  - **Large changesets with Opus 4.6**: Use review council instructions to tell the model to use a Team — it will spawn sub-agents to divide the work
650
650
  - **Multi-model parallel review**: Give each model a specific focus area (security, performance, correctness) via per-model instructions and get combined results
651
- - **Cross-model perspectives**: Run the same analysis across different providers (e.g., Claude, Gemini, GPT) — where models agree signals high-confidence findings, but unique outliers from a single model can be equally valuable, catching issue types that only that model excels at spotting
651
+ - **Cross-model perspectives**: Run the same analysis across different providers (e.g., Claude, Antigravity, GPT) — where models agree signals high-confidence findings, but unique outliers from a single model can be equally valuable, catching issue types that only that model excels at spotting
652
652
 
653
653
  ### Chat
654
654
 
@@ -683,7 +683,7 @@ Configure your preferred models in `providers.pi.models` — see [AI Provider Co
683
683
  }
684
684
  ```
685
685
 
686
- 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. Codex chat also supports `sandbox`: use `workspace-write` by default, or `read-only` for discussion-only sessions.
686
+ Available chat provider IDs: `pi`, `claude`, `codex`, `copilot-acp`, `opencode-acp`, `cursor-acp`. Each supports `command`, `args` (replaces defaults), `extra_args` (appends), and `env` overrides. Codex chat also supports `sandbox`: use `workspace-write` by default, or `read-only` for discussion-only sessions. (Antigravity is an analysis-only provider — it has no ACP mode, so there is no Antigravity chat provider.)
687
687
 
688
688
  **Keyboard shortcut:** Press `p` then `c` to toggle the chat panel.
689
689
 
@@ -959,8 +959,8 @@ These commands update your MCP configuration in `~/.claude/settings.json` (user-
959
959
 
960
960
  ### Prerequisites
961
961
 
962
- - Node.js 20.0.0 or higher
963
- - [pnpm](https://pnpm.io/) 10.x
962
+ - Node.js 22.0.0 or higher
963
+ - [pnpm](https://pnpm.io/) 11.x
964
964
  - Git
965
965
 
966
966
  ### Running Locally
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@in-the-loop-labs/pair-review",
3
- "version": "3.9.0",
3
+ "version": "4.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": {
@@ -19,8 +19,9 @@
19
19
  "LICENSE"
20
20
  ],
21
21
  "engines": {
22
- "node": ">=20.0.0"
22
+ "node": ">=22.0.0"
23
23
  },
24
+ "packageManager": "pnpm@11.9.0",
24
25
  "scripts": {
25
26
  "start": "node src/server.js",
26
27
  "dev": "node bin/pair-review.js",
@@ -47,7 +48,7 @@
47
48
  "cursor",
48
49
  "copilot",
49
50
  "codex",
50
- "gemini"
51
+ "antigravity"
51
52
  ],
52
53
  "author": "Tim Perkins",
53
54
  "license": "Apache-2.0",
@@ -63,7 +64,7 @@
63
64
  "@agentclientprotocol/sdk": "^0.14.1",
64
65
  "@modelcontextprotocol/sdk": "^1.25.3",
65
66
  "@octokit/rest": "^19.0.11",
66
- "better-sqlite3": "^11.8.1",
67
+ "better-sqlite3": "^12.11.1",
67
68
  "express": "^4.18.2",
68
69
  "glob": "^13.0.6",
69
70
  "markdown-it": "^13.0.2",
@@ -83,10 +84,5 @@
83
84
  "jsdom": "^29.0.1",
84
85
  "supertest": "^7.1.4",
85
86
  "vitest": "^4.0.16"
86
- },
87
- "pnpm": {
88
- "onlyBuiltDependencies": [
89
- "better-sqlite3"
90
- ]
91
87
  }
92
88
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pair-review",
3
- "version": "3.9.0",
3
+ "version": "4.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",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-critic",
3
- "version": "3.9.0",
3
+ "version": "4.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",
package/public/css/pr.css CHANGED
@@ -6939,66 +6939,6 @@ body:not([data-theme="dark"]) .theme-icon-light {
6939
6939
  border-color: var(--color-border-secondary);
6940
6940
  }
6941
6941
 
6942
- /* ============================================
6943
- Analysis Progress Dots
6944
- ============================================ */
6945
-
6946
- .analysis-progress-dots {
6947
- display: flex;
6948
- align-items: center;
6949
- gap: 6px;
6950
- margin-right: 8px;
6951
- }
6952
-
6953
- .progress-dot {
6954
- width: 8px;
6955
- height: 8px;
6956
- border-radius: 50%;
6957
- border: 1.5px solid var(--color-accent-ai);
6958
- background: transparent;
6959
- transition: all 0.3s ease;
6960
- }
6961
-
6962
- .progress-dot.active {
6963
- animation: pulse-dot 1.2s ease-in-out infinite;
6964
- }
6965
-
6966
- .progress-dot.completed {
6967
- background: var(--color-accent-ai);
6968
- border-color: var(--color-accent-ai);
6969
- }
6970
-
6971
- .progress-dot.error {
6972
- background: #ef4444;
6973
- border-color: #ef4444;
6974
- }
6975
-
6976
- @keyframes pulse-dot {
6977
- 0%, 100% {
6978
- transform: scale(1);
6979
- opacity: 1;
6980
- }
6981
- 50% {
6982
- transform: scale(1.3);
6983
- opacity: 0.9;
6984
- }
6985
- }
6986
-
6987
- /* Dark theme for progress dots */
6988
- [data-theme="dark"] .progress-dot {
6989
- border-color: var(--color-accent-ai-dark);
6990
- }
6991
-
6992
- [data-theme="dark"] .progress-dot.completed {
6993
- background: var(--color-accent-ai-dark);
6994
- border-color: var(--color-accent-ai-dark);
6995
- }
6996
-
6997
- [data-theme="dark"] .progress-dot.error {
6998
- background: #f87171;
6999
- border-color: #f87171;
7000
- }
7001
-
7002
6942
  /* Magical Analyze Button - Amber AI CTA */
7003
6943
  #analyze-btn {
7004
6944
  background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
@@ -12959,6 +12899,18 @@ body.resizing * {
12959
12899
  animation: pulse-dot 1.2s ease-in-out infinite;
12960
12900
  }
12961
12901
 
12902
+ /* Pulse used by the running/setting-up stack-progress status icons above. */
12903
+ @keyframes pulse-dot {
12904
+ 0%, 100% {
12905
+ transform: scale(1);
12906
+ opacity: 1;
12907
+ }
12908
+ 50% {
12909
+ transform: scale(1.3);
12910
+ opacity: 0.9;
12911
+ }
12912
+ }
12913
+
12962
12914
  .status-pending .stack-progress-status-icon {
12963
12915
  color: var(--color-text-muted, #d1d9e0);
12964
12916
  }
@@ -170,7 +170,7 @@ class AdvancedConfigTab {
170
170
  /**
171
171
  * Set default orchestration provider/model for new councils.
172
172
  * Falls back to 'claude'/'sonnet' if not provided.
173
- * @param {string} provider - Default provider ID (e.g., 'claude', 'gemini')
173
+ * @param {string} provider - Default provider ID (e.g., 'claude', 'antigravity')
174
174
  * @param {string} model - Default model ID (e.g., 'sonnet', 'opus')
175
175
  */
176
176
  setDefaultOrchestration(provider, model) {
@@ -627,7 +627,7 @@ class AnalysisConfigModal {
627
627
  selectModel(modelId) {
628
628
  // Guard: never store a model that doesn't belong to the current provider.
629
629
  // Callers can pass a model resolved from a different scope (e.g. 'opus'
630
- // while the provider is 'gemini'); fall back to the provider's default so
630
+ // while the provider is 'antigravity'); fall back to the provider's default so
631
631
  // the UI always shows a selected card and submissions carry a valid pair.
632
632
  if (modelId && this.models.length && !this.models.some(m => m.id === modelId)) {
633
633
  const fallback = this.models.find(m => m.default) || this.models[0];
@@ -952,7 +952,7 @@ class AnalysisConfigModal {
952
952
  }
953
953
  // Only honour currentModel when it belongs to the selected provider.
954
954
  // selectProvider() has already chosen a valid model for the provider (via
955
- // tier matching); applying a foreign model here (e.g. 'opus' under 'gemini')
955
+ // tier matching); applying a foreign model here (e.g. 'opus' under 'antigravity')
956
956
  // would leave no model card selected and submit an invalid pair.
957
957
  if (options.currentModel && this.models.some(m => m.id === options.currentModel)) {
958
958
  this.selectModel(options.currentModel);
@@ -304,16 +304,6 @@ class CouncilProgressModal {
304
304
  }
305
305
  }
306
306
 
307
- // Update toolbar progress dots
308
- const manager = window.prManager || window.localManager;
309
- if (manager?.updateProgressDot) {
310
- for (let level = 1; level <= 4; level++) {
311
- if (status.levels[level]) {
312
- manager.updateProgressDot(level, status.levels[level].status);
313
- }
314
- }
315
- }
316
-
317
307
  // Terminal states
318
308
  if (status.status === 'completed') {
319
309
  this._handleCompletion(status);
@@ -346,7 +346,7 @@ class LocalManager {
346
346
  const lastCouncilId = reviewSettings.last_council_id;
347
347
 
348
348
  // Resolve provider and model as a MATCHED pair so the council/advanced tabs
349
- // are never seeded with a cross-provider model (e.g. gemini + opus), which
349
+ // are never seeded with a cross-provider model (e.g. antigravity + opus), which
350
350
  // would blank the model <select> and be rejected by the backend.
351
351
  const providersInfo = await manager._getProvidersInfo();
352
352
  const { provider: currentProvider, model: currentModel } = window.resolveProviderModelPair([
@@ -1893,55 +1893,6 @@ class LocalManager {
1893
1893
  };
1894
1894
  document.addEventListener('keydown', keyHandler);
1895
1895
  }
1896
-
1897
- /**
1898
- * Get the progress dots container element
1899
- * @returns {HTMLElement|null}
1900
- */
1901
- getProgressDotsContainer() {
1902
- return document.getElementById('analysis-progress-dots');
1903
- }
1904
-
1905
- /**
1906
- * Update a specific progress dot during analysis
1907
- * Maps level numbers to phase names:
1908
- * - Level 4 -> orchestration (finalization)
1909
- * - Level 1 -> level1
1910
- * - Level 2 -> level2
1911
- * - Level 3 -> level3
1912
- * @param {number} level - The level number (1, 2, 3, or 4)
1913
- * @param {string} status - The status ('running', 'completed', 'failed')
1914
- */
1915
- updateProgressDot(level, status) {
1916
- const container = this.getProgressDotsContainer();
1917
- if (!container) return;
1918
-
1919
- // Map levels to dot phases
1920
- const phaseMap = {
1921
- 4: 'orchestration', // Orchestration/finalization is level 4 in progress modal
1922
- 1: 'level1',
1923
- 2: 'level2',
1924
- 3: 'level3'
1925
- };
1926
-
1927
- const phase = phaseMap[level];
1928
- if (!phase) return;
1929
-
1930
- const dot = container.querySelector(`[data-phase="${phase}"]`);
1931
- if (!dot) return;
1932
-
1933
- // Remove existing states
1934
- dot.classList.remove('active', 'completed', 'error');
1935
-
1936
- // Apply new state
1937
- if (status === 'running') {
1938
- dot.classList.add('active');
1939
- } else if (status === 'completed') {
1940
- dot.classList.add('completed');
1941
- } else if (status === 'failed') {
1942
- dot.classList.add('error');
1943
- }
1944
- }
1945
1896
  }
1946
1897
 
1947
1898
  // Initialize LocalManager when in local mode
package/public/js/pr.js CHANGED
@@ -704,7 +704,7 @@ class PRManager {
704
704
  // Resolve provider and model as a MATCHED pair. Resolving each half
705
705
  // independently (repo || app || hardcoded) can mix a provider from one
706
706
  // scope with a model from another, yielding an invalid pair (e.g.
707
- // gemini/opus) that startAnalysis would forward to the backend as-is.
707
+ // antigravity/opus) that startAnalysis would forward to the backend as-is.
708
708
  const providers = providersInfo || await this._getProvidersInfo();
709
709
  const { provider, model } = window.resolveProviderModelPair([
710
710
  { provider: repoSettings?.default_provider, model: repoSettings?.default_model },
@@ -3053,7 +3053,7 @@ class PRManager {
3053
3053
  ]);
3054
3054
 
3055
3055
  // Resolve provider and model as a MATCHED pair so the council/advanced tabs
3056
- // are never seeded with a cross-provider model (e.g. gemini + opus), which
3056
+ // are never seeded with a cross-provider model (e.g. antigravity + opus), which
3057
3057
  // would blank the model <select> and be rejected by the backend.
3058
3058
  const providersInfo = await this._getProvidersInfo();
3059
3059
  const { provider: currentProvider, model: currentModel } = window.resolveProviderModelPair([
@@ -6588,9 +6588,6 @@ class PRManager {
6588
6588
  } else {
6589
6589
  btn.innerHTML = '<span class="analyzing-icon">✨</span> Analyzing...';
6590
6590
  }
6591
-
6592
- // Show progress dots
6593
- this.showProgressDots();
6594
6591
  }
6595
6592
 
6596
6593
  /**
@@ -6615,9 +6612,6 @@ class PRManager {
6615
6612
  }
6616
6613
  btn.disabled = true;
6617
6614
 
6618
- // Complete all progress dots (they'll be hidden when button resets)
6619
- this.completeAllProgressDots();
6620
-
6621
6615
  // Revert to normal after 2 seconds
6622
6616
  setTimeout(() => this.resetButton(), 2000);
6623
6617
  }
@@ -6645,114 +6639,6 @@ class PRManager {
6645
6639
  } else {
6646
6640
  btn.innerHTML = 'Analyze with AI';
6647
6641
  }
6648
-
6649
- // Hide progress dots when resetting
6650
- this.hideProgressDots();
6651
- }
6652
-
6653
- // ============================================
6654
- // Progress Dots Controller
6655
- // ============================================
6656
-
6657
- /**
6658
- * Get the progress dots container
6659
- * @returns {HTMLElement|null}
6660
- */
6661
- getProgressDotsContainer() {
6662
- return document.getElementById('analysis-progress-dots');
6663
- }
6664
-
6665
- /**
6666
- * Show progress dots (called when analysis starts)
6667
- */
6668
- showProgressDots() {
6669
- const container = this.getProgressDotsContainer();
6670
- if (!container) return;
6671
-
6672
- container.style.display = 'flex';
6673
-
6674
- // Reset all dots to initial state
6675
- const dots = container.querySelectorAll('.progress-dot');
6676
- dots.forEach(dot => {
6677
- dot.classList.remove('active', 'completed', 'error');
6678
- });
6679
-
6680
- // Set first dot (orchestration) as active
6681
- const firstDot = container.querySelector('[data-phase="orchestration"]');
6682
- if (firstDot) {
6683
- firstDot.classList.add('active');
6684
- }
6685
- }
6686
-
6687
- /**
6688
- * Hide progress dots (called when analysis completes or is cancelled)
6689
- */
6690
- hideProgressDots() {
6691
- const container = this.getProgressDotsContainer();
6692
- if (!container) return;
6693
-
6694
- container.style.display = 'none';
6695
-
6696
- // Reset all dots
6697
- const dots = container.querySelectorAll('.progress-dot');
6698
- dots.forEach(dot => {
6699
- dot.classList.remove('active', 'completed', 'error');
6700
- });
6701
- }
6702
-
6703
- /**
6704
- * Update progress dots based on level status
6705
- * Maps level numbers to phases:
6706
- * - Level 4 (orchestration/finalization) -> orchestration
6707
- * - Level 1 -> level1
6708
- * - Level 2 -> level2
6709
- * - Level 3 -> level3
6710
- * @param {number} level - The level number (1, 2, 3, or 4)
6711
- * @param {string} status - The status ('running', 'completed', 'failed')
6712
- */
6713
- updateProgressDot(level, status) {
6714
- const container = this.getProgressDotsContainer();
6715
- if (!container) return;
6716
-
6717
- // Map levels to dot phases
6718
- const phaseMap = {
6719
- 4: 'orchestration', // Orchestration/finalization is level 4 in progress modal
6720
- 1: 'level1',
6721
- 2: 'level2',
6722
- 3: 'level3'
6723
- };
6724
-
6725
- const phase = phaseMap[level];
6726
- if (!phase) return;
6727
-
6728
- const dot = container.querySelector(`[data-phase="${phase}"]`);
6729
- if (!dot) return;
6730
-
6731
- // Remove existing states
6732
- dot.classList.remove('active', 'completed', 'error');
6733
-
6734
- // Apply new state
6735
- if (status === 'running') {
6736
- dot.classList.add('active');
6737
- } else if (status === 'completed') {
6738
- dot.classList.add('completed');
6739
- } else if (status === 'failed') {
6740
- dot.classList.add('error');
6741
- }
6742
- }
6743
-
6744
- /**
6745
- * Complete all progress dots (called briefly before hiding)
6746
- */
6747
- completeAllProgressDots() {
6748
- const container = this.getProgressDotsContainer();
6749
- if (!container) return;
6750
-
6751
- const dots = container.querySelectorAll('.progress-dot');
6752
- dots.forEach(dot => {
6753
- dot.classList.remove('active', 'error');
6754
- dot.classList.add('completed');
6755
- });
6756
6642
  }
6757
6643
 
6758
6644
  /**
@@ -6960,7 +6846,7 @@ class PRManager {
6960
6846
  const lastCouncilId = reviewSettings.last_council_id;
6961
6847
 
6962
6848
  // Resolve provider and model as a MATCHED pair so the council/advanced tabs
6963
- // are never seeded with a cross-provider model (e.g. gemini + opus), which
6849
+ // are never seeded with a cross-provider model (e.g. antigravity + opus), which
6964
6850
  // would blank the model <select> and be rejected by the backend.
6965
6851
  const providersInfo = await this._getProvidersInfo();
6966
6852
  const { provider: currentProvider, model: currentModel } = window.resolveProviderModelPair([
@@ -6,7 +6,7 @@
6
6
  * settings, then app config) and historically each half was resolved
7
7
  * independently with `repo || app || hardcoded`. When a scope overrides only
8
8
  * ONE half, the halves can come from different scopes and produce an invalid
9
- * pair such as `gemini` + `opus` (an Anthropic model). The modal then shows no
9
+ * pair such as `antigravity` + `opus` (an Anthropic model). The modal then shows no
10
10
  * selected model, and the non-modal auto-analyze path posts the broken pair
11
11
  * straight to the backend.
12
12
  *
package/public/local.html CHANGED
@@ -435,13 +435,6 @@
435
435
  </div>
436
436
  <div class="diff-stats" id="diff-stats"></div>
437
437
  <div class="toolbar-actions">
438
- <!-- Progress Dots (visible during analysis) -->
439
- <div class="analysis-progress-dots" id="analysis-progress-dots" style="display: none;">
440
- <span class="progress-dot" data-phase="level1" title="Level 1: Diff"></span>
441
- <span class="progress-dot" data-phase="level2" title="Level 2: File"></span>
442
- <span class="progress-dot" data-phase="level3" title="Level 3: Codebase"></span>
443
- <span class="progress-dot" data-phase="orchestration" title="Consolidation"></span>
444
- </div>
445
438
  <button class="btn btn-sm btn-secondary" id="analyze-btn" title="Analyze with AI">
446
439
  <svg class="analyze-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
447
440
  <path d="M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z"/>
package/public/pr.html CHANGED
@@ -231,13 +231,6 @@
231
231
  </div>
232
232
  <div class="diff-stats" id="diff-stats"></div>
233
233
  <div class="toolbar-actions">
234
- <!-- Progress Dots (visible during analysis) -->
235
- <div class="analysis-progress-dots" id="analysis-progress-dots" style="display: none;">
236
- <span class="progress-dot" data-phase="level1" title="Level 1: Diff"></span>
237
- <span class="progress-dot" data-phase="level2" title="Level 2: File"></span>
238
- <span class="progress-dot" data-phase="level3" title="Level 3: Codebase"></span>
239
- <span class="progress-dot" data-phase="orchestration" title="Consolidation"></span>
240
- </div>
241
234
  <button class="btn btn-sm btn-secondary" id="analyze-btn" title="Analyze with AI">
242
235
  <svg class="analyze-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
243
236
  <path d="M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z"/>
@@ -342,8 +342,8 @@ A suggestion is a duplicate if it targets the same file and overlapping lines an
342
342
  class Analyzer {
343
343
  /**
344
344
  * @param {Object} database - Database instance
345
- * @param {string} model - Model to use (e.g., 'opus', 'gemini-2.5-pro')
346
- * @param {string} provider - Provider ID (e.g., 'claude', 'gemini'). Defaults to 'claude'.
345
+ * @param {string} model - Model to use (e.g., 'opus', 'gemini-3.1-pro-low')
346
+ * @param {string} provider - Provider ID (e.g., 'claude', 'antigravity'). Defaults to 'claude'.
347
347
  * @param {Object} providerOverrides - Per-call config overrides passed to createProvider (optional)
348
348
  * @param {Object|null} providerOverridesMap - Per-provider overrides map for council mode (provider ID → overrides)
349
349
  */
@@ -860,8 +860,8 @@ class Analyzer {
860
860
  *
861
861
  * Uses the bare command name since BIN_DIR is added to PATH in all
862
862
  * providers. Using the absolute path causes issues with AI providers
863
- * that pattern-match allowed tools (e.g., Gemini only matches
864
- * 'git-diff-lines', not the full path).
863
+ * that pattern-match allowed shell commands by their bare command name
864
+ * (matching 'git-diff-lines', not the full path).
865
865
  *
866
866
  * @param {string|null} worktreePath - Path to the git worktree
867
867
  * @returns {string} e.g. `git-diff-lines` or `git-diff-lines --cwd "/path"`