fix(chunk-tree): corrected zero-width insert indent detection logic
- Fixed zero-width insert detection to derive target indent from neighboring lines instead of replaced range. - Improved indent selection for body-level insertions by picking deeper indent between two neighbors. - Updated error messages to clarify insert vs splice operations and line range validation. - Modified assertChecksum() return type to handle cases with default CRC and no explicit selector.
This commit is contained in:
@@ -535,8 +535,11 @@ export class EditTool implements AgentTool<TInput> {
|
||||
|
||||
const normalizedOperations: ChunkEditOperation[] = [];
|
||||
|
||||
const assertChecksum = (op: string, crc: string | undefined, sel: string | undefined): string => {
|
||||
const assertChecksum = (op: string, crc: string | undefined, sel: string | undefined): string | undefined => {
|
||||
if (crc) return crc.toUpperCase();
|
||||
// When no explicit sel is given, the default selector/crc from
|
||||
// the path will be applied downstream by applyChunkEdits.
|
||||
if (!sel && defaultCrc) return undefined;
|
||||
if (sel && chunkTree) {
|
||||
const resolved = resolveChunkPath(chunkTree, sel);
|
||||
if (resolved) {
|
||||
|
||||
@@ -1361,7 +1361,29 @@ export function applyChunkEdits(params: {
|
||||
const rangeStart = lineStartOffset(offsets, absBeg, state.source);
|
||||
const rangeEnd = lineEndOffset(offsets, absEnd, state.source);
|
||||
const replacedRange = state.source.slice(rangeStart, rangeEnd);
|
||||
const targetIndent = detectCommonIndent(replacedRange).prefix;
|
||||
// For zero-width inserts the replaced range is empty; derive
|
||||
// indent from the two neighboring lines, picking the deeper
|
||||
// indent so body-level insertions stay at body depth even when
|
||||
// one neighbor is a boundary line (opening/closing brace).
|
||||
let targetIndent: string;
|
||||
if (isZeroWidthInsert(absBeg, absEnd)) {
|
||||
const indA = detectCommonIndent(
|
||||
state.source.slice(
|
||||
lineStartOffset(offsets, absEnd, state.source),
|
||||
lineEndOffset(offsets, absEnd, state.source),
|
||||
),
|
||||
).prefix;
|
||||
const bLine = Math.min(absBeg, state.tree.lineCount);
|
||||
const indB = detectCommonIndent(
|
||||
state.source.slice(
|
||||
lineStartOffset(offsets, bLine, state.source),
|
||||
lineEndOffset(offsets, bLine, state.source),
|
||||
),
|
||||
).prefix;
|
||||
targetIndent = indA.length >= indB.length ? indA : indB;
|
||||
} else {
|
||||
targetIndent = detectCommonIndent(replacedRange).prefix;
|
||||
}
|
||||
let replacement = normalizeInsertedContent(operation.content, targetIndent);
|
||||
if (replacement.length > 0 && !replacement.endsWith("\n") && absEnd < state.tree.lineCount) {
|
||||
replacement += "\n";
|
||||
|
||||
@@ -1048,7 +1048,7 @@ describe("zero-width splice (line insertion)", () => {
|
||||
content: "noop();",
|
||||
},
|
||||
]),
|
||||
).toThrow(/Invalid zero-width splice L20-L19/);
|
||||
).toThrow(/Invalid zero-width insert L20-L19/);
|
||||
});
|
||||
test("zero-width splice after the chunk preserves the separator gap", () => {
|
||||
const source = `class Worker {\n\trun(): void {\n\t\twork();\n\t}\n\n\tstop(): void {\n\t\tcleanup();\n\t}\n}\n`;
|
||||
@@ -1250,7 +1250,7 @@ describe("splice", () => {
|
||||
content: "replacement",
|
||||
},
|
||||
]),
|
||||
).toThrow(/Invalid splice range L4-L2/);
|
||||
).toThrow(/Invalid line range L4-L2/);
|
||||
});
|
||||
|
||||
test("splice rejects line 0 before edit application", () => {
|
||||
@@ -1265,7 +1265,7 @@ describe("splice", () => {
|
||||
content: "replacement",
|
||||
},
|
||||
]),
|
||||
).toThrow(/Splice beg 0 is invalid/);
|
||||
).toThrow(/Line 0 is invalid/);
|
||||
});
|
||||
|
||||
test("splice with out-of-range lines throws", () => {
|
||||
|
||||
@@ -444,7 +444,7 @@ describe("chunk mode tools", () => {
|
||||
},
|
||||
],
|
||||
}),
|
||||
).rejects.toThrow(/Invalid splice range L5-L2/);
|
||||
).rejects.toThrow(/Invalid line range L5-L2/);
|
||||
|
||||
expect(await Bun.file(filePath).text()).toBe(originalSource);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user