diff --git a/packages/opencode/src/tool/hashline_read.ts b/packages/opencode/src/tool/hashline_read.ts
index beece02d25d..ed11654a6d8 100644
--- a/packages/opencode/src/tool/hashline_read.ts
+++ b/packages/opencode/src/tool/hashline_read.ts
@@ -1,5 +1,5 @@
import z from "zod"
-import * as fs from "fs"
+import * as fs from "fs/promises"
import * as path from "path"
import { Tool } from "./tool"
import { LSP } from "../lsp"
@@ -48,23 +48,21 @@ export const HashlineReadTool = Tool.define("hashline_read", {
})
if (!stat) {
- const dir = path.dirname(filepath)
- const base = path.basename(filepath)
-
- const dirEntries = fs.readdirSync(dir)
- const suggestions = dirEntries
- .filter(
- (entry) =>
- entry.toLowerCase().includes(base.toLowerCase()) || base.toLowerCase().includes(entry.toLowerCase()),
- )
- .map((entry) => path.join(dir, entry))
- .slice(0, 3)
-
- if (suggestions.length > 0) {
- throw new Error(`File not found: ${filepath}\n\nDid you mean one of these?\n${suggestions.join("\n")}`)
+ await fs.mkdir(path.dirname(filepath), { recursive: true })
+ await Bun.write(filepath, "")
+
+ FileTime.read(ctx.sessionID, filepath)
+ FileTime.hashlineRead(ctx.sessionID, filepath)
+
+ return {
+ title,
+ output: [`${filepath}`, `file`, ""].join("\n") + "\n\n\n(File created successfully - empty and ready for editing)",
+ metadata: {
+ preview: "",
+ truncated: false,
+ loaded: [],
+ },
}
-
- throw new Error(`File not found: ${filepath}`)
}
if (stat.isDirectory()) {
@@ -192,4 +190,4 @@ async function isBinaryFile(filepath: string, file: Bun.BunFile): Promise 0.3
-}
\ No newline at end of file
+}
diff --git a/packages/opencode/test/tool/hashline_read.test.ts b/packages/opencode/test/tool/hashline_read.test.ts
index 17ba3a62421..3234015157e 100644
--- a/packages/opencode/test/tool/hashline_read.test.ts
+++ b/packages/opencode/test/tool/hashline_read.test.ts
@@ -109,17 +109,24 @@ describe("tool.hashline_read binary file detection", () => {
})
describe("tool.hashline_read non-existent file", () => {
- test("returns error for non-existent file", async () => {
+ test("creates non-existent file and returns successfully", async () => {
await using tmp = await tmpdir({})
await Instance.provide({
directory: tmp.path,
fn: async () => {
const hashlineRead = await HashlineReadTool.init()
- const error = await hashlineRead
- .execute({ filePath: path.join(tmp.path, "nonexistent.txt") }, ctx)
- .catch((e) => e)
- expect(error).toBeInstanceOf(Error)
- expect(error.message).toContain("File not found")
+ const filePath = path.join(tmp.path, "nonexistent.txt")
+
+ expect(await Bun.file(filePath).exists()).toBe(false)
+
+ const result = await hashlineRead.execute({ filePath }, ctx)
+
+ expect(result).toBeDefined()
+ expect(await Bun.file(filePath).exists()).toBe(true)
+ expect(result.output).toContain(`${filePath}`)
+ expect(result.output).toContain("file")
+ expect(result.output).toContain("(File created successfully - empty and ready for editing)")
+ expect(result.metadata.preview).toBe("")
},
})
})
@@ -265,4 +272,4 @@ describe("tool.hashline_read CJK byte counting", () => {
},
})
})
-})
\ No newline at end of file
+})