MCPcopy
hub / github.com/openclaw/clawsweeper / localReviewCommand

Function localReviewCommand

src/commit-sweeper.ts:422–509  ·  view source on GitHub ↗
(args: Args)

Source from the content-addressed store, hash-verified

420// Conforms to the #253 replacement spec: clean checkout, unique run dir, no GitHub
421// token, and reject unsupported repos (never fall back to a foreign profile).
422function localReviewCommand(args: Args): void {
423 const targetDir = resolve(argString(args, "target_dir", "."));
424 const baseBranch = argString(args, "base", "main");
425 const reportDir = resolve(
426 argString(args, "report_dir", join(homedir(), ".clawsweeper-local-reviews")),
427 );
428
429 // Spec: genuinely offline — withhold every GitHub credential from the review engine.
430 for (const tokenVar of LOCAL_REVIEW_SCRUBBED_TOKEN_ENV) {
431 delete process.env[tokenVar];
432 }
433
434 // Spec: committed-range review requires a clean checkout (no hidden staged/untracked work).
435 const dirtyTree = run("git", ["status", "--porcelain"], { cwd: targetDir }).trim();
436 if (dirtyTree) {
437 console.error(`[local-review] working tree not clean — commit or stash first:\n${dirtyTree}`);
438 process.exit(1);
439 }
440
441 const targetRepo =
442 argString(args, "target_repo", "") ||
443 run("git", ["remote", "get-url", "origin"], { cwd: targetDir })
444 .replace(/.*github\.com[:/]/, "")
445 .replace(/\.git\s*$/, "")
446 .trim();
447
448 // Spec: reject unsupported repos — never silently fall back to a foreign profile.
449 const profile = configuredRepositoryProfileFor(targetRepo);
450 if (!profile) {
451 console.error(
452 `[local-review] no review profile for '${targetRepo}'. Add a repository profile, or pass --target-repo <known-repo>.`,
453 );
454 process.exit(1);
455 }
456 const profileSlug = profile.slug;
457
458 // Range = merge-base(base, HEAD)..HEAD — the whole branch, reviewed as one unit.
459 const headSha = run("git", ["rev-parse", "HEAD"], { cwd: targetDir }).trim();
460 const baseSha = run("git", ["merge-base", baseBranch, "HEAD"], { cwd: targetDir }).trim();
461 if (!baseSha || baseSha === headSha) {
462 console.error(`[local-review] no commits on HEAD beyond ${baseBranch} — nothing to review.`);
463 process.exit(1);
464 }
465
466 const metadata = commitMetadata(targetDir, targetRepo, headSha, true);
467
468 // Spec: unique per-run dir so concurrent runs never collide on result paths.
469 const runDir = join(reportDir, `run-${headSha.slice(0, 8)}-${Date.now()}-${process.pid}`);
470 ensureDir(runDir);
471
472 // Spec: hard-enforce no GitHub access. The review prompt suggests `gh` for issue
473 // refs, and `gh` uses its own configured auth (token-env deletion can't stop it),
474 // so point it at an empty config dir — any `gh` the spawned reviewer runs finds
475 // no cached credentials. Belt-and-suspenders with Codex's read-only sandbox.
476 const ghEmptyConfig = join(runDir, ".gh-empty");
477 ensureDir(ghEmptyConfig);
478 process.env.GH_CONFIG_DIR = ghEmptyConfig;
479

Callers 1

mainFunction · 0.85

Calls 9

argStringFunction · 0.85
commitMetadataFunction · 0.85
argNumberFunction · 0.85
runFunction · 0.70
ensureDirFunction · 0.70
runCodexFunction · 0.70

Tested by

no test coverage detected