src/agents/codeAgentRepoResolver.ts

import { existsSync, readdirSync, realpathSync, statSync, type Dirent } from "node:fs"; import { spawnSync } from "node:child_process"; import path from "node:path"; import { resolveAllowedCodeWorkspaceRoots } from "./codeAgentSettings.ts";

type GitHubRepoRef = { owner: string; repo: string; canonical: string; };

export type CodeAgentRepoResolution = { cwd: string; githubRepo: string; };

const MAX_REPO_SEARCH_DEPTH = 6; const MAX_REPO_SEARCH_DIRS = 4000; const SKIP_DIR_NAMES = new Set([ ".git", ".hg", ".svn", ".cache", ".next", ".turbo", "build", "coverage", "dist", "node_modules", "target" ]);

function repoRef(owner: string, repo: string): GitHubRepoRef | null { const normalizedOwner = String(owner || "").trim().toLowerCase(); const normalizedRepo = String(repo || "") .trim() .replace(/.git$/i, "") .toLowerCase(); if (!normalizedOwner || !normalizedRepo) return null; return { owner: normalizedOwner, repo: normalizedRepo, canonical: ${normalizedOwner}/${normalizedRepo} }; }

export function parseGitHubRepoRef(value: string): GitHubRepoRef | null { const text = String(value || ""); const patterns = [ /git@github.com:([A-Za-z0-9_.-]+)/([A-Za-z0-9_.-]+)(?:.git)?/i, /ssh://git@github.com/([A-Za-z0-9_.-]+)/([A-Za-z0-9_.-]+)(?:.git)?/i, /(?:https?://)?(?:www.)?github.com/([A-Za-z0-9_.-]+)/([A-Za-z0-9_.-]+)(?:.git)?(?:[/?#\s]|$)/i ]; for (const pattern of patterns) { const match = pattern.exec(text); const ref = match ? repoRef(match[1], match[2]) : null; if (ref) return ref; } return null; }

function uniqueRealDirs(values: string[]): string[] { const seen = new Set(); const dirs: string[] = []; for (const value of values) { if (!existsSync(value)) continue; let stats: ReturnType; try { stats = statSync(value); } catch { continue; } if (!stats.isDirectory()) continue; const real = realpathSync(value); const key = real.toLowerCase(); if (seen.has(key)) continue; seen.add(key); dirs.push(real); } return dirs; }

function relativeInside(parent: string, child: string): boolean { const rel = path.relative(parent, child); return rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel)); }

export function assertCodeAgentCwdAllowed(settings: Record<string, unknown>, cwd: string): string { const allowedRoots = uniqueRealDirs(resolveAllowedCodeWorkspaceRoots(settings)); if (allowedRoots.length === 0) { throw new Error("Code workers require at least one allowed coding workspace root in settings."); } const realCwd = realpathSync(cwd); if (!allowedRoots.some((root) => relativeInside(root, realCwd))) { throw new Error( Code worker directory is outside allowed coding workspace roots: ${realCwd} ); } return realCwd; }

function hasGitMetadata(dir: string): boolean { return existsSync(path.join(dir, ".git")); }

function gitRemoteOutput(dir: string): string { const result = spawnSync("git", ["remote", "-v"], { cwd: dir, encoding: "utf8", timeout: 2500 }); if (result.error || result.status !== 0) return ""; return String(result.stdout || ""); }

function gitHubRemotesForDir(dir: string): Set { const remotes = new Set(); for (const line of gitRemoteOutput(dir).split(" ")) { const ref = parseGitHubRepoRef(line); if (ref) remotes.add(ref.canonical); } return remotes; }

function findGitRepoDirs(root: string): string[] { const repos: string[] = []; const stack: Array<{ dir: string; depth: number }> = [{ dir: root, depth: 0 }]; const visited = new Set(); let inspected = 0;

while (stack.length > 0) { const current = stack.pop(); if (!current) continue; let realDir: string; try { realDir = realpathSync(current.dir); } catch { continue; } const key = realDir.toLowerCase(); if (visited.has(key)) continue; visited.add(key); inspected += 1; if (inspected > MAX_REPO_SEARCH_DIRS) { throw new Error(Coding workspace search exceeded ${MAX_REPO_SEARCH_DIRS} directories under ${root}.); }

if (hasGitMetadata(realDir)) {
  repos.push(realDir);
}
if (current.depth >= MAX_REPO_SEARCH_DEPTH) continue;

let entries: Dirent[];
try {
  entries = readdirSync(realDir, { withFileTypes: true });
} catch {
  continue;
}
for (const entry of entries) {
  if (!entry.isDirectory()) continue;
  if (SKIP_DIR_NAMES.has(entry.name)) continue;
  stack.push({ dir: path.join(realDir, entry.name), depth: current.depth + 1 });
}

}

return repos; }

export function resolveGitHubRepoCwdForCodeTask(args: { settings: Record<string, unknown>; task: string; githubUrl?: string | null; }): CodeAgentRepoResolution | null { const ref = parseGitHubRepoRef(${args.githubUrl || ""} ${args.task || ""}); if (!ref) return null;

const allowedRoots = uniqueRealDirs(resolveAllowedCodeWorkspaceRoots(args.settings)); if (allowedRoots.length === 0) { throw new Error(No allowed coding workspace roots configured for GitHub repo ${ref.canonical}.); }

const matches: string[] = []; for (const root of allowedRoots) { for (const repoDir of findGitRepoDirs(root)) { if (gitHubRemotesForDir(repoDir).has(ref.canonical)) { matches.push(repoDir); } } }

const uniqueMatches = uniqueRealDirs(matches); if (uniqueMatches.length === 0) { throw new Error( No approved local clone found for GitHub repo ${ref.canonical} under allowed coding workspace roots. ); } if (uniqueMatches.length > 1) { throw new Error( Multiple approved local clones found for GitHub repo ${ref.canonical}; pass cwd explicitly. ); }

return { cwd: uniqueMatches[0], githubRepo: ref.canonical }; }