From 975183e4eb14ec9a76b431a3160b0ac4b4af5916 Mon Sep 17 00:00:00 2001 From: Rodney Shen Date: Wed, 3 Dec 2025 23:45:43 -0500 Subject: [PATCH 1/3] Writing filetime reads to disk to persist across crash/restarts. --- packages/opencode/src/file/time.ts | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/opencode/src/file/time.ts b/packages/opencode/src/file/time.ts index 5cba5e820..6fcd99bae 100644 --- a/packages/opencode/src/file/time.ts +++ b/packages/opencode/src/file/time.ts @@ -1,5 +1,6 @@ import { Instance } from "../project/instance" import { Log } from "../util/log" +import { Storage } from "../storage/storage" export namespace FileTime { const log = Log.create({ service: "file.time" }) @@ -19,14 +20,33 @@ export namespace FileTime { const { read } = state() read[sessionID] = read[sessionID] || {} read[sessionID][file] = new Date() + + Storage.write(["filetime", sessionID, Buffer.from(file).toString("base64url")], { + time: read[sessionID][file]!.toISOString(), + path: file, + }).catch(() => {}) } - export function get(sessionID: string, file: string) { - return state().read[sessionID]?.[file] + export async function get(sessionID: string, file: string) { + const memTime = state().read[sessionID]?.[file] + if (memTime) return memTime + try { + const stored = await Storage.read<{ time: string; path: string }>(["filetime", sessionID, Buffer.from(file).toString("base64url")]) + if (stored?.time) { + const date = new Date(stored.time) + const { read } = state() + read[sessionID] = read[sessionID] || {} + read[sessionID][file] = date + return date + } + } catch { + // Storage read failed, treat as not read + } + return undefined } export async function assert(sessionID: string, filepath: string) { - const time = get(sessionID, filepath) + const time = await get(sessionID, filepath) if (!time) throw new Error(`You must read the file ${filepath} before overwriting it. Use the Read tool first`) const stats = await Bun.file(filepath).stat() if (stats.mtime.getTime() > time.getTime()) { From c23ff8dac0434f603784d92de5a6893729d54281 Mon Sep 17 00:00:00 2001 From: Rodney Shen Date: Thu, 4 Dec 2025 00:13:28 -0500 Subject: [PATCH 2/3] Update packages/opencode/src/file/time.ts bot comment Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- packages/opencode/src/file/time.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/file/time.ts b/packages/opencode/src/file/time.ts index 6fcd99bae..b0cb722ad 100644 --- a/packages/opencode/src/file/time.ts +++ b/packages/opencode/src/file/time.ts @@ -30,7 +30,22 @@ export namespace FileTime { export async function get(sessionID: string, file: string) { const memTime = state().read[sessionID]?.[file] if (memTime) return memTime - try { + export async function get(sessionID: string, file: string) { + const memTime = state().read[sessionID]?.[file] + if (memTime) return memTime + + const stored = await Storage.read<{ time: string; path: string }>(["filetime", sessionID, Buffer.from(file).toString("base64url")]) + .catch(() => undefined) + + if (stored?.time) { + const date = new Date(stored.time) + const { read } = state() + read[sessionID] = read[sessionID] || {} + read[sessionID][file] = date + return date + } + return undefined + } const stored = await Storage.read<{ time: string; path: string }>(["filetime", sessionID, Buffer.from(file).toString("base64url")]) if (stored?.time) { const date = new Date(stored.time) From 81b88133a366ee9d9af65219a50deace75f89e68 Mon Sep 17 00:00:00 2001 From: Rodney Shen Date: Thu, 4 Dec 2025 00:18:10 -0500 Subject: [PATCH 3/3] no try catch --- packages/opencode/src/file/time.ts | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/packages/opencode/src/file/time.ts b/packages/opencode/src/file/time.ts index b0cb722ad..591a3c29c 100644 --- a/packages/opencode/src/file/time.ts +++ b/packages/opencode/src/file/time.ts @@ -30,13 +30,13 @@ export namespace FileTime { export async function get(sessionID: string, file: string) { const memTime = state().read[sessionID]?.[file] if (memTime) return memTime - export async function get(sessionID: string, file: string) { - const memTime = state().read[sessionID]?.[file] - if (memTime) return memTime - - const stored = await Storage.read<{ time: string; path: string }>(["filetime", sessionID, Buffer.from(file).toString("base64url")]) - .catch(() => undefined) - + + const stored = await Storage.read<{ time: string; path: string }>([ + "filetime", + sessionID, + Buffer.from(file).toString("base64url"), + ]).catch(() => undefined) + if (stored?.time) { const date = new Date(stored.time) const { read } = state() @@ -46,19 +46,6 @@ export namespace FileTime { } return undefined } - const stored = await Storage.read<{ time: string; path: string }>(["filetime", sessionID, Buffer.from(file).toString("base64url")]) - if (stored?.time) { - const date = new Date(stored.time) - const { read } = state() - read[sessionID] = read[sessionID] || {} - read[sessionID][file] = date - return date - } - } catch { - // Storage read failed, treat as not read - } - return undefined - } export async function assert(sessionID: string, filepath: string) { const time = await get(sessionID, filepath)