@in-the-loop-labs/pair-review 2.5.0 → 2.6.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.
- package/.pi/extensions/task/index.ts +5 -2
- package/config.managed.json +1 -0
- package/package.json +2 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin-code-critic/.claude-plugin/plugin.json +1 -1
- package/public/index.html +9 -0
- package/public/js/index.js +6 -0
- package/public/setup.html +19 -0
- package/src/ai/claude-provider.js +8 -1
- package/src/ai/codex-provider.js +12 -2
- package/src/ai/cursor-agent-provider.js +18 -0
- package/src/ai/pi-provider.js +6 -7
- package/src/chat/pi-bridge.js +3 -6
- package/src/config.js +8 -2
- package/src/routes/config.js +2 -0
|
@@ -205,10 +205,13 @@ async function runTask(
|
|
|
205
205
|
onUpdate: OnUpdate | undefined,
|
|
206
206
|
makeDetails: (results: TaskResult[]) => TaskDetails,
|
|
207
207
|
): Promise<TaskResult> {
|
|
208
|
-
// Build args: full tool access, JSON output, no session persistence
|
|
208
|
+
// Build args: full tool access, JSON output, no session persistence.
|
|
209
|
+
// Skills and extensions are left enabled so subtasks have access to the
|
|
210
|
+
// user's configured environment. --no-prompt-templates is kept because
|
|
211
|
+
// prompt templates can't be triggered in -p mode.
|
|
209
212
|
const args: string[] = [
|
|
210
213
|
"--mode", "json", "-p", "--no-session",
|
|
211
|
-
"--no-
|
|
214
|
+
"--no-prompt-templates",
|
|
212
215
|
"-e", EXTENSION_DIR,
|
|
213
216
|
];
|
|
214
217
|
if (model) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@in-the-loop-labs/pair-review",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.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": {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"public/",
|
|
15
15
|
"plugin/",
|
|
16
16
|
"plugin-code-critic/",
|
|
17
|
+
"config.managed.json",
|
|
17
18
|
"README.md",
|
|
18
19
|
"LICENSE"
|
|
19
20
|
],
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pair-review",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.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",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "code-critic",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.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/index.html
CHANGED
|
@@ -177,6 +177,14 @@
|
|
|
177
177
|
color: var(--color-text-primary);
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
+
.app-version {
|
|
181
|
+
color: var(--color-fg-muted, #656d76);
|
|
182
|
+
font-size: 12px;
|
|
183
|
+
font-weight: 400;
|
|
184
|
+
margin-left: 6px;
|
|
185
|
+
opacity: 0.7;
|
|
186
|
+
}
|
|
187
|
+
|
|
180
188
|
.header-right {
|
|
181
189
|
display: flex;
|
|
182
190
|
align-items: center;
|
|
@@ -1089,6 +1097,7 @@
|
|
|
1089
1097
|
<path transform="rotate(-50 12 12)" d="M18.178 8c5.096 0 5.096 8 0 8-5.095 0-7.133-8-12.356-8-5.096 0-5.096 8 0 8 5.223 0 7.26-8 12.356-8z"/>
|
|
1090
1098
|
</svg>
|
|
1091
1099
|
<span class="logo-text">pair<span class="logo-accent">review</span></span>
|
|
1100
|
+
<span id="app-version" class="app-version"></span>
|
|
1092
1101
|
</a>
|
|
1093
1102
|
</div>
|
|
1094
1103
|
<div class="header-right">
|
package/public/js/index.js
CHANGED
|
@@ -1092,6 +1092,12 @@
|
|
|
1092
1092
|
const config = await response.json();
|
|
1093
1093
|
updateCommandExamples(config.is_running_via_npx);
|
|
1094
1094
|
|
|
1095
|
+
// Display version in header
|
|
1096
|
+
if (config.version) {
|
|
1097
|
+
const versionEl = document.getElementById('app-version');
|
|
1098
|
+
if (versionEl) versionEl.textContent = 'v' + config.version;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1095
1101
|
// Expose chat provider config to components (ChatPanel reads these)
|
|
1096
1102
|
window.__pairReview = window.__pairReview || {};
|
|
1097
1103
|
window.__pairReview.chatProvider = config.chat_provider || 'pi';
|
package/public/setup.html
CHANGED
|
@@ -137,6 +137,14 @@
|
|
|
137
137
|
color: var(--color-text-primary);
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
+
.app-version {
|
|
141
|
+
color: var(--color-fg-muted, #656d76);
|
|
142
|
+
font-size: 12px;
|
|
143
|
+
font-weight: 400;
|
|
144
|
+
margin-left: 6px;
|
|
145
|
+
opacity: 0.7;
|
|
146
|
+
}
|
|
147
|
+
|
|
140
148
|
.setup-target {
|
|
141
149
|
font-family: var(--font-mono);
|
|
142
150
|
font-size: 15px;
|
|
@@ -463,6 +471,7 @@
|
|
|
463
471
|
<path transform="rotate(-50 12 12)" d="M18.178 8c5.096 0 5.096 8 0 8-5.095 0-7.133-8-12.356-8-5.096 0-5.096 8 0 8 5.223 0 7.26-8 12.356-8z"/>
|
|
464
472
|
</svg>
|
|
465
473
|
<span class="logo-text">pair<span class="logo-accent">review</span></span>
|
|
474
|
+
<span id="app-version" class="app-version"></span>
|
|
466
475
|
</a>
|
|
467
476
|
<div class="setup-target" id="setup-target"></div>
|
|
468
477
|
<div class="setup-subtitle">Setting up review</div>
|
|
@@ -839,6 +848,16 @@
|
|
|
839
848
|
});
|
|
840
849
|
}
|
|
841
850
|
|
|
851
|
+
/* ── Display Version ── */
|
|
852
|
+
fetch('/api/config').then(function(r) {
|
|
853
|
+
return r.ok ? r.json() : null;
|
|
854
|
+
}).then(function(config) {
|
|
855
|
+
if (config && config.version) {
|
|
856
|
+
var versionEl = document.getElementById('app-version');
|
|
857
|
+
if (versionEl) versionEl.textContent = 'v' + config.version;
|
|
858
|
+
}
|
|
859
|
+
}).catch(function() { /* non-critical */ });
|
|
860
|
+
|
|
842
861
|
/* ── Kick Off ── */
|
|
843
862
|
startSetup();
|
|
844
863
|
})();
|
|
@@ -174,7 +174,14 @@ class ClaudeProvider extends AIProvider {
|
|
|
174
174
|
].join(',');
|
|
175
175
|
permissionArgs = ['--allowedTools', allowedTools];
|
|
176
176
|
}
|
|
177
|
-
|
|
177
|
+
// Suppress user hooks in analysis subprocesses to avoid side-effects
|
|
178
|
+
// (notifications, confirmations, etc.) firing on every tool call during review.
|
|
179
|
+
// Uses --settings '{"disableAllHooks":true}' since Claude has no --no-hooks flag.
|
|
180
|
+
// Skills and extensions are left enabled so the subprocess has access to the
|
|
181
|
+
// user's configured environment. To disable skills, add --disable-slash-commands
|
|
182
|
+
// to extra_args in provider/model config.
|
|
183
|
+
const hooksArgs = ['--settings', '{"disableAllHooks":true}'];
|
|
184
|
+
const baseArgs = ['-p', '--verbose', ...cliModelArgs, '--output-format', 'stream-json', ...hooksArgs, ...permissionArgs];
|
|
178
185
|
if (maxBudget) {
|
|
179
186
|
const budgetNum = parseFloat(maxBudget);
|
|
180
187
|
if (isNaN(budgetNum) || budgetNum <= 0) {
|
package/src/ai/codex-provider.js
CHANGED
|
@@ -23,7 +23,8 @@ const BIN_DIR = path.join(__dirname, '..', '..', 'bin');
|
|
|
23
23
|
* Based on OpenAI Codex Models guide (developers.openai.com/codex/models)
|
|
24
24
|
* - gpt-5.1-codex-mini: Smaller, cost-effective variant for quick scans
|
|
25
25
|
* - gpt-5.2-codex: Advanced coding model for everyday reviews, good reasoning/cost balance
|
|
26
|
-
* - gpt-5.3-codex:
|
|
26
|
+
* - gpt-5.3-codex: Capable agentic coding model with frontier performance and reasoning
|
|
27
|
+
* - gpt-5.4: Latest generation with enhanced reasoning depth
|
|
27
28
|
*/
|
|
28
29
|
const CODEX_MODELS = [
|
|
29
30
|
{
|
|
@@ -50,7 +51,16 @@ const CODEX_MODELS = [
|
|
|
50
51
|
name: 'GPT-5.3 Codex',
|
|
51
52
|
tier: 'thorough',
|
|
52
53
|
tagline: 'Deep Review',
|
|
53
|
-
description: '
|
|
54
|
+
description: 'Capable agentic coding model—combines frontier coding performance with strong reasoning for cross-file analysis.',
|
|
55
|
+
badge: 'Thorough',
|
|
56
|
+
badgeClass: 'badge-power'
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'gpt-5.4',
|
|
60
|
+
name: 'GPT-5.4',
|
|
61
|
+
tier: 'thorough',
|
|
62
|
+
tagline: 'Latest Gen',
|
|
63
|
+
description: 'Latest generation model with enhanced reasoning depth for complex architectural reviews.',
|
|
54
64
|
badge: 'Most Thorough',
|
|
55
65
|
badgeClass: 'badge-power'
|
|
56
66
|
}
|
|
@@ -143,6 +143,24 @@ const CURSOR_AGENT_MODELS = [
|
|
|
143
143
|
description: 'Deep analysis with extended thinking—Cursor default for maximum review quality',
|
|
144
144
|
badge: 'Most Thorough',
|
|
145
145
|
badgeClass: 'badge-power'
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
id: 'gpt-5.4-high',
|
|
149
|
+
name: 'GPT-5.4 High',
|
|
150
|
+
tier: 'thorough',
|
|
151
|
+
tagline: 'Latest OpenAI',
|
|
152
|
+
description: 'Latest generation with high reasoning effort—strong for complex architectural reviews',
|
|
153
|
+
badge: 'Latest Gen',
|
|
154
|
+
badgeClass: 'badge-power'
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
id: 'gpt-5.4-medium',
|
|
158
|
+
name: 'GPT-5.4',
|
|
159
|
+
tier: 'thorough',
|
|
160
|
+
tagline: 'Latest Gen',
|
|
161
|
+
description: 'Latest generation at medium reasoning depth',
|
|
162
|
+
badge: 'Latest',
|
|
163
|
+
badgeClass: 'badge-power'
|
|
146
164
|
}
|
|
147
165
|
];
|
|
148
166
|
|
package/src/ai/pi-provider.js
CHANGED
|
@@ -189,24 +189,23 @@ class PiProvider extends AIProvider {
|
|
|
189
189
|
// --no-session: Each pi invocation is an ephemeral analysis — there's no need to
|
|
190
190
|
// persist session state between runs. Set PAIR_REVIEW_PI_SESSION=1
|
|
191
191
|
// to enable session saving for debugging (sessions saved to ~/.pi/sessions/).
|
|
192
|
-
// --no-skills: Skills are disabled by default to keep runs deterministic. A skill can
|
|
193
|
-
// still be loaded via `--skill` in model-specific `extra_args` if needed.
|
|
194
|
-
|
|
195
192
|
// Build args: base args + built-in extra_args + provider extra_args + model extra_args
|
|
196
193
|
// In yolo mode, omit --tools entirely to allow all tools (including edit, write)
|
|
197
194
|
// The task extension is loaded to give the model a subagent tool for delegating
|
|
198
195
|
// work to isolated subprocesses, preserving the main context window.
|
|
199
|
-
// --no-
|
|
200
|
-
//
|
|
196
|
+
// --no-prompt-templates: prompt templates can't be triggered in -p mode, so suppress
|
|
197
|
+
// them to avoid wasting context. Skills and extensions are left enabled so the
|
|
198
|
+
// subprocess has access to the user's configured environment. To disable them,
|
|
199
|
+
// add --no-skills or --no-extensions to extra_args in provider/model config.
|
|
201
200
|
const sessionArgs = process.env.PAIR_REVIEW_PI_SESSION ? [] : ['--no-session'];
|
|
202
201
|
let baseArgs;
|
|
203
202
|
if (configOverrides.yolo) {
|
|
204
203
|
baseArgs = ['-p', '--mode', 'json', ...cliModelArgs, ...sessionArgs,
|
|
205
|
-
'--no-
|
|
204
|
+
'--no-prompt-templates',
|
|
206
205
|
'-e', TASK_EXTENSION_DIR];
|
|
207
206
|
} else {
|
|
208
207
|
baseArgs = ['-p', '--mode', 'json', ...cliModelArgs, '--tools', 'read,bash,grep,find,ls', ...sessionArgs,
|
|
209
|
-
'--no-
|
|
208
|
+
'--no-prompt-templates',
|
|
210
209
|
'-e', TASK_EXTENSION_DIR];
|
|
211
210
|
}
|
|
212
211
|
const builtInArgs = builtIn?.extra_args || [];
|
package/src/chat/pi-bridge.js
CHANGED
|
@@ -273,12 +273,9 @@ class PiBridge extends EventEmitter {
|
|
|
273
273
|
}
|
|
274
274
|
|
|
275
275
|
// Load extensions via -e (e.g., task extension for subagent delegation).
|
|
276
|
-
//
|
|
277
|
-
|
|
278
|
-
args.push('
|
|
279
|
-
for (const ext of this.extensions) {
|
|
280
|
-
args.push('-e', ext);
|
|
281
|
-
}
|
|
276
|
+
// These are additive — the user's auto-discovered extensions remain available.
|
|
277
|
+
for (const ext of this.extensions) {
|
|
278
|
+
args.push('-e', ext);
|
|
282
279
|
}
|
|
283
280
|
|
|
284
281
|
return args;
|
package/src/config.js
CHANGED
|
@@ -13,6 +13,7 @@ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
|
13
13
|
const CONFIG_LOCAL_FILE = path.join(CONFIG_DIR, 'config.local.json');
|
|
14
14
|
const CONFIG_EXAMPLE_FILE = path.join(CONFIG_DIR, 'config.example.json');
|
|
15
15
|
const PACKAGE_ROOT = path.join(__dirname, '..');
|
|
16
|
+
const MANAGED_CONFIG_FILE = path.join(PACKAGE_ROOT, 'config.managed.json');
|
|
16
17
|
|
|
17
18
|
const DEFAULT_CONFIG = {
|
|
18
19
|
github_token: "",
|
|
@@ -175,6 +176,7 @@ async function loadConfig() {
|
|
|
175
176
|
|
|
176
177
|
const localDir = path.join(process.cwd(), '.pair-review');
|
|
177
178
|
const sources = [
|
|
179
|
+
{ path: MANAGED_CONFIG_FILE, label: 'managed config', required: false },
|
|
178
180
|
{ path: CONFIG_FILE, label: 'global config', required: true },
|
|
179
181
|
{ path: CONFIG_LOCAL_FILE, label: 'global local config', required: false },
|
|
180
182
|
{ path: path.join(localDir, 'config.json'), label: 'project config', required: false },
|
|
@@ -183,22 +185,26 @@ async function loadConfig() {
|
|
|
183
185
|
|
|
184
186
|
let mergedConfig = { ...DEFAULT_CONFIG };
|
|
185
187
|
let isFirstRun = false;
|
|
188
|
+
let hasManagedConfig = false;
|
|
186
189
|
|
|
187
190
|
for (const source of sources) {
|
|
188
191
|
try {
|
|
189
192
|
const data = await fs.readFile(source.path, 'utf8');
|
|
190
193
|
const parsed = JSON.parse(data);
|
|
194
|
+
if (source.label === 'managed config' && Object.keys(parsed).length > 0) {
|
|
195
|
+
hasManagedConfig = true;
|
|
196
|
+
}
|
|
191
197
|
mergedConfig = deepMerge(mergedConfig, parsed);
|
|
192
198
|
} catch (error) {
|
|
193
199
|
if (error.code === 'ENOENT') {
|
|
194
|
-
if (source.required) {
|
|
200
|
+
if (source.required && !hasManagedConfig) {
|
|
195
201
|
// Global config doesn't exist — create it with defaults
|
|
196
202
|
const config = { ...DEFAULT_CONFIG };
|
|
197
203
|
await saveConfig(config);
|
|
198
204
|
logger.debug(`Created default config file: ${CONFIG_FILE}`);
|
|
199
205
|
isFirstRun = true;
|
|
200
206
|
}
|
|
201
|
-
// Optional files: skip silently
|
|
207
|
+
// Optional files or managed-config-present: skip silently
|
|
202
208
|
} else if (error instanceof SyntaxError) {
|
|
203
209
|
if (source.required) {
|
|
204
210
|
console.error(`Invalid configuration file at ~/.pair-review/config.json`);
|
package/src/routes/config.js
CHANGED
|
@@ -21,6 +21,7 @@ const {
|
|
|
21
21
|
} = require('../ai');
|
|
22
22
|
const { normalizeRepository } = require('../utils/paths');
|
|
23
23
|
const { isRunningViaNpx, saveConfig } = require('../config');
|
|
24
|
+
const { version } = require('../../package.json');
|
|
24
25
|
const { getAllChatProviders, getAllCachedChatAvailability } = require('../chat/chat-providers');
|
|
25
26
|
const { PRESETS } = require('../utils/comment-formatter');
|
|
26
27
|
const logger = require('../utils/logger');
|
|
@@ -42,6 +43,7 @@ router.get('/api/config', (req, res) => {
|
|
|
42
43
|
|
|
43
44
|
// Only return safe configuration values (not secrets like github_token)
|
|
44
45
|
res.json({
|
|
46
|
+
version,
|
|
45
47
|
theme: config.theme || 'light',
|
|
46
48
|
comment_button_action: config.comment_button_action || 'submit',
|
|
47
49
|
comment_format: config.comment_format || 'legacy',
|