From c82340821931c83d6a9ef6fdbc42367b89c25f13 Mon Sep 17 00:00:00 2001 From: Dean Stratakos <29683763+dastratakos@users.noreply.github.com> Date: Wed, 13 May 2026 18:38:25 -0700 Subject: [PATCH 1/2] fix: include untracked files in diff patch for working-tree runs --- packages/cli/src/git.ts | 2 +- packages/cli/src/routes/diff.ts | 44 ++++++++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/git.ts b/packages/cli/src/git.ts index f93242a..8e7ddf3 100644 --- a/packages/cli/src/git.ts +++ b/packages/cli/src/git.ts @@ -146,7 +146,7 @@ export function getUntrackedFiles(): string[] { return out ? out.split("\n") : []; } -function hasStringStdout(err: unknown): err is { stdout: string } { +export function hasStringStdout(err: unknown): err is { stdout: string } { return ( typeof err === "object" && err !== null && "stdout" in err && typeof err.stdout === "string" ); diff --git a/packages/cli/src/routes/diff.ts b/packages/cli/src/routes/diff.ts index a5bb607..a53744d 100644 --- a/packages/cli/src/routes/diff.ts +++ b/packages/cli/src/routes/diff.ts @@ -7,7 +7,7 @@ import { eq } from "drizzle-orm"; import type { StageDb } from "../db/client.js"; import type { ChapterRunRow } from "../db/schema/chapter-run.js"; import { chapterRun } from "../db/schema/index.js"; -import { buildDiffArgs } from "../git.js"; +import { buildDiffArgs, hasStringStdout } from "../git.js"; import { SCOPE_KIND, WORKING_TREE_REF } from "../schema.js"; import type { Route } from "../server.js"; import { writeJson } from "./json.js"; @@ -15,6 +15,32 @@ import { writeJson } from "./json.js"; const execFileAsync = promisify(execFile); const MAX_FILE_BYTES = 5 * 1024 * 1024; +const MAX_DIFF_BYTES = 50 * 1024 * 1024; + +async function buildUntrackedPatch(cwd: string): Promise { + const { stdout } = await execFileAsync("git", ["ls-files", "--others", "--exclude-standard"], { + cwd, + encoding: "utf8", + }); + const files = stdout.trim() ? stdout.trim().split("\n") : []; + if (files.length === 0) return ""; + + const patches: string[] = []; + for (const file of files) { + try { + await execFileAsync("git", ["diff", "--no-index", "--no-color", "--", "/dev/null", file], { + cwd, + encoding: "utf8", + maxBuffer: MAX_DIFF_BYTES, + }); + } catch (err: unknown) { + if (hasStringStdout(err)) { + patches.push(err.stdout); + } + } + } + return patches.join("\n"); +} export function diffRoutes(db: StageDb): Route[] { return [ @@ -47,11 +73,23 @@ export function diffRoutes(db: StageDb): Route[] { run.scopeKind === SCOPE_KIND.COMMITTED ? "private, max-age=300" : "no-store"; try { - const { stdout: patch } = await execFileAsync("git", args, { + const { stdout: trackedPatch } = await execFileAsync("git", args, { cwd: repoRoot, encoding: "utf8", - maxBuffer: 50 * 1024 * 1024, + maxBuffer: MAX_DIFF_BYTES, }); + + let patch = trackedPatch; + if ( + run.scopeKind === SCOPE_KIND.WORKING_TREE && + run.workingTreeRef === WORKING_TREE_REF.WORK + ) { + const untrackedPatch = await buildUntrackedPatch(repoRoot); + if (untrackedPatch) { + patch = patch ? `${patch}\n${untrackedPatch}` : untrackedPatch; + } + } + const fileContents = await buildFileContents(run, repoRoot, patch); const body: DiffResponse = { patch, fileContents }; res.writeHead(200, { From 179a4ef759084bed34d9a6217c046cb9654210d7 Mon Sep 17 00:00:00 2001 From: Dean Stratakos <29683763+dastratakos@users.noreply.github.com> Date: Wed, 13 May 2026 18:42:52 -0700 Subject: [PATCH 2/2] perf: parallelize untracked file diff generation --- packages/cli/src/routes/diff.ts | 37 ++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/packages/cli/src/routes/diff.ts b/packages/cli/src/routes/diff.ts index a53744d..5a5e053 100644 --- a/packages/cli/src/routes/diff.ts +++ b/packages/cli/src/routes/diff.ts @@ -25,21 +25,30 @@ async function buildUntrackedPatch(cwd: string): Promise { const files = stdout.trim() ? stdout.trim().split("\n") : []; if (files.length === 0) return ""; - const patches: string[] = []; - for (const file of files) { - try { - await execFileAsync("git", ["diff", "--no-index", "--no-color", "--", "/dev/null", file], { - cwd, - encoding: "utf8", - maxBuffer: MAX_DIFF_BYTES, - }); - } catch (err: unknown) { - if (hasStringStdout(err)) { - patches.push(err.stdout); + const patches = await Promise.all( + files.map(async (file) => { + try { + await execFileAsync( + "git", + [ + "diff", + "--no-index", + "--no-color", + "--src-prefix=a/", + "--dst-prefix=b/", + "--", + "/dev/null", + file, + ], + { cwd, encoding: "utf8", maxBuffer: MAX_DIFF_BYTES }, + ); + return ""; + } catch (err: unknown) { + return hasStringStdout(err) ? err.stdout : ""; } - } - } - return patches.join("\n"); + }), + ); + return patches.filter(Boolean).join("\n"); } export function diffRoutes(db: StageDb): Route[] {