@in-the-loop-labs/pair-review 2.6.2 → 2.7.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/bin/git-diff-lines +1 -1
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin-code-critic/.claude-plugin/plugin.json +1 -1
- package/plugin-code-critic/skills/analyze/scripts/git-diff-lines +1 -1
- package/public/css/pr.css +201 -0
- package/public/index.html +168 -3
- package/public/js/components/AIPanel.js +16 -2
- package/public/js/components/ChatPanel.js +41 -6
- package/public/js/components/ConfirmDialog.js +21 -2
- package/public/js/components/CouncilProgressModal.js +13 -0
- package/public/js/components/DiffOptionsDropdown.js +410 -23
- package/public/js/components/SuggestionNavigator.js +12 -5
- package/public/js/components/TabTitle.js +96 -0
- package/public/js/components/Toast.js +6 -0
- package/public/js/index.js +648 -43
- package/public/js/local.js +569 -76
- package/public/js/modules/analysis-history.js +3 -2
- package/public/js/modules/comment-manager.js +5 -0
- package/public/js/modules/comment-minimizer.js +304 -0
- package/public/js/pr.js +82 -6
- package/public/local.html +14 -0
- package/public/pr.html +3 -0
- package/src/ai/analyzer.js +22 -16
- package/src/ai/cursor-agent-provider.js +21 -12
- package/src/chat/prompt-builder.js +3 -3
- package/src/config.js +2 -0
- package/src/database.js +590 -39
- package/src/git/base-branch.js +173 -0
- package/src/git/sha-abbrev.js +35 -0
- package/src/git/worktree.js +3 -2
- package/src/github/client.js +32 -1
- package/src/hooks/hook-runner.js +100 -0
- package/src/hooks/payloads.js +212 -0
- package/src/local-review.js +468 -129
- package/src/local-scope.js +58 -0
- package/src/main.js +57 -6
- package/src/routes/analyses.js +73 -10
- package/src/routes/chat.js +33 -0
- package/src/routes/config.js +1 -0
- package/src/routes/github-collections.js +2 -2
- package/src/routes/local.js +734 -68
- package/src/routes/mcp.js +20 -10
- package/src/routes/pr.js +92 -14
- package/src/routes/setup.js +1 -0
- package/src/routes/worktrees.js +212 -148
- package/src/server.js +30 -0
- package/src/setup/local-setup.js +46 -5
- package/src/setup/pr-setup.js +28 -5
- package/src/utils/diff-file-list.js +1 -1
package/src/ai/analyzer.js
CHANGED
|
@@ -659,7 +659,7 @@ Do NOT create suggestions for any files not in this list. If you cannot find iss
|
|
|
659
659
|
async getChangedFilesList(worktreePath, prMetadata) {
|
|
660
660
|
try {
|
|
661
661
|
const { stdout } = await execPromise(
|
|
662
|
-
`git diff ${prMetadata.base_sha}...${prMetadata.head_sha} --name-only`,
|
|
662
|
+
`git diff --no-ext-diff ${prMetadata.base_sha}...${prMetadata.head_sha} --name-only`,
|
|
663
663
|
{ cwd: worktreePath }
|
|
664
664
|
);
|
|
665
665
|
return stdout.trim().split('\n').filter(f => f.length > 0);
|
|
@@ -670,22 +670,20 @@ Do NOT create suggestions for any files not in this list. If you cannot find iss
|
|
|
670
670
|
}
|
|
671
671
|
|
|
672
672
|
/**
|
|
673
|
-
* Get list of changed files for local mode analysis
|
|
674
|
-
*
|
|
675
|
-
*
|
|
676
|
-
* Design note: Staged files are intentionally excluded. Local mode focuses on
|
|
677
|
-
* reviewing uncommitted working directory changes before they are staged.
|
|
678
|
-
* Staged changes are considered "ready to commit" and outside the scope of
|
|
679
|
-
* local review at this point.
|
|
673
|
+
* Get list of changed files for local mode analysis.
|
|
674
|
+
* By default includes unstaged changes and untracked files.
|
|
675
|
+
* When `options.includeStaged` is true, also includes staged (git add'd) files.
|
|
680
676
|
*
|
|
681
677
|
* @param {string} localPath - Path to the local git repository
|
|
678
|
+
* @param {Object} [options]
|
|
679
|
+
* @param {boolean} [options.includeStaged] - Also include staged files
|
|
682
680
|
* @returns {Promise<Array<string>>} List of changed file paths
|
|
683
681
|
*/
|
|
684
|
-
async getLocalChangedFiles(localPath) {
|
|
682
|
+
async getLocalChangedFiles(localPath, options = {}) {
|
|
685
683
|
try {
|
|
686
|
-
// Get modified tracked files (unstaged
|
|
684
|
+
// Get modified tracked files (unstaged)
|
|
687
685
|
const { stdout: unstaged } = await execPromise(
|
|
688
|
-
'git diff --name-only',
|
|
686
|
+
'git diff --no-ext-diff --name-only',
|
|
689
687
|
{ cwd: localPath }
|
|
690
688
|
);
|
|
691
689
|
|
|
@@ -695,12 +693,20 @@ Do NOT create suggestions for any files not in this list. If you cannot find iss
|
|
|
695
693
|
{ cwd: localPath }
|
|
696
694
|
);
|
|
697
695
|
|
|
698
|
-
// Combine and dedupe (no staged files - see design note above)
|
|
699
|
-
// Filter empty strings immediately after split to handle empty git output
|
|
700
696
|
const unstagedFiles = unstaged.trim().split('\n').filter(f => f.length > 0);
|
|
701
697
|
const untrackedFiles = untracked.trim().split('\n').filter(f => f.length > 0);
|
|
702
698
|
const allFiles = [...unstagedFiles, ...untrackedFiles];
|
|
703
699
|
|
|
700
|
+
// Include staged files when scope includes staged
|
|
701
|
+
if (options.includeStaged) {
|
|
702
|
+
const { stdout: staged } = await execPromise(
|
|
703
|
+
'git diff --no-ext-diff --cached --name-only',
|
|
704
|
+
{ cwd: localPath }
|
|
705
|
+
);
|
|
706
|
+
const stagedFiles = staged.trim().split('\n').filter(f => f.length > 0);
|
|
707
|
+
allFiles.push(...stagedFiles);
|
|
708
|
+
}
|
|
709
|
+
|
|
704
710
|
return [...new Set(allFiles)];
|
|
705
711
|
} catch (error) {
|
|
706
712
|
logger.warn(`Could not get local changed files for ${localPath}: ${error.message}`);
|
|
@@ -777,7 +783,7 @@ The following files are marked as generated in .gitattributes and should be SKIP
|
|
|
777
783
|
${generatedPatterns.map(p => `- ${p}`).join('\n')}
|
|
778
784
|
|
|
779
785
|
These are auto-generated files (like package-lock.json, build outputs, etc.) that should not be reviewed.
|
|
780
|
-
When running git diff, you can exclude these with: git diff ${'{base}'}...${'{head}'} -- ':!pattern' for each pattern.
|
|
786
|
+
When running git diff, you can exclude these with: git diff --no-ext-diff ${'{base}'}...${'{head}'} -- ':!pattern' for each pattern.
|
|
781
787
|
Or simply ignore any changes to files matching these patterns in your analysis.
|
|
782
788
|
`;
|
|
783
789
|
}
|
|
@@ -983,10 +989,10 @@ ${prMetadata.description || '(No description provided)'}
|
|
|
983
989
|
const isLocal = prMetadata.reviewType === 'local';
|
|
984
990
|
if (isLocal) {
|
|
985
991
|
// For local mode, diff against HEAD to see working directory changes
|
|
986
|
-
return suffix ? `git diff HEAD ${suffix}` : 'git diff HEAD';
|
|
992
|
+
return suffix ? `git diff --no-ext-diff HEAD ${suffix}` : 'git diff --no-ext-diff HEAD';
|
|
987
993
|
}
|
|
988
994
|
// For PR mode, diff between base and head commits
|
|
989
|
-
const baseCmd = `git diff ${prMetadata.base_sha}...${prMetadata.head_sha}`;
|
|
995
|
+
const baseCmd = `git diff --no-ext-diff ${prMetadata.base_sha}...${prMetadata.head_sha}`;
|
|
990
996
|
return suffix ? `${baseCmd} ${suffix}` : baseCmd;
|
|
991
997
|
}
|
|
992
998
|
|
|
@@ -30,9 +30,9 @@ const BIN_DIR = path.join(__dirname, '..', '..', 'bin');
|
|
|
30
30
|
*
|
|
31
31
|
* Tier structure:
|
|
32
32
|
* - free (auto): Cursor's default auto-routing model
|
|
33
|
-
* - fast (composer-
|
|
33
|
+
* - fast (composer-2-fast, gpt-5.3-codex-fast, gemini-3-flash): Quick analysis
|
|
34
34
|
* - balanced (composer-1.5, sonnet-4.6-thinking, sonnet-4.5-thinking, gemini-3.1-pro): Recommended for most reviews
|
|
35
|
-
* - thorough (gpt-5.3-codex-high, gpt-5.3-codex-xhigh, opus-4.5-thinking, opus-4.6-thinking): Deep analysis for complex code
|
|
35
|
+
* - thorough (composer-2, gpt-5.3-codex-high, gpt-5.3-codex-xhigh, opus-4.5-thinking, opus-4.6-thinking): Deep analysis for complex code
|
|
36
36
|
*/
|
|
37
37
|
const CURSOR_AGENT_MODELS = [
|
|
38
38
|
{
|
|
@@ -45,23 +45,32 @@ const CURSOR_AGENT_MODELS = [
|
|
|
45
45
|
badgeClass: 'badge-speed'
|
|
46
46
|
},
|
|
47
47
|
{
|
|
48
|
-
id: 'composer-
|
|
49
|
-
name: 'Composer
|
|
50
|
-
tier: '
|
|
48
|
+
id: 'composer-2',
|
|
49
|
+
name: 'Composer 2',
|
|
50
|
+
tier: 'thorough',
|
|
51
51
|
tagline: 'Latest Composer',
|
|
52
|
-
description: '
|
|
53
|
-
badge: '
|
|
54
|
-
badgeClass: 'badge-
|
|
52
|
+
description: 'Frontier-level coding model trained with compaction-in-the-loop RL—strong on long-horizon tasks requiring hundreds of actions',
|
|
53
|
+
badge: 'Latest',
|
|
54
|
+
badgeClass: 'badge-power'
|
|
55
55
|
},
|
|
56
56
|
{
|
|
57
|
-
id: 'composer-
|
|
58
|
-
name: 'Composer
|
|
57
|
+
id: 'composer-2-fast',
|
|
58
|
+
name: 'Composer 2 Fast',
|
|
59
59
|
tier: 'fast',
|
|
60
|
-
tagline: '
|
|
61
|
-
description: '
|
|
60
|
+
tagline: 'Fast Composer',
|
|
61
|
+
description: 'Same intelligence as Composer 2 with lower latency—default for interactive Cursor sessions',
|
|
62
62
|
badge: 'Fast',
|
|
63
63
|
badgeClass: 'badge-speed'
|
|
64
64
|
},
|
|
65
|
+
{
|
|
66
|
+
id: 'composer-1.5',
|
|
67
|
+
name: 'Composer 1.5',
|
|
68
|
+
tier: 'balanced',
|
|
69
|
+
tagline: 'Previous Composer',
|
|
70
|
+
description: 'Previous generation Cursor Composer model—positioned between Sonnet and Opus for multi-file edits',
|
|
71
|
+
badge: 'Previous Gen',
|
|
72
|
+
badgeClass: 'badge-balanced'
|
|
73
|
+
},
|
|
65
74
|
{
|
|
66
75
|
id: 'gpt-5.3-codex-fast',
|
|
67
76
|
name: 'GPT-5.3 Codex Fast',
|
|
@@ -124,8 +124,8 @@ function buildReviewContext(review, prData) {
|
|
|
124
124
|
lines.push(`This is a local code review for: ${name}`);
|
|
125
125
|
lines.push('');
|
|
126
126
|
lines.push('## Viewing Code Changes');
|
|
127
|
-
lines.push('The changes under review are **unstaged and untracked local changes**. Staged changes (`git diff --cached`) are treated as already reviewed.');
|
|
128
|
-
lines.push('To see the diff under review: `git diff`');
|
|
127
|
+
lines.push('The changes under review are **unstaged and untracked local changes**. Staged changes (`git diff --no-ext-diff --cached`) are treated as already reviewed.');
|
|
128
|
+
lines.push('To see the diff under review: `git diff --no-ext-diff`');
|
|
129
129
|
lines.push('Do NOT use `git diff HEAD~1` or `git log` — those show committed history, not the changes under review.');
|
|
130
130
|
} else {
|
|
131
131
|
const parts = [];
|
|
@@ -146,7 +146,7 @@ function buildReviewContext(review, prData) {
|
|
|
146
146
|
lines.push('');
|
|
147
147
|
lines.push('## Viewing Code Changes');
|
|
148
148
|
lines.push(`The changes under review are the diff between base commit \`${prData.base_sha.substring(0, 8)}\` and head commit \`${prData.head_sha.substring(0, 8)}\`.`);
|
|
149
|
-
lines.push(`To see the full diff: \`git diff ${prData.base_sha}...${prData.head_sha}\``);
|
|
149
|
+
lines.push(`To see the full diff: \`git diff --no-ext-diff ${prData.base_sha}...${prData.head_sha}\``);
|
|
150
150
|
lines.push('Do NOT use `git diff HEAD~1` or `git diff` without arguments — those do not show the PR changes.');
|
|
151
151
|
}
|
|
152
152
|
}
|
package/src/config.js
CHANGED
|
@@ -23,6 +23,7 @@ const DEFAULT_CONFIG = {
|
|
|
23
23
|
default_provider: "claude", // AI provider: 'claude', 'gemini', 'codex', 'copilot', 'opencode', 'cursor-agent', 'pi'
|
|
24
24
|
default_model: "opus", // Model within the provider (e.g., 'opus' for Claude, 'gemini-2.5-pro' for Gemini)
|
|
25
25
|
worktree_retention_days: 7,
|
|
26
|
+
review_retention_days: 21,
|
|
26
27
|
dev_mode: false, // When true, disables static file caching for development
|
|
27
28
|
debug_stream: false, // When true, logs AI provider streaming events (equivalent to --debug-stream CLI flag)
|
|
28
29
|
db_name: "", // Custom database filename (default: database.db). Useful for per-worktree isolation.
|
|
@@ -35,6 +36,7 @@ const DEFAULT_CONFIG = {
|
|
|
35
36
|
chat_providers: {}, // Custom chat provider configurations (overrides built-in defaults)
|
|
36
37
|
monorepos: {}, // Monorepo configurations: { "owner/repo": { path: "~/path/to/clone" } }
|
|
37
38
|
assisted_by_url: "https://github.com/in-the-loop-labs/pair-review", // URL for "Review assisted by" footer link
|
|
39
|
+
hooks: {}, // Hook commands per event: { "review.started": { "my_hook": { "command": "..." } } }
|
|
38
40
|
enable_graphite: false // When true, shows Graphite links alongside GitHub links
|
|
39
41
|
};
|
|
40
42
|
|