@in-the-loop-labs/pair-review 3.9.1 → 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 +10 -10
- package/package.json +5 -9
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin-code-critic/.claude-plugin/plugin.json +1 -1
- package/public/js/components/AdvancedConfigTab.js +1 -1
- package/public/js/components/AnalysisConfigModal.js +2 -2
- package/public/js/local.js +1 -1
- package/public/js/pr.js +3 -3
- package/public/js/utils/provider-model.js +1 -1
- package/src/ai/analyzer.js +4 -4
- package/src/ai/antigravity-provider.js +594 -0
- package/src/ai/index.js +1 -1
- package/src/ai/opencode-provider.js +1 -1
- package/src/ai/provider.js +5 -5
- package/src/ai/stream-parser.js +1 -52
- package/src/chat/acp-bridge.js +1 -1
- package/src/chat/chat-providers.js +1 -9
- package/src/config.js +3 -3
- package/src/database.js +1 -1
- package/src/main.js +4 -4
- package/src/routes/config.js +2 -2
- package/src/ai/gemini-provider.js +0 -752
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,
|
|
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
|
-
| `
|
|
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
|
|
470
|
-
|
|
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
|
-
- **
|
|
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,
|
|
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,
|
|
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`, `
|
|
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
|
|
963
|
-
- [pnpm](https://pnpm.io/)
|
|
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
|
+
"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": ">=
|
|
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
|
-
"
|
|
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.
|
|
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
|
+
"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
|
+
"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",
|
|
@@ -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', '
|
|
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 '
|
|
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 '
|
|
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);
|
package/public/js/local.js
CHANGED
|
@@ -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.
|
|
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([
|
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
|
-
//
|
|
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.
|
|
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([
|
|
@@ -6846,7 +6846,7 @@ class PRManager {
|
|
|
6846
6846
|
const lastCouncilId = reviewSettings.last_council_id;
|
|
6847
6847
|
|
|
6848
6848
|
// Resolve provider and model as a MATCHED pair so the council/advanced tabs
|
|
6849
|
-
// are never seeded with a cross-provider model (e.g.
|
|
6849
|
+
// are never seeded with a cross-provider model (e.g. antigravity + opus), which
|
|
6850
6850
|
// would blank the model <select> and be rejected by the backend.
|
|
6851
6851
|
const providersInfo = await this._getProvidersInfo();
|
|
6852
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 `
|
|
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/src/ai/analyzer.js
CHANGED
|
@@ -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-
|
|
346
|
-
* @param {string} provider - Provider ID (e.g., '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
|
|
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"`
|