@in-the-loop-labs/pair-review 3.0.0 → 3.0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@in-the-loop-labs/pair-review",
3
- "version": "3.0.0",
3
+ "version": "3.0.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": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pair-review",
3
- "version": "3.0.0",
3
+ "version": "3.0.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": "3.0.0",
3
+ "version": "3.0.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",
@@ -27,6 +27,14 @@ const { buildSparseCheckoutGuidance } = require('./prompts/sparse-checkout-guida
27
27
  /** Minimum total suggestion count across all voices before consolidation is applied */
28
28
  const COUNCIL_CONSOLIDATION_THRESHOLD = 8;
29
29
 
30
+ /**
31
+ * Common git diff flags used across all diff operations.
32
+ * - --no-color: Disable color output (guards against color.diff=always in user config)
33
+ * - --no-ext-diff: Disable external diff drivers
34
+ * - --src-prefix/--dst-prefix: Ensure consistent a/ b/ prefixes (overrides user's diff.noprefix)
35
+ */
36
+ const GIT_DIFF_COMMON_FLAGS = '--no-color --no-ext-diff --src-prefix=a/ --dst-prefix=b/';
37
+
30
38
  /**
31
39
  * Build a human-readable display label for a council voice/reviewer.
32
40
  * Uses 1-based index so logs read "Reviewer 1", "Reviewer 2", etc.
@@ -989,10 +997,10 @@ ${prMetadata.description || '(No description provided)'}
989
997
  const isLocal = prMetadata.reviewType === 'local';
990
998
  if (isLocal) {
991
999
  // For local mode, diff against HEAD to see working directory changes
992
- return suffix ? `git diff --no-ext-diff HEAD ${suffix}` : 'git diff --no-ext-diff HEAD';
1000
+ return suffix ? `git diff ${GIT_DIFF_COMMON_FLAGS} HEAD ${suffix}` : `git diff ${GIT_DIFF_COMMON_FLAGS} HEAD`;
993
1001
  }
994
1002
  // For PR mode, diff between base and head commits
995
- const baseCmd = `git diff --no-ext-diff ${prMetadata.base_sha}...${prMetadata.head_sha}`;
1003
+ const baseCmd = `git diff ${GIT_DIFF_COMMON_FLAGS} ${prMetadata.base_sha}...${prMetadata.head_sha}`;
996
1004
  return suffix ? `${baseCmd} ${suffix}` : baseCmd;
997
1005
  }
998
1006
 
@@ -33,6 +33,14 @@ const MAX_FILE_SIZE = 1024 * 1024;
33
33
  */
34
34
  const GIT_DIFF_HAS_DIFFERENCES = 1;
35
35
 
36
+ /**
37
+ * Common git diff flags used across all diff operations.
38
+ * - --no-color: Disable color output for consistent parsing
39
+ * - --no-ext-diff: Disable external diff drivers
40
+ * - --src-prefix/--dst-prefix: Ensure consistent a/ b/ prefixes (overrides user's diff.noprefix)
41
+ */
42
+ const GIT_DIFF_COMMON_FLAGS = '--no-color --no-ext-diff --src-prefix=a/ --dst-prefix=b/';
43
+
36
44
  /**
37
45
  * Find the main git repository root, resolving through worktrees.
38
46
  * For regular repos, returns the repo root.
@@ -401,7 +409,7 @@ function generateUntrackedDiffs(repoPath, untrackedFiles, wFlag) {
401
409
  const filePath = path.join(repoPath, untracked.file);
402
410
  let fileDiff;
403
411
  try {
404
- fileDiff = execSync(`git diff --no-index --no-color --no-ext-diff${wFlag} -- /dev/null "${filePath}"`, {
412
+ fileDiff = execSync(`git diff --no-index ${GIT_DIFF_COMMON_FLAGS}${wFlag} -- /dev/null "${filePath}"`, {
405
413
  cwd: repoPath,
406
414
  encoding: 'utf8',
407
415
  stdio: ['pipe', 'pipe', 'pipe'],
@@ -478,37 +486,37 @@ async function generateScopedDiff(repoPath, scopeStart, scopeEnd, baseBranch, op
478
486
  try {
479
487
  if (hasBranch && !hasStaged && !hasUnstaged) {
480
488
  // Branch only → committed changes since merge-base
481
- diff = execSync(`git diff ${mergeBaseSha}..HEAD --no-color --no-ext-diff --unified=25${wFlag}`, {
489
+ diff = execSync(`git diff ${mergeBaseSha}..HEAD ${GIT_DIFF_COMMON_FLAGS} --unified=25${wFlag}`, {
482
490
  cwd: repoPath, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'],
483
491
  maxBuffer: 50 * 1024 * 1024
484
492
  });
485
493
  } else if (hasBranch && hasStaged && !hasUnstaged) {
486
494
  // Branch–Staged → staged changes relative to merge-base
487
- diff = execSync(`git diff --cached ${mergeBaseSha} --no-color --no-ext-diff --unified=25${wFlag}`, {
495
+ diff = execSync(`git diff --cached ${mergeBaseSha} ${GIT_DIFF_COMMON_FLAGS} --unified=25${wFlag}`, {
488
496
  cwd: repoPath, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'],
489
497
  maxBuffer: 50 * 1024 * 1024
490
498
  });
491
499
  } else if (hasBranch && hasUnstaged) {
492
500
  // Branch–Unstaged (or Branch–Untracked) → working tree vs merge-base
493
- diff = execSync(`git diff ${mergeBaseSha} --no-color --no-ext-diff --unified=25${wFlag}`, {
501
+ diff = execSync(`git diff ${mergeBaseSha} ${GIT_DIFF_COMMON_FLAGS} --unified=25${wFlag}`, {
494
502
  cwd: repoPath, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'],
495
503
  maxBuffer: 50 * 1024 * 1024
496
504
  });
497
505
  } else if (hasStaged && !hasUnstaged) {
498
506
  // Staged only → cached changes
499
- diff = execSync(`git diff --cached --no-color --no-ext-diff --unified=25${wFlag}`, {
507
+ diff = execSync(`git diff --cached ${GIT_DIFF_COMMON_FLAGS} --unified=25${wFlag}`, {
500
508
  cwd: repoPath, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'],
501
509
  maxBuffer: 50 * 1024 * 1024
502
510
  });
503
511
  } else if (hasStaged && hasUnstaged) {
504
512
  // Staged–Unstaged (or Staged–Untracked) → all changes vs HEAD
505
- diff = execSync(`git diff HEAD --no-color --no-ext-diff --unified=25${wFlag}`, {
513
+ diff = execSync(`git diff HEAD ${GIT_DIFF_COMMON_FLAGS} --unified=25${wFlag}`, {
506
514
  cwd: repoPath, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'],
507
515
  maxBuffer: 50 * 1024 * 1024
508
516
  });
509
517
  } else if (hasUnstaged) {
510
518
  // Unstaged only or Unstaged–Untracked → working tree changes
511
- diff = execSync(`git diff --no-color --no-ext-diff --unified=25${wFlag}`, {
519
+ diff = execSync(`git diff ${GIT_DIFF_COMMON_FLAGS} --unified=25${wFlag}`, {
512
520
  cwd: repoPath, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'],
513
521
  maxBuffer: 50 * 1024 * 1024
514
522
  });
@@ -590,7 +598,7 @@ async function computeScopedDigest(repoPath, scopeStart, scopeEnd) {
590
598
  // Staged in scope → cached diff content
591
599
  if (scopeIncludes(scopeStart, scopeEnd, 'staged')) {
592
600
  try {
593
- const result = await execAsync('git diff --cached --no-ext-diff', {
601
+ const result = await execAsync(`git diff --cached ${GIT_DIFF_COMMON_FLAGS}`, {
594
602
  cwd: repoPath, encoding: 'utf8', maxBuffer: 50 * 1024 * 1024
595
603
  });
596
604
  parts.push('STAGED:' + result.stdout);
@@ -602,7 +610,7 @@ async function computeScopedDigest(repoPath, scopeStart, scopeEnd) {
602
610
  // Unstaged in scope → working tree diff
603
611
  if (scopeIncludes(scopeStart, scopeEnd, 'unstaged')) {
604
612
  try {
605
- const result = await execAsync('git diff --no-ext-diff', {
613
+ const result = await execAsync(`git diff ${GIT_DIFF_COMMON_FLAGS}`, {
606
614
  cwd: repoPath, encoding: 'utf8', maxBuffer: 50 * 1024 * 1024
607
615
  });
608
616
  parts.push('UNSTAGED:' + result.stdout);