diff --git a/src/hooks/hashline-read-enhancer/hook.ts b/src/hooks/hashline-read-enhancer/hook.ts index 652c000f5..093312d4a 100644 --- a/src/hooks/hashline-read-enhancer/hook.ts +++ b/src/hooks/hashline-read-enhancer/hook.ts @@ -141,6 +141,22 @@ function extractFilePath(metadata: unknown): string | undefined { return undefined } +function extractLineCount(metadata: unknown): number | undefined { + if (!metadata || typeof metadata !== "object") { + return undefined + } + + const objectMeta = metadata as Record + const candidates = [objectMeta.lineCount, objectMeta.linesWritten, objectMeta.lines] + for (const candidate of candidates) { + if (typeof candidate === "number" && Number.isInteger(candidate) && candidate >= 0) { + return candidate + } + } + + return undefined +} + async function appendWriteHashlineOutput(output: { output: string; metadata: unknown }): Promise { if (output.output.startsWith(WRITE_SUCCESS_MARKER)) { return @@ -151,6 +167,12 @@ async function appendWriteHashlineOutput(output: { output: string; metadata: unk return } + const metadataLineCount = extractLineCount(output.metadata) + if (metadataLineCount !== undefined) { + output.output = `${WRITE_SUCCESS_MARKER} ${metadataLineCount} lines written.` + return + } + const filePath = extractFilePath(output.metadata) if (!filePath) { return diff --git a/src/hooks/hashline-read-enhancer/index.test.ts b/src/hooks/hashline-read-enhancer/index.test.ts index dcab65bc9..b46ffa88e 100644 --- a/src/hooks/hashline-read-enhancer/index.test.ts +++ b/src/hooks/hashline-read-enhancer/index.test.ts @@ -11,9 +11,9 @@ function mockCtx(): PluginInput { return { client: {} as PluginInput["client"], directory: "/test", - project: "/test" as unknown as PluginInput["project"], + project: "/test" as PluginInput["project"], worktree: "/test", - serverUrl: "http://localhost" as unknown as PluginInput["serverUrl"], + serverUrl: "http://localhost" as PluginInput["serverUrl"], $: {} as PluginInput["$"], } } @@ -238,6 +238,26 @@ describe("hashline-read-enhancer", () => { fs.rmSync(tempDir, { recursive: true, force: true }) }) + it("uses write metadata line count without reading the file", async () => { + //#given + const hook = createHashlineReadEnhancerHook(mockCtx(), { hashline_edit: { enabled: true } }) + const input = { tool: "write", sessionID: "s", callID: "c" } + const output = { + title: "write", + output: "Wrote file successfully.", + metadata: { + filepath: "/tmp/hashline-metadata-fast-path-missing-file.ts", + lineCount: 7, + }, + } + + //#when + await hook["tool.execute.after"](input, output) + + //#then + expect(output.output).toBe("File written successfully. 7 lines written.") + }) + it("does not overwrite write tool error output with success message", async () => { //#given — write tool failed, but stale file exists from previous write const hook = createHashlineReadEnhancerHook(mockCtx(), { hashline_edit: { enabled: true } })