fix: accept minimax apply-patch add delete quirks
This commit is contained in:
@@ -16,6 +16,7 @@ export interface UpdateChunk {
|
||||
export interface PatchParseResult {
|
||||
patch: string;
|
||||
hunks: PatchHunk[];
|
||||
hints: string[];
|
||||
}
|
||||
|
||||
export interface PatchUpdateResult {
|
||||
@@ -119,7 +120,8 @@ export function applyPatchV2HelpPayload() {
|
||||
"Add File has no @@ hunk marker: put content immediately after `*** Add File: <path>` and prefix every content line with +.",
|
||||
"A blank line in Add File is a line containing only +.",
|
||||
"Update File uses @@ or @@ context markers, followed by context lines starting with space and changed lines starting with - or +.",
|
||||
"Prefer `trans <route> apply-patch < /tmp/patch.diff` for long patches, Windows paths, or quoting-sensitive content."
|
||||
"Prefer `trans <route> apply-patch < /tmp/patch.diff` for long patches, Windows paths, or quoting-sensitive content.",
|
||||
"MiniMax compatibility: stray @@ or unprefixed content inside Add File, and extra hunk/body lines after Delete File, are accepted with stderr hints."
|
||||
],
|
||||
examples: {
|
||||
addFile: [
|
||||
@@ -159,6 +161,7 @@ export function parseApplyPatchV2(patchText: string): PatchParseResult {
|
||||
if (last !== endMarker) throw new ApplyPatchV2Error(`invalid patch: last line must be '${endMarker}'`);
|
||||
|
||||
const hunks: PatchHunk[] = [];
|
||||
const hints: string[] = [];
|
||||
let index = 1;
|
||||
const environmentLine = lines[index]?.trimStart() ?? "";
|
||||
if (environmentLine.startsWith(environmentIdMarker)) {
|
||||
@@ -178,10 +181,30 @@ export function parseApplyPatchV2(patchText: string): PatchParseResult {
|
||||
const added: string[] = [];
|
||||
while (index < lines.length - 1 && !isFileHeader(lines[index] ?? "")) {
|
||||
const addLine = lines[index] ?? "";
|
||||
if (!addLine.startsWith("+")) {
|
||||
throw invalidAddFileLineError(addLine, index + 1, filePath);
|
||||
if (addLine.startsWith("+")) {
|
||||
if (addLine.length > 1 && addLine.slice(1).trim().length === 0) {
|
||||
hints.push(`apply-patch hint: accepted MiniMax-style whitespace-only Add File line in ${filePath} on line ${index + 1}; prefer a line containing only + for blank lines.`);
|
||||
added.push("");
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
added.push(addLine.slice(1));
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
added.push(addLine.slice(1));
|
||||
if (addLine.trimStart().startsWith("@@")) {
|
||||
hints.push(`apply-patch hint: accepted MiniMax-style @@ inside Add File ${filePath} on line ${index + 1}; Add File does not need @@.`);
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
if (addLine.trim().length === 0) {
|
||||
hints.push(`apply-patch hint: accepted a bare blank line inside Add File ${filePath} on line ${index + 1}; prefer a line containing only +.`);
|
||||
added.push("");
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
hints.push(`apply-patch hint: accepted unprefixed Add File content in ${filePath} on line ${index + 1}; prefix new-file content lines with +.`);
|
||||
added.push(addLine);
|
||||
index += 1;
|
||||
}
|
||||
hunks.push({ kind: "add", path: filePath, content: joinLinesWithFinalNewline(added) });
|
||||
@@ -190,9 +213,13 @@ export function parseApplyPatchV2(patchText: string): PatchParseResult {
|
||||
if (line.startsWith(deleteFileMarker)) {
|
||||
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);
|
||||
const extraLines: number[] = [];
|
||||
while (index < lines.length - 1 && !isFileHeader(lines[index] ?? "")) {
|
||||
if ((lines[index] ?? "").trim().length > 0) extraLines.push(index + 1);
|
||||
index += 1;
|
||||
}
|
||||
if (extraLines.length > 0) {
|
||||
hints.push(`apply-patch hint: ignored extra MiniMax-style hunk/body lines after Delete File ${filePath} on line ${extraLines[0]}; Delete File only needs the header.`);
|
||||
}
|
||||
hunks.push({ kind: "delete", path: filePath });
|
||||
continue;
|
||||
@@ -222,47 +249,7 @@ export function parseApplyPatchV2(patchText: string): PatchParseResult {
|
||||
throw new ApplyPatchV2Error("invalid hunk header", { line: index + 1, text: line });
|
||||
}
|
||||
|
||||
return { patch, hunks };
|
||||
}
|
||||
|
||||
function invalidAddFileLineError(lineText: string, line: number, filePath: string): ApplyPatchV2Error {
|
||||
const details = { line, path: filePath, text: lineText };
|
||||
if (lineText.trimStart().startsWith("@@")) {
|
||||
return new ApplyPatchV2Error(
|
||||
"invalid add file line: remove @@ for Add File. Add File sections do not use hunk markers; put content directly after the header and prefix every content line with +.",
|
||||
details,
|
||||
);
|
||||
}
|
||||
if (lineText.trim().length === 0) {
|
||||
return new ApplyPatchV2Error(
|
||||
"invalid add file line: blank lines in Add File must be written as a line containing only +.",
|
||||
details,
|
||||
);
|
||||
}
|
||||
return new ApplyPatchV2Error(
|
||||
"invalid add file line: every Add File content line must start with +. Add File has no @@ marker; use @@ only under Update File.",
|
||||
details,
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
return { patch, hunks, hints };
|
||||
}
|
||||
|
||||
export function deriveUpdatedContent(filePath: string, originalContent: string, chunks: UpdateChunk[]): PatchUpdateResult {
|
||||
@@ -291,6 +278,7 @@ export async function runApplyPatchV2(options: ApplyPatchV2Options): Promise<num
|
||||
try {
|
||||
const parsed = parseApplyPatchV2(patchText);
|
||||
const plan = await applyPatchV2Hunks(options.executor, parsed.hunks);
|
||||
for (const hint of parsed.hints) stderr.write(`${hint}\n`);
|
||||
options.stdout.write("Success. Updated the following files:\n");
|
||||
for (const item of plan.changed) options.stdout.write(`${item}\n`);
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user