@in-the-loop-labs/pair-review 1.6.1 → 2.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 +77 -4
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/skills/review-requests/SKILL.md +4 -1
- package/plugin-code-critic/.claude-plugin/plugin.json +1 -1
- package/plugin-code-critic/skills/analyze/SKILL.md +4 -3
- package/public/css/pr.css +1875 -144
- package/public/js/CONVENTIONS.md +16 -0
- package/public/js/components/AIPanel.js +66 -0
- package/public/js/components/AnalysisConfigModal.js +2 -2
- package/public/js/components/ChatPanel.js +2952 -0
- package/public/js/components/CouncilProgressModal.js +28 -18
- package/public/js/components/KeyboardShortcuts.js +3 -0
- package/public/js/components/PanelGroup.js +723 -0
- package/public/js/components/PreviewModal.js +3 -8
- package/public/js/components/StatusIndicator.js +2 -2
- package/public/js/components/Toast.js +22 -1
- package/public/js/components/VoiceCentricConfigTab.js +2 -2
- package/public/js/index.js +8 -0
- package/public/js/local.js +25 -682
- package/public/js/modules/analysis-history.js +19 -66
- package/public/js/modules/comment-manager.js +57 -19
- package/public/js/modules/diff-context.js +176 -0
- package/public/js/modules/diff-renderer.js +30 -0
- package/public/js/modules/file-comment-manager.js +126 -105
- package/public/js/modules/file-list-merger.js +64 -0
- package/public/js/modules/panel-resizer.js +25 -6
- package/public/js/modules/suggestion-manager.js +40 -125
- package/public/js/pr.js +974 -178
- package/public/js/repo-settings.js +36 -6
- package/public/js/utils/category-emoji.js +44 -0
- package/public/js/utils/time.js +32 -0
- package/public/local.html +107 -71
- package/public/pr.html +107 -71
- package/public/repo-settings.html +32 -0
- package/src/ai/analyzer.js +8 -4
- package/src/ai/claude-provider.js +22 -11
- package/src/ai/copilot-provider.js +39 -9
- package/src/ai/cursor-agent-provider.js +36 -7
- package/src/ai/gemini-provider.js +17 -4
- package/src/ai/prompts/config.js +7 -1
- package/src/ai/provider-availability.js +1 -1
- package/src/ai/provider.js +25 -37
- package/src/ai/stream-parser.js +1 -1
- package/src/chat/CONVENTIONS.md +18 -0
- package/src/chat/pi-bridge.js +491 -0
- package/src/chat/prompt-builder.js +262 -0
- package/src/chat/session-manager.js +619 -0
- package/src/config.js +14 -0
- package/src/database.js +322 -15
- package/src/main.js +4 -17
- package/src/routes/analyses.js +721 -0
- package/src/routes/chat.js +655 -0
- package/src/routes/config.js +29 -8
- package/src/routes/context-files.js +223 -0
- package/src/routes/local.js +225 -1133
- package/src/routes/mcp.js +39 -30
- package/src/routes/pr.js +410 -52
- package/src/routes/reviews.js +1035 -0
- package/src/routes/shared.js +5 -30
- package/src/server.js +34 -12
- package/src/sse/review-events.js +46 -0
- package/src/utils/auto-context.js +88 -0
- package/src/utils/category-emoji.js +33 -0
- package/src/utils/diff-file-list.js +57 -0
- package/public/js/components/ProgressModal.js +0 -705
- package/src/routes/analysis.js +0 -1600
- package/src/routes/comments.js +0 -534
|
@@ -21,7 +21,8 @@ const BIN_DIR = path.join(__dirname, '..', '..', 'bin');
|
|
|
21
21
|
*/
|
|
22
22
|
const GEMINI_MODELS = [
|
|
23
23
|
{
|
|
24
|
-
id: 'gemini-3-flash
|
|
24
|
+
id: 'gemini-3-flash',
|
|
25
|
+
aliases: ['gemini-3-flash-preview'],
|
|
25
26
|
name: '3.0 Flash',
|
|
26
27
|
tier: 'fast',
|
|
27
28
|
tagline: 'Rapid Sanity Check',
|
|
@@ -40,16 +41,28 @@ const GEMINI_MODELS = [
|
|
|
40
41
|
default: true
|
|
41
42
|
},
|
|
42
43
|
{
|
|
43
|
-
id: 'gemini-3-pro
|
|
44
|
+
id: 'gemini-3-pro',
|
|
45
|
+
aliases: ['gemini-3-pro-preview'],
|
|
44
46
|
name: '3.0 Pro',
|
|
45
47
|
tier: 'thorough',
|
|
46
48
|
tagline: 'Architectural Audit',
|
|
47
49
|
description: 'Most intelligent Gemini model—advanced reasoning for deep architectural analysis',
|
|
48
50
|
badge: 'Deep Dive',
|
|
49
51
|
badgeClass: 'badge-power'
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: 'gemini-3.1-pro',
|
|
55
|
+
name: '3.1 Pro',
|
|
56
|
+
tier: 'thorough',
|
|
57
|
+
tagline: 'Latest & Greatest',
|
|
58
|
+
description: 'Newest Gemini model—cutting-edge reasoning for complex architectural reviews',
|
|
59
|
+
badge: 'Latest',
|
|
60
|
+
badgeClass: 'badge-power'
|
|
50
61
|
}
|
|
51
62
|
];
|
|
52
63
|
|
|
64
|
+
const DEFAULT_GEMINI_MODEL = 'gemini-2.5-pro';
|
|
65
|
+
|
|
53
66
|
class GeminiProvider extends AIProvider {
|
|
54
67
|
/**
|
|
55
68
|
* @param {string} model - Model identifier
|
|
@@ -59,7 +72,7 @@ class GeminiProvider extends AIProvider {
|
|
|
59
72
|
* @param {Object} configOverrides.env - Additional environment variables
|
|
60
73
|
* @param {Object[]} configOverrides.models - Custom model definitions
|
|
61
74
|
*/
|
|
62
|
-
constructor(model =
|
|
75
|
+
constructor(model = DEFAULT_GEMINI_MODEL, configOverrides = {}) {
|
|
63
76
|
super(model);
|
|
64
77
|
|
|
65
78
|
// Command precedence: ENV > config > default
|
|
@@ -690,7 +703,7 @@ class GeminiProvider extends AIProvider {
|
|
|
690
703
|
}
|
|
691
704
|
|
|
692
705
|
static getDefaultModel() {
|
|
693
|
-
return
|
|
706
|
+
return DEFAULT_GEMINI_MODEL;
|
|
694
707
|
}
|
|
695
708
|
|
|
696
709
|
static getInstallInstructions() {
|
package/src/ai/prompts/config.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Defines tier mappings for the prompt system.
|
|
6
6
|
* Note: Provider-specific model-to-tier mappings are defined in each provider's
|
|
7
|
-
* getModels() method.
|
|
7
|
+
* getModels() method. The tier is persisted on each analysis_runs record at creation time.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -21,6 +21,11 @@ const TIER_ALIASES = {
|
|
|
21
21
|
*/
|
|
22
22
|
const TIERS = ['fast', 'balanced', 'thorough'];
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* All accepted tier values (internal tiers + user-facing aliases)
|
|
26
|
+
*/
|
|
27
|
+
const VALID_TIERS = [...TIERS, ...Object.keys(TIER_ALIASES)];
|
|
28
|
+
|
|
24
29
|
/**
|
|
25
30
|
* Prompt types (analysis levels)
|
|
26
31
|
*/
|
|
@@ -44,6 +49,7 @@ function resolveTier(tierOrAlias) {
|
|
|
44
49
|
module.exports = {
|
|
45
50
|
TIER_ALIASES,
|
|
46
51
|
TIERS,
|
|
52
|
+
VALID_TIERS,
|
|
47
53
|
PROMPT_TYPES,
|
|
48
54
|
resolveTier
|
|
49
55
|
};
|
package/src/ai/provider.js
CHANGED
|
@@ -10,6 +10,7 @@ const path = require('path');
|
|
|
10
10
|
const { spawn } = require('child_process');
|
|
11
11
|
const logger = require('../utils/logger');
|
|
12
12
|
const { extractJSON } = require('../utils/json-extractor');
|
|
13
|
+
const { TIERS, TIER_ALIASES } = require('./prompts/config');
|
|
13
14
|
|
|
14
15
|
// Directory containing bin scripts (git-diff-lines, etc.)
|
|
15
16
|
const BIN_DIR = path.join(__dirname, '..', '..', 'bin');
|
|
@@ -345,23 +346,10 @@ function prettifyModelId(id) {
|
|
|
345
346
|
.replace(/\b\w/g, c => c.toUpperCase()); // Capitalize each word
|
|
346
347
|
}
|
|
347
348
|
|
|
348
|
-
/**
|
|
349
|
-
* Canonical model tiers
|
|
350
|
-
*/
|
|
351
|
-
const CANONICAL_TIERS = ['fast', 'balanced', 'thorough'];
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
* Tier aliases that map to canonical tiers
|
|
355
|
-
*/
|
|
356
|
-
const TIER_ALIASES = {
|
|
357
|
-
free: 'fast',
|
|
358
|
-
premium: 'thorough'
|
|
359
|
-
};
|
|
360
|
-
|
|
361
349
|
/**
|
|
362
350
|
* All valid tier values (canonical + aliases)
|
|
363
351
|
*/
|
|
364
|
-
const VALID_TIERS = [...
|
|
352
|
+
const VALID_TIERS = [...TIERS, ...Object.keys(TIER_ALIASES)];
|
|
365
353
|
|
|
366
354
|
/**
|
|
367
355
|
* Normalize a tier to its canonical form
|
|
@@ -603,27 +591,6 @@ function createProvider(providerId, model = null) {
|
|
|
603
591
|
return new ProviderClass(actualModel, { ...(overrides || {}), yolo: yoloMode });
|
|
604
592
|
}
|
|
605
593
|
|
|
606
|
-
/**
|
|
607
|
-
* Get tier for a specific model from a provider
|
|
608
|
-
* Queries the provider's model definitions (or config overrides) to find the tier
|
|
609
|
-
* @param {string} providerId - Provider ID (e.g., 'claude', 'gemini')
|
|
610
|
-
* @param {string} modelId - Model ID (e.g., 'sonnet', 'gemini-2.5-pro')
|
|
611
|
-
* @returns {string|null} Tier name or null if provider or model not found
|
|
612
|
-
*/
|
|
613
|
-
function getTierForModel(providerId, modelId) {
|
|
614
|
-
const ProviderClass = providerRegistry.get(providerId);
|
|
615
|
-
if (!ProviderClass) {
|
|
616
|
-
return null;
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
// Merge config models with built-in models
|
|
620
|
-
const overrides = providerConfigOverrides.get(providerId);
|
|
621
|
-
const models = mergeModels(ProviderClass.getModels(), overrides?.models);
|
|
622
|
-
|
|
623
|
-
const model = models.find(m => m.id === modelId);
|
|
624
|
-
return model?.tier || null;
|
|
625
|
-
}
|
|
626
|
-
|
|
627
594
|
/**
|
|
628
595
|
* Test availability of a provider with timeout
|
|
629
596
|
* @param {string} providerId - Provider ID
|
|
@@ -656,6 +623,27 @@ async function testProviderAvailability(providerId, timeout = 10000) {
|
|
|
656
623
|
}
|
|
657
624
|
}
|
|
658
625
|
|
|
626
|
+
/**
|
|
627
|
+
* Get tier for a specific model from a provider
|
|
628
|
+
* Queries the provider's model definitions (or config overrides) to find the tier
|
|
629
|
+
* @param {string} providerId - Provider ID (e.g., 'claude', 'gemini')
|
|
630
|
+
* @param {string} modelId - Model ID (e.g., 'sonnet', 'gemini-2.5-pro')
|
|
631
|
+
* @returns {string|null} Tier name or null if provider or model not found
|
|
632
|
+
*/
|
|
633
|
+
function getTierForModel(providerId, modelId) {
|
|
634
|
+
const ProviderClass = providerRegistry.get(providerId);
|
|
635
|
+
if (!ProviderClass) {
|
|
636
|
+
return null;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// Merge config models with built-in models
|
|
640
|
+
const overrides = providerConfigOverrides.get(providerId);
|
|
641
|
+
const models = mergeModels(ProviderClass.getModels(), overrides?.models);
|
|
642
|
+
|
|
643
|
+
const model = models.find(m => m.id === modelId);
|
|
644
|
+
return model?.tier || null;
|
|
645
|
+
}
|
|
646
|
+
|
|
659
647
|
module.exports = {
|
|
660
648
|
AIProvider,
|
|
661
649
|
MODEL_TIERS,
|
|
@@ -665,12 +653,12 @@ module.exports = {
|
|
|
665
653
|
getRegisteredProviderIds,
|
|
666
654
|
getAllProvidersInfo,
|
|
667
655
|
createProvider,
|
|
668
|
-
getTierForModel,
|
|
669
656
|
testProviderAvailability,
|
|
670
657
|
// Config override support
|
|
671
658
|
applyConfigOverrides,
|
|
672
659
|
getProviderConfigOverrides,
|
|
673
660
|
inferModelDefaults,
|
|
674
661
|
resolveDefaultModel,
|
|
675
|
-
prettifyModelId
|
|
662
|
+
prettifyModelId,
|
|
663
|
+
getTierForModel
|
|
676
664
|
};
|
package/src/ai/stream-parser.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Stream Parser - Side-channel parser for real-time AI streaming events
|
|
4
4
|
*
|
|
5
5
|
* Reads stdout data incrementally from provider processes and emits normalized
|
|
6
|
-
* events for display in the
|
|
6
|
+
* events for display in the progress modal. This is a read-only side channel;
|
|
7
7
|
* the existing stdout buffering and final JSON extraction remain untouched.
|
|
8
8
|
*
|
|
9
9
|
* Normalized event shape:
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Chat Module Conventions
|
|
2
|
+
|
|
3
|
+
## Action handler pattern (ChatPanel.js)
|
|
4
|
+
|
|
5
|
+
All action handlers (adopt, update, dismiss) follow identical structure:
|
|
6
|
+
1. Guard: if streaming or no `_contextItemId`, return early
|
|
7
|
+
2. Set `_pendingActionContext` with `{ type, itemId }`
|
|
8
|
+
3. Set `inputEl.value` to clean, human-readable text (NO item IDs)
|
|
9
|
+
4. Call `sendMessage()`
|
|
10
|
+
|
|
11
|
+
See `_handleAdoptClick` as the canonical example. New action handlers must follow this pattern.
|
|
12
|
+
|
|
13
|
+
## Action metadata separation
|
|
14
|
+
|
|
15
|
+
Item IDs never appear in user-visible message text. They flow through:
|
|
16
|
+
`_pendingActionContext` (frontend) → `actionContext` (API payload) → `[Action: ...]` hint (agent-facing message in session-manager.js)
|
|
17
|
+
|
|
18
|
+
This keeps the chat transcript clean while giving the agent structured metadata it can parse reliably.
|