fix: optimize Windows apply-patch fs path

This commit is contained in:
Codex
2026-06-26 17:05:09 +00:00
parent 9bce21b9ef
commit 624904c383
5 changed files with 404 additions and 22 deletions
+78 -6
View File
@@ -632,6 +632,7 @@ function isBulkReadFailure(error: unknown): boolean {
}
function shouldUseBulkUpdatePath(executor: ApplyPatchV2Executor, hunks: PatchHunk[]): boolean {
const isFsBulkPath = executor.fs !== undefined;
if (executor.fs !== undefined) {
if (executor.fs.readFiles === undefined || executor.fs.applyReplacementsBulk === undefined) return false;
} else if (!executor.run) {
@@ -643,7 +644,7 @@ function shouldUseBulkUpdatePath(executor: ApplyPatchV2Executor, hunks: PatchHun
if (paths.has(hunk.path)) return false;
paths.add(hunk.path);
}
return paths.size >= 2;
return isFsBulkPath ? paths.size >= 1 : paths.size >= 2;
}
async function applyPatchV2UpdateHunksBulk(executor: ApplyPatchV2Executor, hunks: Array<Extract<PatchHunk, { kind: "update" }>>): Promise<ApplyPatchV2Plan> {
@@ -733,6 +734,7 @@ function formatApplyPatchFailure(error: unknown): string {
const outcomes = Array.isArray(details.outcomes) ? details.outcomes as ApplyPatchV2Outcome[] : [];
const lines = [`${message.trimEnd()}`];
appendParserFailureHint(lines, message, details);
appendRemoteOperationFailureDetails(lines, details);
appendExpectedLinesFailureHint(lines, details);
if (outcomes.length > 1 || outcomes.some((item) => item.status === "applied")) {
lines.push("Patch status:");
@@ -757,6 +759,72 @@ function appendParserFailureHint(lines: string[], message: string, details: Reco
}
}
function appendRemoteOperationFailureDetails(lines: string[], details: Record<string, unknown>): void {
const remote = remoteOperationFailureRecord(details);
if (remote === null) return;
const summaryFields = [
["operation", stringField(remote, "operation")],
["route", stringField(remote, "route")],
["file", stringField(remote, "filePath") ?? stringField(remote, "path")],
["targetCount", numberOrStringField(remote, "targetCount")],
["inputBytes", numberOrStringField(remote, "inputBytes")],
["expectedBytes", numberOrStringField(remote, "expectedBytes")],
["sha256", stringField(remote, "expectedSha256") ?? stringField(remote, "sha256")],
["elapsedMs", numberOrStringField(remote, "remoteElapsedMs")],
["landed", booleanOrStringField(remote, "landed")],
["exitCode", numberOrStringField(remote, "exitCode")],
].filter(([, value]) => value !== undefined && value !== null && value !== "");
if (summaryFields.length > 0) {
lines.push(`Remote operation: ${summaryFields.map(([key, value]) => `${key}=${value}`).join(" ")}`);
}
const stderrTail = stringField(remote, "stderrTail") ?? stringField(remote, "stderr");
if (stderrTail !== undefined && stderrTail.trim().length > 0) {
lines.push("Remote stderr tail:");
appendQuotedBlock(lines, stderrTail.trim(), 8, 1200);
}
const stdoutTail = stringField(remote, "stdoutTail") ?? stringField(remote, "stdout");
if (stdoutTail !== undefined && stdoutTail.trim().length > 0) {
lines.push("Remote stdout tail:");
appendQuotedBlock(lines, stdoutTail.trim(), 6, 900);
}
}
function remoteOperationFailureRecord(details: Record<string, unknown>): Record<string, unknown> | null {
if (typeof details.operation === "string") return details;
const cause = recordValue(details.cause);
if (cause !== null) {
const nested = remoteOperationFailureRecord(cause);
if (nested !== null) return nested;
}
const failed = recordValue(details.failed);
const failedError = recordValue(failed?.error);
const failedDetails = recordValue(failedError?.details);
if (failedDetails !== null) {
const nested = remoteOperationFailureRecord(failedDetails);
if (nested !== null) return nested;
}
return null;
}
function stringField(record: Record<string, unknown>, key: string): string | undefined {
const value = record[key];
return typeof value === "string" ? value : undefined;
}
function numberOrStringField(record: Record<string, unknown>, key: string): string | undefined {
const value = record[key];
if (typeof value === "number" && Number.isFinite(value)) return String(value);
if (typeof value === "string" && value.length > 0) return value;
return undefined;
}
function booleanOrStringField(record: Record<string, unknown>, key: string): string | undefined {
const value = record[key];
if (typeof value === "boolean") return String(value);
if (typeof value === "string" && value.length > 0) return value;
return undefined;
}
function appendExpectedLinesFailureHint(lines: string[], details: Record<string, unknown>): void {
const cause = recordValue(details.cause) ?? details;
const expected = typeof cause.expected === "string" ? cause.expected : "";
@@ -941,12 +1009,16 @@ async function readRemoteText(executor: ApplyPatchV2Executor, target: string): P
async function readRemoteTextsBulk(executor: ApplyPatchV2Executor, targets: string[]): Promise<Map<string, string>> {
if (targets.length === 0) return new Map();
if (executor.fs?.readFiles !== undefined && targets.length > 1) {
const files = await executor.fs.readFiles(targets);
for (const target of targets) {
if (!files.has(target)) throw new ApplyPatchV2Error("remote apply-patch v2 fs bulk read omitted target", { target });
if (executor.fs?.readFiles !== undefined) {
try {
const files = await executor.fs.readFiles(targets);
for (const target of targets) {
if (!files.has(target)) throw new ApplyPatchV2Error("remote apply-patch v2 fs bulk read omitted target", { target });
}
return files;
} catch (error) {
if (!isBulkReadFailure(error)) throw error;
}
return files;
}
if (executor.fs || targets.length === 1) {
const files = new Map<string, string>();