@in-the-loop-labs/pair-review 3.3.1 → 3.3.3

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.3.1",
3
+ "version": "3.3.3",
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.3.1",
3
+ "version": "3.3.3",
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.3.1",
3
+ "version": "3.3.3",
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/src/database.js CHANGED
@@ -2586,14 +2586,14 @@ class WorktreePoolRepository {
2586
2586
  }
2587
2587
 
2588
2588
  /**
2589
- * Find all pool worktrees for background fetch (excludes 'switching' status).
2589
+ * Find all pool worktrees for background fetch (excludes transient statuses).
2590
2590
  * Ordered by last_fetched_at ASC NULLS FIRST (coldest first).
2591
2591
  */
2592
2592
  async findAllForFetch(repository) {
2593
2593
  return await query(this.db, `
2594
2594
  SELECT id, path, last_fetched_at, status
2595
2595
  FROM worktree_pool
2596
- WHERE repository = ? COLLATE NOCASE AND status != 'switching'
2596
+ WHERE repository = ? COLLATE NOCASE AND status NOT IN ('switching', 'creating')
2597
2597
  ORDER BY last_fetched_at ASC NULLS FIRST
2598
2598
  `, [repository]);
2599
2599
  }
@@ -66,8 +66,9 @@ class GitWorktreeManager {
66
66
  /**
67
67
  * Resolve which git remote points to the given repository URLs.
68
68
  * Compares normalized URLs against all configured remotes. If no match is
69
- * found, adds (or updates) a managed `pair-review-base` remote so that
70
- * subsequent fetches target the correct repository (e.g. the base repo of a fork PR).
69
+ * found, falls back to an existing non-managed remote instead of mutating the
70
+ * repository's git config. This preserves proxy/mirror setups where the
71
+ * canonical fetch URL may differ from GitHub's clone URL.
71
72
  *
72
73
  * @param {Object} git - simple-git instance
73
74
  * @param {string} cloneUrl - HTTPS clone URL of the target repository
@@ -81,9 +82,7 @@ class GitWorktreeManager {
81
82
  const remoteOutput = await git.raw(['remote', '-v']);
82
83
 
83
84
  if (!remoteOutput || !remoteOutput.trim()) {
84
- console.log(`No remotes found, adding ${MANAGED_REMOTE} remote for ${cloneUrl}`);
85
- await git.addRemote(MANAGED_REMOTE, cloneUrl);
86
- return MANAGED_REMOTE;
85
+ throw new Error(`No remotes configured cannot resolve base repository for ${cloneUrl}`);
87
86
  }
88
87
 
89
88
  // Parse remote output into { name: url } map (fetch URLs only)
@@ -115,9 +114,16 @@ class GitWorktreeManager {
115
114
 
116
115
  const normalizedCloneUrl = normalizeUrl(cloneUrl);
117
116
  const normalizedSshUrl = sshUrl ? normalizeUrl(sshUrl) : '';
117
+ const remoteNames = Object.keys(remotes);
118
+ const fallbackRemote = remotes.origin
119
+ ? 'origin'
120
+ : remoteNames.find((name) => name !== MANAGED_REMOTE) || 'origin';
118
121
 
119
- // Check each remote for a match
122
+ // Check each non-managed remote for a direct URL match
120
123
  for (const [name, url] of Object.entries(remotes)) {
124
+ if (name === MANAGED_REMOTE) {
125
+ continue;
126
+ }
121
127
  const normalizedRemoteUrl = normalizeUrl(url);
122
128
  if (normalizedRemoteUrl === normalizedCloneUrl ||
123
129
  (normalizedSshUrl && normalizedRemoteUrl === normalizedSshUrl)) {
@@ -126,16 +132,13 @@ class GitWorktreeManager {
126
132
  }
127
133
  }
128
134
 
129
- // No match found — add or update the managed remote
130
- if (remotes[MANAGED_REMOTE]) {
131
- console.log(`Updating ${MANAGED_REMOTE} remote URL to ${cloneUrl}`);
132
- await git.raw(['remote', 'set-url', MANAGED_REMOTE, cloneUrl]);
133
- } else {
134
- console.log(`Adding ${MANAGED_REMOTE} remote for ${cloneUrl}`);
135
- await git.addRemote(MANAGED_REMOTE, cloneUrl);
136
- }
137
-
138
- return MANAGED_REMOTE;
135
+ console.warn(
136
+ `No configured remote matched ${cloneUrl}; using existing remote '${fallbackRemote}' without modifying git config`
137
+ );
138
+ // NOTE: For fork PRs this may return a remote that does not point to the
139
+ // base repository. Callers rely on fetchPRHead's SHA-fallback path and
140
+ // tolerant base-branch fetching to handle this without mutating git config.
141
+ return fallbackRemote;
139
142
  }
140
143
 
141
144
  /**
package/src/main.js CHANGED
@@ -1201,6 +1201,11 @@ function startPoolBackgroundFetches(db, config) {
1201
1201
  if (elapsed < intervalMs) continue;
1202
1202
  }
1203
1203
 
1204
+ if (!fs.existsSync(entry.path)) {
1205
+ logger.warn(`Background fetch skipped for ${entry.id}: directory no longer exists (${entry.path})`);
1206
+ continue;
1207
+ }
1208
+
1204
1209
  logger.info(`Background fetch starting for ${repoName} pool worktree ${entry.id}`);
1205
1210
  try {
1206
1211
  const git = simpleGit(entry.path, { timeout: { block: 300000 } });