@in-the-loop-labs/pair-review 3.7.1 → 3.7.2
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pair-review",
|
|
3
|
-
"version": "3.7.
|
|
3
|
+
"version": "3.7.2",
|
|
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.7.
|
|
3
|
+
"version": "3.7.2",
|
|
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/js/pr.js
CHANGED
|
@@ -1690,8 +1690,12 @@ class PRManager {
|
|
|
1690
1690
|
label = 'Exit guided tour';
|
|
1691
1691
|
} else if (this._tourStops && this._tourStops.length > 0) {
|
|
1692
1692
|
label = 'Start guided tour';
|
|
1693
|
+
} else if (this._toursAutoGenerate === false) {
|
|
1694
|
+
// No stops yet and auto-generation is off: a click kicks off manual
|
|
1695
|
+
// generation (see startOrToggleTour), so the verb is "Generate".
|
|
1696
|
+
label = 'Generate guided tour';
|
|
1693
1697
|
} else {
|
|
1694
|
-
label = '
|
|
1698
|
+
label = 'Guided tour (none available yet)';
|
|
1695
1699
|
}
|
|
1696
1700
|
btn.title = label;
|
|
1697
1701
|
btn.setAttribute('aria-label', label);
|
|
@@ -19,7 +19,7 @@ const { normalizeRepository } = require('../utils/paths');
|
|
|
19
19
|
const { mergeInstructions } = require('../utils/instructions');
|
|
20
20
|
const { GitWorktreeManager } = require('../git/worktree');
|
|
21
21
|
const { GitHubClient } = require('../github/client');
|
|
22
|
-
const { getGitHubToken, resolveHostBinding, resolveBindingRepositoryFromPR, resolveLoadSkills, buildCouncilProviderOverrides } = require('../config');
|
|
22
|
+
const { getGitHubToken, resolveHostBinding, resolveBindingRepositoryFromPR, resolveRepoOptions, resolveLoadSkills, buildCouncilProviderOverrides } = require('../config');
|
|
23
23
|
const { setupStackPR } = require('../setup/stack-setup');
|
|
24
24
|
const Analyzer = require('../ai/analyzer');
|
|
25
25
|
const { getProviderClass, createProvider } = require('../ai/provider');
|
|
@@ -166,6 +166,7 @@ const defaults = {
|
|
|
166
166
|
getGitHubToken,
|
|
167
167
|
resolveHostBinding,
|
|
168
168
|
resolveBindingRepositoryFromPR,
|
|
169
|
+
resolveRepoOptions,
|
|
169
170
|
setupStackPR,
|
|
170
171
|
Analyzer,
|
|
171
172
|
getProviderClass,
|
|
@@ -205,8 +206,23 @@ async function executeStackAnalysis(params) {
|
|
|
205
206
|
if (!state) return;
|
|
206
207
|
|
|
207
208
|
try {
|
|
209
|
+
// 0. Resolve the config-binding key once. It drives both the per-repo
|
|
210
|
+
// worktree config (just below) and the host binding (step 3). For
|
|
211
|
+
// monorepo-style `url_pattern` configs this differs from the PR
|
|
212
|
+
// identity `${owner}/${repo}`.
|
|
213
|
+
const bindingRepository = deps.resolveBindingRepositoryFromPR(owner, repo, config);
|
|
214
|
+
// Honor the repo's configured worktree options so stack worktrees match the
|
|
215
|
+
// non-stack path. This carries through:
|
|
216
|
+
// - worktreeConfig (worktree_name_template / worktree_directory) so they
|
|
217
|
+
// don't fall back to pair-review's default naming and location, and
|
|
218
|
+
// - the checkout script + timeout and sparse-checkout inheritance used
|
|
219
|
+
// during per-PR worktree creation (forwarded to createWorktreeForPR).
|
|
220
|
+
// These derive purely from file config, so DB repo_settings (pool config)
|
|
221
|
+
// are not needed here.
|
|
222
|
+
const { worktreeConfig, checkoutScript, checkoutTimeout } = deps.resolveRepoOptions(config, bindingRepository);
|
|
223
|
+
|
|
208
224
|
// 1. Resolve repositoryPath from trigger worktree
|
|
209
|
-
const worktreeManager = new deps.GitWorktreeManager(db);
|
|
225
|
+
const worktreeManager = new deps.GitWorktreeManager(db, worktreeConfig || {});
|
|
210
226
|
let repositoryPath;
|
|
211
227
|
try {
|
|
212
228
|
const owningRepoGit = await worktreeManager.resolveOwningRepo(triggerWorktreePath);
|
|
@@ -230,13 +246,13 @@ async function executeStackAnalysis(params) {
|
|
|
230
246
|
logger.warn(`Bulk git fetch failed, will fetch per-PR: ${fetchError.message}`);
|
|
231
247
|
}
|
|
232
248
|
|
|
233
|
-
// 3. Fetch all PR data from GitHub in parallel
|
|
234
|
-
//
|
|
235
|
-
//
|
|
236
|
-
//
|
|
237
|
-
//
|
|
238
|
-
//
|
|
239
|
-
|
|
249
|
+
// 3. Fetch all PR data from GitHub in parallel.
|
|
250
|
+
// `bindingRepository` (resolved in step 0) is the config-binding key. We use
|
|
251
|
+
// it — not the PR identity `${owner}/${repo}` — for host-binding lookups so
|
|
252
|
+
// alt-host stack analyses target the right host. The two differ for
|
|
253
|
+
// monorepo-style `url_pattern` configs (one `repos[...]` entry serves many
|
|
254
|
+
// captured owner/repo pairs). The PR identity is still used for DB rows and
|
|
255
|
+
// worktree identity.
|
|
240
256
|
const stackBinding = deps.resolveHostBinding(bindingRepository, config);
|
|
241
257
|
const githubToken = stackBinding.token;
|
|
242
258
|
const prDataMap = new Map();
|
|
@@ -275,7 +291,16 @@ async function executeStackAnalysis(params) {
|
|
|
275
291
|
|
|
276
292
|
const prInfo = { owner, repo, number: prNum };
|
|
277
293
|
const { path: perPRWorktreePath } = await worktreeManager.createWorktreeForPR(
|
|
278
|
-
prInfo, prData, repositoryPath
|
|
294
|
+
prInfo, prData, repositoryPath,
|
|
295
|
+
{
|
|
296
|
+
checkoutScript,
|
|
297
|
+
checkoutTimeout,
|
|
298
|
+
// No checkout script → inherit the trigger worktree's sparse-checkout
|
|
299
|
+
// layout instead of a full checkout from the repo root. When a script is
|
|
300
|
+
// configured it sets up sparse-checkout itself, so worktreeSourcePath is
|
|
301
|
+
// unused (and omitted) in that case.
|
|
302
|
+
...(checkoutScript ? {} : { worktreeSourcePath: triggerWorktreePath }),
|
|
303
|
+
}
|
|
279
304
|
);
|
|
280
305
|
worktreePathMap.set(prNum, perPRWorktreePath);
|
|
281
306
|
} catch (wtError) {
|
|
@@ -307,6 +332,7 @@ async function executeStackAnalysis(params) {
|
|
|
307
332
|
worktreePath: worktreePathMap.get(prNum),
|
|
308
333
|
analysisConfig, stackAnalysisId, state,
|
|
309
334
|
githubToken, binding: stackBinding, prData: prDataMap.get(prNum),
|
|
335
|
+
worktreeConfig, checkoutScript,
|
|
310
336
|
onAnalysisIdReady
|
|
311
337
|
}).then(result => {
|
|
312
338
|
state.prStatuses.set(prNum, {
|
|
@@ -346,6 +372,7 @@ async function executeStackAnalysis(params) {
|
|
|
346
372
|
async function analyzeStackPR(deps, db, config, {
|
|
347
373
|
owner, repo, repository, bindingRepository, prNum, worktreePath,
|
|
348
374
|
analysisConfig, stackAnalysisId, state, githubToken, binding, prData,
|
|
375
|
+
worktreeConfig, checkoutScript,
|
|
349
376
|
onAnalysisIdReady
|
|
350
377
|
}) {
|
|
351
378
|
// Build a GitHubClient for analyzer-side dedup pre-fetch. The stack
|
|
@@ -357,12 +384,17 @@ async function analyzeStackPR(deps, db, config, {
|
|
|
357
384
|
if (stackGithubClient) {
|
|
358
385
|
logger.debug(`analyzer githubClient wired for ${owner}/${repo}#${prNum} (stack)`);
|
|
359
386
|
}
|
|
360
|
-
// 1. Setup PR (generates diff, stores metadata)
|
|
361
|
-
|
|
387
|
+
// 1. Setup PR (expands sparse-checkout, generates diff, stores metadata)
|
|
388
|
+
// Construct with the repo's resolved worktreeConfig for consistency with the
|
|
389
|
+
// creation manager. setupStackPR operates against the explicit worktreePath
|
|
390
|
+
// (diff generation + sparse-cone expansion), so the worktreeConfig naming /
|
|
391
|
+
// directory options are not exercised today — threading them through guards
|
|
392
|
+
// against silent latent regressions if that changes.
|
|
393
|
+
const worktreeManager = new deps.GitWorktreeManager(db, worktreeConfig || {});
|
|
362
394
|
await deps.setupStackPR({
|
|
363
395
|
db, owner, repo, prNumber: prNum,
|
|
364
396
|
githubToken, binding, bindingRepository,
|
|
365
|
-
worktreePath, worktreeManager, prData
|
|
397
|
+
worktreePath, worktreeManager, prData, checkoutScript
|
|
366
398
|
});
|
|
367
399
|
|
|
368
400
|
// 2. Fetch prMetadata from DB
|
package/src/setup/stack-setup.js
CHANGED
|
@@ -32,9 +32,12 @@ const logger = require('../utils/logger');
|
|
|
32
32
|
* @param {string} params.worktreePath - Path to the per-PR worktree
|
|
33
33
|
* @param {import('../git/worktree').GitWorktreeManager} params.worktreeManager - Worktree manager instance
|
|
34
34
|
* @param {Object} [params.prData] - Pre-fetched PR data from GitHub (skips API call when provided)
|
|
35
|
+
* @param {string|null} [params.checkoutScript] - Repo's configured checkout script, if any. When set,
|
|
36
|
+
* the script owns all sparse-checkout setup, so built-in sparse-cone expansion is skipped (mirrors
|
|
37
|
+
* the non-stack `pr-setup.js` contract).
|
|
35
38
|
* @returns {Promise<{ reviewId: number, prMetadata: Object, prData: Object, isNew: boolean }>}
|
|
36
39
|
*/
|
|
37
|
-
async function setupStackPR({ db, owner, repo, prNumber, githubToken, binding, bindingRepository, worktreePath, worktreeManager, prData: prefetchedPRData }) {
|
|
40
|
+
async function setupStackPR({ db, owner, repo, prNumber, githubToken, binding, bindingRepository, worktreePath, worktreeManager, prData: prefetchedPRData, checkoutScript }) {
|
|
38
41
|
// `bindingRepository` is accepted so callers (e.g. `executeStackAnalysis`)
|
|
39
42
|
// can thread the resolved config-binding key through to any downstream
|
|
40
43
|
// per-repo lookups added in this function. Currently unused inside this
|
|
@@ -56,13 +59,38 @@ async function setupStackPR({ db, owner, repo, prNumber, githubToken, binding, b
|
|
|
56
59
|
const prFiles = await githubClient.fetchPullRequestFiles(owner, repo, prNumber);
|
|
57
60
|
logger.info(`PR #${prNumber} has ${prFiles.length} changed files`);
|
|
58
61
|
|
|
59
|
-
// 3.
|
|
62
|
+
// 3. Expand sparse-checkout for PR-changed directories (mirrors pr-setup.js).
|
|
63
|
+
// Stack worktrees inherit the trigger worktree's sparse-checkout layout, which
|
|
64
|
+
// may omit directories a sibling PR touches. The SHA-based diff below reads
|
|
65
|
+
// commit objects (not the working tree) so it is unaffected, but the later
|
|
66
|
+
// file-context and codebase-context analysis steps DO read files from disk —
|
|
67
|
+
// an unexpanded cone would silently under-review those files. Expanding here
|
|
68
|
+
// ensures every PR-changed directory is present on disk.
|
|
69
|
+
//
|
|
70
|
+
// IMPORTANT: when a checkout_script is configured the script owns all
|
|
71
|
+
// sparse-checkout setup, so we must NOT auto-expand — doing so would override
|
|
72
|
+
// the cone the script just configured. This matches the pr-setup.js contract.
|
|
73
|
+
if (!checkoutScript && prFiles.length > 0) {
|
|
74
|
+
const isSparse = await worktreeManager.isSparseCheckoutEnabled(worktreePath);
|
|
75
|
+
if (isSparse) {
|
|
76
|
+
try {
|
|
77
|
+
const addedDirs = await worktreeManager.ensurePRDirectoriesInSparseCheckout(worktreePath, prFiles);
|
|
78
|
+
if (addedDirs.length > 0) {
|
|
79
|
+
logger.info(`Stack PR #${prNumber}: expanded sparse-checkout for: ${addedDirs.join(', ')}`);
|
|
80
|
+
}
|
|
81
|
+
} catch (sparseError) {
|
|
82
|
+
logger.warn(`Stack PR #${prNumber}: sparse-checkout expansion failed (non-fatal): ${sparseError.message}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 4. Generate diff in the worktree (SHA-based, works after checkout)
|
|
60
88
|
const diff = await worktreeManager.generateUnifiedDiff(worktreePath, prData);
|
|
61
89
|
|
|
62
|
-
//
|
|
90
|
+
// 5. Get changed files with stats
|
|
63
91
|
const changedFiles = await worktreeManager.getChangedFiles(worktreePath, prData);
|
|
64
92
|
|
|
65
|
-
//
|
|
93
|
+
// 6. Store via storePRData (creates/updates pr_metadata, reviews, worktrees records)
|
|
66
94
|
const prInfo = { owner, repo, number: prNumber };
|
|
67
95
|
const { isNewReview, reviewId } = await storePRData(db, prInfo, prData, diff, changedFiles, worktreePath);
|
|
68
96
|
|