fix: clarify apply-patch delete-file misuse
This commit is contained in:
@@ -188,8 +188,13 @@ export function parseApplyPatchV2(patchText: string): PatchParseResult {
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith(deleteFileMarker)) {
|
||||
hunks.push({ kind: "delete", path: validatePatchPath(line.slice(deleteFileMarker.length), index + 1) });
|
||||
const filePath = validatePatchPath(line.slice(deleteFileMarker.length), index + 1);
|
||||
index += 1;
|
||||
const nextContentIndex = nextNonBlankLineIndex(lines, index, lines.length - 1);
|
||||
if (nextContentIndex < lines.length - 1 && !isFileHeader(lines[nextContentIndex] ?? "")) {
|
||||
throw invalidDeleteFileLineError(lines[nextContentIndex] ?? "", nextContentIndex + 1, filePath);
|
||||
}
|
||||
hunks.push({ kind: "delete", path: filePath });
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith(updateFileMarker)) {
|
||||
@@ -240,6 +245,26 @@ function invalidAddFileLineError(lineText: string, line: number, filePath: strin
|
||||
);
|
||||
}
|
||||
|
||||
function invalidDeleteFileLineError(lineText: string, line: number, filePath: string): ApplyPatchV2Error {
|
||||
const details = { line, path: filePath, text: lineText };
|
||||
if (lineText.trimStart().startsWith("@@")) {
|
||||
return new ApplyPatchV2Error(
|
||||
"invalid delete file line: remove @@ for Delete File. Delete File sections contain only the `*** Delete File: <path>` header; do not include hunk markers or file content.",
|
||||
details,
|
||||
);
|
||||
}
|
||||
return new ApplyPatchV2Error(
|
||||
"invalid delete file line: Delete File sections contain only the `*** Delete File: <path>` header. Remove old file content lines such as -old line.",
|
||||
details,
|
||||
);
|
||||
}
|
||||
|
||||
function nextNonBlankLineIndex(lines: string[], start: number, endExclusive: number): number {
|
||||
let index = start;
|
||||
while (index < endExclusive && (lines[index] ?? "").trim().length === 0) index += 1;
|
||||
return index;
|
||||
}
|
||||
|
||||
export function deriveUpdatedContent(filePath: string, originalContent: string, chunks: UpdateChunk[]): PatchUpdateResult {
|
||||
const originalLines = splitContentLines(originalContent);
|
||||
const replacements = computeReplacements(filePath, originalLines, chunks);
|
||||
|
||||
@@ -923,6 +923,25 @@ export async function runSshArgvGuidanceContract(): Promise<JsonRecord> {
|
||||
);
|
||||
assertCondition(!addFileWithHunkMarkerV2.commands.some((command) => command.startsWith("write-b64") || command.startsWith("delete")), "v2 Add File parse failures must not touch remote files", addFileWithHunkMarkerV2.commands);
|
||||
|
||||
const deleteFileWithHunkMarkerV2 = await applyPatchV2FixtureAttempt([
|
||||
"*** Begin Patch",
|
||||
"*** Delete File: bad-delete.txt",
|
||||
"@@",
|
||||
"-content",
|
||||
"*** End Patch",
|
||||
"",
|
||||
].join("\n"), { "bad-delete.txt": "content\n" }, { stderrOutput: true });
|
||||
assertCondition(deleteFileWithHunkMarkerV2.exitCode === 1 && deleteFileWithHunkMarkerV2.error === null, "v2 CLI path should return a visible parse error for Delete File @@ misuse", deleteFileWithHunkMarkerV2);
|
||||
assertCondition(deleteFileWithHunkMarkerV2.stdout === "", "v2 Delete File parse failures should keep Codex-style empty stdout", deleteFileWithHunkMarkerV2);
|
||||
assertCondition(
|
||||
deleteFileWithHunkMarkerV2.stderr.includes("remove @@ for Delete File")
|
||||
&& deleteFileWithHunkMarkerV2.stderr.includes("do not include hunk markers or file content"),
|
||||
"v2 Delete File @@ misuse should tell agents exactly how to repair the patch",
|
||||
deleteFileWithHunkMarkerV2.stderr,
|
||||
);
|
||||
assertCondition(deleteFileWithHunkMarkerV2.files["bad-delete.txt"] === "content\n", "v2 Delete File parse failures must not delete remote files", deleteFileWithHunkMarkerV2);
|
||||
assertCondition(!deleteFileWithHunkMarkerV2.commands.some((command) => command.startsWith("delete")), "v2 Delete File parse failures must not issue remote delete operations", deleteFileWithHunkMarkerV2.commands);
|
||||
|
||||
const sequentialCompoundV2 = await applyPatchV2Fixture([
|
||||
"*** Begin Patch",
|
||||
"*** Update File: sequence.txt",
|
||||
|
||||
Reference in New Issue
Block a user