feat(hashline-edit): add anchor insert modes and strict insert validation
This commit is contained in:
@@ -11,12 +11,10 @@ function createMockContext(): ToolContext {
|
||||
sessionID: "test",
|
||||
messageID: "test",
|
||||
agent: "test",
|
||||
directory: "/tmp",
|
||||
worktree: "/tmp",
|
||||
abort: new AbortController().signal,
|
||||
metadata: mock(() => {}),
|
||||
ask: async () => {},
|
||||
}
|
||||
} as unknown as ToolContext
|
||||
}
|
||||
|
||||
describe("createHashlineEditTool", () => {
|
||||
@@ -103,7 +101,7 @@ describe("createHashlineEditTool", () => {
|
||||
|
||||
//#then
|
||||
expect(result).toContain("Error")
|
||||
expect(result).toContain("hash")
|
||||
expect(result).toContain(">>>")
|
||||
})
|
||||
|
||||
it("preserves literal backslash-n and supports string[] payload", async () => {
|
||||
@@ -132,4 +130,90 @@ describe("createHashlineEditTool", () => {
|
||||
//#then
|
||||
expect(fs.readFileSync(filePath, "utf-8")).toBe("join(\\n)\na\nb\nline2")
|
||||
})
|
||||
|
||||
it("supports insert_before and insert_between", async () => {
|
||||
//#given
|
||||
const filePath = path.join(tempDir, "test.txt")
|
||||
fs.writeFileSync(filePath, "line1\nline2\nline3")
|
||||
const line1 = computeLineHash(1, "line1")
|
||||
const line2 = computeLineHash(2, "line2")
|
||||
const line3 = computeLineHash(3, "line3")
|
||||
|
||||
//#when
|
||||
await tool.execute(
|
||||
{
|
||||
filePath,
|
||||
edits: [
|
||||
{ type: "insert_before", line: `3#${line3}`, text: ["before3"] },
|
||||
{ type: "insert_between", after_line: `1#${line1}`, before_line: `2#${line2}`, text: ["between"] },
|
||||
],
|
||||
},
|
||||
createMockContext(),
|
||||
)
|
||||
|
||||
//#then
|
||||
expect(fs.readFileSync(filePath, "utf-8")).toBe("line1\nbetween\nline2\nbefore3\nline3")
|
||||
})
|
||||
|
||||
it("returns error when insert text is empty array", async () => {
|
||||
//#given
|
||||
const filePath = path.join(tempDir, "test.txt")
|
||||
fs.writeFileSync(filePath, "line1\nline2")
|
||||
const line1 = computeLineHash(1, "line1")
|
||||
|
||||
//#when
|
||||
const result = await tool.execute(
|
||||
{
|
||||
filePath,
|
||||
edits: [{ type: "insert_after", line: `1#${line1}`, text: [] }],
|
||||
},
|
||||
createMockContext(),
|
||||
)
|
||||
|
||||
//#then
|
||||
expect(result).toContain("Error")
|
||||
expect(result).toContain("non-empty")
|
||||
})
|
||||
|
||||
it("supports file rename with edits", async () => {
|
||||
//#given
|
||||
const filePath = path.join(tempDir, "source.txt")
|
||||
const renamedPath = path.join(tempDir, "renamed.txt")
|
||||
fs.writeFileSync(filePath, "line1\nline2")
|
||||
const line2 = computeLineHash(2, "line2")
|
||||
|
||||
//#when
|
||||
await tool.execute(
|
||||
{
|
||||
filePath,
|
||||
rename: renamedPath,
|
||||
edits: [{ type: "set_line", line: `2#${line2}`, text: "line2-updated" }],
|
||||
},
|
||||
createMockContext(),
|
||||
)
|
||||
|
||||
//#then
|
||||
expect(fs.existsSync(filePath)).toBe(false)
|
||||
expect(fs.readFileSync(renamedPath, "utf-8")).toBe("line1\nline2-updated")
|
||||
})
|
||||
|
||||
it("supports file delete mode", async () => {
|
||||
//#given
|
||||
const filePath = path.join(tempDir, "delete-me.txt")
|
||||
fs.writeFileSync(filePath, "line1")
|
||||
|
||||
//#when
|
||||
const result = await tool.execute(
|
||||
{
|
||||
filePath,
|
||||
delete: true,
|
||||
edits: [],
|
||||
},
|
||||
createMockContext(),
|
||||
)
|
||||
|
||||
//#then
|
||||
expect(fs.existsSync(filePath)).toBe(false)
|
||||
expect(result).toContain("Successfully deleted")
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user