refactor(hashline-edit): align tool payload to op/pos/end/lines

Unify hashline_edit input with replace/append/prepend + pos/end/lines semantics so callers use a single stable shape. Add normalization coverage and refresh tool guidance/tests to reduce schema confusion and stale legacy payload usage.
This commit is contained in:
minpeter
2026-02-24 03:00:38 +09:00
parent 1cf918362d
commit 9eda19bf7b
5 changed files with 210 additions and 189 deletions
+25 -26
View File
@@ -31,7 +31,7 @@ describe("createHashlineEditTool", () => {
fs.rmSync(tempDir, { recursive: true, force: true })
})
it("applies set_line with LINE#ID anchor", async () => {
it("applies replace with single LINE#ID anchor", async () => {
//#given
const filePath = path.join(tempDir, "test.txt")
fs.writeFileSync(filePath, "line1\nline2\nline3")
@@ -41,7 +41,7 @@ describe("createHashlineEditTool", () => {
const result = await tool.execute(
{
filePath,
edits: [{ type: "set_line", line: `2#${hash}`, text: "modified line2" }],
edits: [{ op: "replace", pos: `2#${hash}`, lines: "modified line2" }],
},
createMockContext(),
)
@@ -51,7 +51,7 @@ describe("createHashlineEditTool", () => {
expect(result).toBe(`Updated ${filePath}`)
})
it("applies replace_lines and insert_after", async () => {
it("applies ranged replace and anchored append", async () => {
//#given
const filePath = path.join(tempDir, "test.txt")
fs.writeFileSync(filePath, "line1\nline2\nline3\nline4")
@@ -65,15 +65,15 @@ describe("createHashlineEditTool", () => {
filePath,
edits: [
{
type: "replace_lines",
start_line: `2#${line2Hash}`,
end_line: `3#${line3Hash}`,
text: "replaced",
op: "replace",
pos: `2#${line2Hash}`,
end: `3#${line3Hash}`,
lines: "replaced",
},
{
type: "insert_after",
line: `4#${line4Hash}`,
text: "inserted",
op: "append",
pos: `4#${line4Hash}`,
lines: "inserted",
},
],
},
@@ -93,7 +93,7 @@ describe("createHashlineEditTool", () => {
const result = await tool.execute(
{
filePath,
edits: [{ type: "set_line", line: "1#ZZ", text: "new" }],
edits: [{ op: "replace", pos: "1#ZZ", lines: "new" }],
},
createMockContext(),
)
@@ -113,7 +113,7 @@ describe("createHashlineEditTool", () => {
await tool.execute(
{
filePath,
edits: [{ type: "set_line", line: `1#${line1Hash}`, text: "join(\\n)" }],
edits: [{ op: "replace", pos: `1#${line1Hash}`, lines: "join(\\n)" }],
},
createMockContext(),
)
@@ -121,7 +121,7 @@ describe("createHashlineEditTool", () => {
await tool.execute(
{
filePath,
edits: [{ type: "insert_after", line: `1#${computeLineHash(1, "join(\\n)")}`, text: ["a", "b"] }],
edits: [{ op: "append", pos: `1#${computeLineHash(1, "join(\\n)")}`, lines: ["a", "b"] }],
},
createMockContext(),
)
@@ -130,12 +130,11 @@ describe("createHashlineEditTool", () => {
expect(fs.readFileSync(filePath, "utf-8")).toBe("join(\\n)\na\nb\nline2")
})
it("supports insert_before and insert_between", async () => {
it("supports anchored prepend and anchored append", 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
@@ -143,8 +142,8 @@ describe("createHashlineEditTool", () => {
{
filePath,
edits: [
{ type: "insert_before", line: `3#${line3}`, text: ["before3"] },
{ type: "insert_between", after_line: `1#${line1}`, before_line: `2#${line2}`, text: ["between"] },
{ op: "prepend", pos: `3#${line3}`, lines: ["before3"] },
{ op: "append", pos: `1#${line1}`, lines: ["between"] },
],
},
createMockContext(),
@@ -164,7 +163,7 @@ describe("createHashlineEditTool", () => {
const result = await tool.execute(
{
filePath,
edits: [{ type: "insert_after", line: `1#${line1}`, text: [] }],
edits: [{ op: "append", pos: `1#${line1}`, lines: [] }],
},
createMockContext(),
)
@@ -186,7 +185,7 @@ describe("createHashlineEditTool", () => {
{
filePath,
rename: renamedPath,
edits: [{ type: "set_line", line: `2#${line2}`, text: "line2-updated" }],
edits: [{ op: "replace", pos: `2#${line2}`, lines: "line2-updated" }],
},
createMockContext(),
)
@@ -226,8 +225,8 @@ describe("createHashlineEditTool", () => {
{
filePath,
edits: [
{ type: "append", text: ["line2"] },
{ type: "prepend", text: ["line1"] },
{ op: "append", lines: ["line2"] },
{ op: "prepend", lines: ["line1"] },
],
},
createMockContext(),
@@ -239,7 +238,7 @@ describe("createHashlineEditTool", () => {
expect(result).toBe(`Updated ${filePath}`)
})
it("accepts replace_lines with one anchor and downgrades to set_line", async () => {
it("accepts replace with one anchor", async () => {
//#given
const filePath = path.join(tempDir, "degrade.txt")
fs.writeFileSync(filePath, "line1\nline2\nline3")
@@ -249,7 +248,7 @@ describe("createHashlineEditTool", () => {
const result = await tool.execute(
{
filePath,
edits: [{ type: "replace_lines", start_line: `2#${line2Hash}`, text: ["line2-updated"] }],
edits: [{ op: "replace", pos: `2#${line2Hash}`, lines: ["line2-updated"] }],
},
createMockContext(),
)
@@ -259,7 +258,7 @@ describe("createHashlineEditTool", () => {
expect(result).toBe(`Updated ${filePath}`)
})
it("accepts insert_after using after_line alias", async () => {
it("accepts anchored append using end alias", async () => {
//#given
const filePath = path.join(tempDir, "alias.txt")
fs.writeFileSync(filePath, "line1\nline2")
@@ -269,7 +268,7 @@ describe("createHashlineEditTool", () => {
await tool.execute(
{
filePath,
edits: [{ type: "insert_after", after_line: `1#${line1Hash}`, text: ["inserted"] }],
edits: [{ op: "append", end: `1#${line1Hash}`, lines: ["inserted"] }],
},
createMockContext(),
)
@@ -289,7 +288,7 @@ describe("createHashlineEditTool", () => {
await tool.execute(
{
filePath,
edits: [{ type: "set_line", line: `2#${line2Hash}`, text: "line2-updated" }],
edits: [{ op: "replace", pos: `2#${line2Hash}`, lines: "line2-updated" }],
},
createMockContext(),
)