From 365d863e3ac73854d57cf54a37f9277b27d63fd6 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Tue, 24 Feb 2026 18:21:05 +0900 Subject: [PATCH] fix(hashline-edit): use instanceof for hash mismatch error detection --- .../hashline-edit/hashline-edit-executor.ts | 3 ++- src/tools/hashline-edit/tools.test.ts | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/tools/hashline-edit/hashline-edit-executor.ts b/src/tools/hashline-edit/hashline-edit-executor.ts index bbbba4ac..e20ebbf9 100644 --- a/src/tools/hashline-edit/hashline-edit-executor.ts +++ b/src/tools/hashline-edit/hashline-edit-executor.ts @@ -5,6 +5,7 @@ import { countLineDiffs, generateUnifiedDiff } from "./diff-utils" import { canonicalizeFileText, restoreFileText } from "./file-text-canonicalization" import { normalizeHashlineEdits, type RawHashlineEdit } from "./normalize-edits" import type { HashlineEdit } from "./types" +import { HashlineMismatchError } from "./validation" interface HashlineEditArgs { filePath: string @@ -158,7 +159,7 @@ export async function executeHashlineEditTool(args: HashlineEditArgs, context: T return `Updated ${effectivePath}` } catch (error) { const message = error instanceof Error ? error.message : String(error) - if (message.toLowerCase().includes("hash")) { + if (error instanceof HashlineMismatchError) { return `Error: hash mismatch - ${message}\nTip: reuse LINE#ID entries from the latest read/edit output, or batch related edits in one call.` } return `Error: ${message}` diff --git a/src/tools/hashline-edit/tools.test.ts b/src/tools/hashline-edit/tools.test.ts index 46f663a3..cb76b834 100644 --- a/src/tools/hashline-edit/tools.test.ts +++ b/src/tools/hashline-edit/tools.test.ts @@ -103,6 +103,25 @@ describe("createHashlineEditTool", () => { expect(result).toContain(">>>") }) + it("does not classify invalid pos format as hash mismatch", async () => { + //#given + const filePath = path.join(tempDir, "invalid-format.txt") + fs.writeFileSync(filePath, "line1\nline2") + + //#when + const result = await tool.execute( + { + filePath, + edits: [{ op: "replace", pos: "42", lines: "updated" }], + }, + createMockContext(), + ) + + //#then + expect(result).toContain("Error") + expect(result.toLowerCase()).not.toContain("hash mismatch") + }) + it("preserves literal backslash-n and supports string[] payload", async () => { //#given const filePath = path.join(tempDir, "test.txt")