From f954854232231c66546a781507e17ecb51ebab85 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Mon, 13 Apr 2026 22:40:12 -0400 Subject: [PATCH] refactor(instance): remove state helper (#22381) --- packages/opencode/src/project/instance.ts | 8 +- packages/opencode/src/project/state.ts | 70 ----------- packages/opencode/test/project/state.test.ts | 115 ------------------- 3 files changed, 2 insertions(+), 191 deletions(-) delete mode 100644 packages/opencode/src/project/state.ts delete mode 100644 packages/opencode/test/project/state.test.ts diff --git a/packages/opencode/src/project/instance.ts b/packages/opencode/src/project/instance.ts index 12de88a27a..505a2a6150 100644 --- a/packages/opencode/src/project/instance.ts +++ b/packages/opencode/src/project/instance.ts @@ -6,7 +6,6 @@ import { Log } from "@/util/log" import { LocalContext } from "../util/local-context" import { Project } from "./project" import { WorkspaceContext } from "@/control-plane/workspace-context" -import { State } from "./state" export interface InstanceContext { directory: string @@ -113,13 +112,10 @@ export const Instance = { restore(ctx: InstanceContext, fn: () => R): R { return context.provide(ctx, fn) }, - state(init: () => S, dispose?: (state: Awaited) => Promise): () => S { - return State.create(() => Instance.directory, init, dispose) - }, async reload(input: { directory: string; init?: () => Promise; project?: Project.Info; worktree?: string }) { const directory = Filesystem.resolve(input.directory) Log.Default.info("reloading instance", { directory }) - await Promise.all([State.dispose(directory), disposeInstance(directory)]) + await disposeInstance(directory) cache.delete(directory) const next = track(directory, boot({ ...input, directory })) @@ -141,7 +137,7 @@ export const Instance = { const directory = Instance.directory const project = Instance.project Log.Default.info("disposing instance", { directory }) - await Promise.all([State.dispose(directory), disposeInstance(directory)]) + await disposeInstance(directory) cache.delete(directory) GlobalBus.emit("event", { diff --git a/packages/opencode/src/project/state.ts b/packages/opencode/src/project/state.ts deleted file mode 100644 index a9dce565b5..0000000000 --- a/packages/opencode/src/project/state.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { Log } from "@/util/log" - -export namespace State { - interface Entry { - state: any - dispose?: (state: any) => Promise - } - - const log = Log.create({ service: "state" }) - const recordsByKey = new Map>() - - export function create(root: () => string, init: () => S, dispose?: (state: Awaited) => Promise) { - return () => { - const key = root() - let entries = recordsByKey.get(key) - if (!entries) { - entries = new Map() - recordsByKey.set(key, entries) - } - const exists = entries.get(init) - if (exists) return exists.state as S - const state = init() - entries.set(init, { - state, - dispose, - }) - return state - } - } - - export async function dispose(key: string) { - const entries = recordsByKey.get(key) - if (!entries) return - - log.info("waiting for state disposal to complete", { key }) - - let disposalFinished = false - - setTimeout(() => { - if (!disposalFinished) { - log.warn( - "state disposal is taking an unusually long time - if it does not complete in a reasonable time, please report this as a bug", - { key }, - ) - } - }, 10000).unref() - - const tasks: Promise[] = [] - for (const [init, entry] of entries) { - if (!entry.dispose) continue - - const label = typeof init === "function" ? init.name : String(init) - - const task = Promise.resolve(entry.state) - .then((state) => entry.dispose!(state)) - .catch((error) => { - log.error("Error while disposing state:", { error, key, init: label }) - }) - - tasks.push(task) - } - await Promise.all(tasks) - - entries.clear() - recordsByKey.delete(key) - - disposalFinished = true - log.info("state disposal completed", { key }) - } -} diff --git a/packages/opencode/test/project/state.test.ts b/packages/opencode/test/project/state.test.ts deleted file mode 100644 index c1a6dab315..0000000000 --- a/packages/opencode/test/project/state.test.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { afterEach, expect, test } from "bun:test" - -import { Instance } from "../../src/project/instance" -import { tmpdir } from "../fixture/fixture" - -afterEach(async () => { - await Instance.disposeAll() -}) - -test("Instance.state caches values for the same instance", async () => { - await using tmp = await tmpdir() - let n = 0 - const state = Instance.state(() => ({ n: ++n })) - - await Instance.provide({ - directory: tmp.path, - fn: async () => { - const a = state() - const b = state() - expect(a).toBe(b) - expect(n).toBe(1) - }, - }) -}) - -test("Instance.state isolates values by directory", async () => { - await using a = await tmpdir() - await using b = await tmpdir() - let n = 0 - const state = Instance.state(() => ({ n: ++n })) - - const x = await Instance.provide({ - directory: a.path, - fn: async () => state(), - }) - const y = await Instance.provide({ - directory: b.path, - fn: async () => state(), - }) - const z = await Instance.provide({ - directory: a.path, - fn: async () => state(), - }) - - expect(x).toBe(z) - expect(x).not.toBe(y) - expect(n).toBe(2) -}) - -test("Instance.state is disposed on instance reload", async () => { - await using tmp = await tmpdir() - const seen: string[] = [] - let n = 0 - const state = Instance.state( - () => ({ n: ++n }), - async (value) => { - seen.push(String(value.n)) - }, - ) - - const a = await Instance.provide({ - directory: tmp.path, - fn: async () => state(), - }) - await Instance.reload({ directory: tmp.path }) - const b = await Instance.provide({ - directory: tmp.path, - fn: async () => state(), - }) - - expect(a).not.toBe(b) - expect(seen).toEqual(["1"]) -}) - -test("Instance.state is disposed on disposeAll", async () => { - await using a = await tmpdir() - await using b = await tmpdir() - const seen: string[] = [] - const state = Instance.state( - () => ({ dir: Instance.directory }), - async (value) => { - seen.push(value.dir) - }, - ) - - await Instance.provide({ - directory: a.path, - fn: async () => state(), - }) - await Instance.provide({ - directory: b.path, - fn: async () => state(), - }) - await Instance.disposeAll() - - expect(seen.sort()).toEqual([a.path, b.path].sort()) -}) - -test("Instance.state dedupes concurrent promise initialization", async () => { - await using tmp = await tmpdir() - let n = 0 - const state = Instance.state(async () => { - n += 1 - await Bun.sleep(10) - return { n } - }) - - const [a, b] = await Instance.provide({ - directory: tmp.path, - fn: async () => Promise.all([state(), state()]), - }) - - expect(a).toBe(b) - expect(n).toBe(1) -})