summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorKit Langton <[email protected]>2026-04-13 22:40:12 -0400
committerGitHub <[email protected]>2026-04-13 22:40:12 -0400
commitf954854232231c66546a781507e17ecb51ebab85 (patch)
tree18485d8b69e7ed6344ca76ce73d7fe7470514307
parent6a99079012f8be6c9bde5a042e4c72f2cd5cd0cc (diff)
downloadopencode-f954854232231c66546a781507e17ecb51ebab85.tar.gz
opencode-f954854232231c66546a781507e17ecb51ebab85.zip
refactor(instance): remove state helper (#22381)
-rw-r--r--packages/opencode/src/project/instance.ts8
-rw-r--r--packages/opencode/src/project/state.ts70
-rw-r--r--packages/opencode/test/project/state.test.ts115
3 files changed, 2 insertions, 191 deletions
diff --git a/packages/opencode/src/project/instance.ts b/packages/opencode/src/project/instance.ts
index 12de88a27..505a2a615 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<R>(ctx: InstanceContext, fn: () => R): R {
return context.provide(ctx, fn)
},
- state<S>(init: () => S, dispose?: (state: Awaited<S>) => Promise<void>): () => S {
- return State.create(() => Instance.directory, init, dispose)
- },
async reload(input: { directory: string; init?: () => Promise<any>; 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 a9dce565b..000000000
--- 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<void>
- }
-
- const log = Log.create({ service: "state" })
- const recordsByKey = new Map<string, Map<any, Entry>>()
-
- export function create<S>(root: () => string, init: () => S, dispose?: (state: Awaited<S>) => Promise<void>) {
- return () => {
- const key = root()
- let entries = recordsByKey.get(key)
- if (!entries) {
- entries = new Map<string, Entry>()
- 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<void>[] = []
- 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 c1a6dab31..000000000
--- 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)
-})