Replace Instance.disposeAll/load with fixture helper (#25418)

This commit is contained in:
Kit Langton 2026-05-02 10:56:15 -04:00 committed by GitHub
commit 4c4860fb24
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
59 changed files with 139 additions and 130 deletions

View file

@ -1,5 +1,5 @@
import { AppRuntime } from "@/effect/app-runtime"
import { Instance } from "../project/instance" import { Instance } from "../project/instance"
import { InstanceStore } from "../project/instance-store"
export async function bootstrap<T>(directory: string, cb: () => Promise<T>) { export async function bootstrap<T>(directory: string, cb: () => Promise<T>) {
return Instance.provide({ return Instance.provide({
@ -9,7 +9,7 @@ export async function bootstrap<T>(directory: string, cb: () => Promise<T>) {
const result = await cb() const result = await cb()
return result return result
} finally { } finally {
await Instance.dispose() await InstanceStore.runtime.runPromise((s) => s.dispose(Instance.current))
} }
}, },
}) })

View file

@ -2,6 +2,7 @@ import { Installation } from "@/installation"
import { Server } from "@/server/server" import { Server } from "@/server/server"
import * as Log from "@opencode-ai/core/util/log" import * as Log from "@opencode-ai/core/util/log"
import { Instance } from "@/project/instance" import { Instance } from "@/project/instance"
import { InstanceStore } from "@/project/instance-store"
import { Rpc } from "@/util/rpc" import { Rpc } from "@/util/rpc"
import { upgrade } from "@/cli/upgrade" import { upgrade } from "@/cli/upgrade"
import { Config } from "@/config/config" import { Config } from "@/config/config"
@ -87,7 +88,7 @@ export const rpc = {
async shutdown() { async shutdown() {
Log.Default.info("worker shutting down") Log.Default.info("worker shutting down")
await Instance.disposeAll() await InstanceStore.runtime.runPromise((s) => s.disposeAll())
if (server) await server.stop(true) if (server) await server.stop(true)
}, },
} }

View file

@ -11,7 +11,9 @@ import { Flag } from "@opencode-ai/core/flag/flag"
import { Auth } from "../auth" import { Auth } from "../auth"
import { Env } from "../env" import { Env } from "../env"
import { applyEdits, modify } from "jsonc-parser" import { applyEdits, modify } from "jsonc-parser"
import { Instance, type InstanceContext } from "../project/instance" import { type InstanceContext } from "../project/instance"
import { InstanceStore } from "../project/instance-store"
import { InstanceRef } from "@/effect/instance-ref"
import { InstallationLocal, InstallationVersion } from "@opencode-ai/core/installation/version" import { InstallationLocal, InstallationVersion } from "@opencode-ai/core/installation/version"
import { existsSync } from "fs" import { existsSync } from "fs"
import { GlobalBus } from "@/bus/global" import { GlobalBus } from "@/bus/global"
@ -736,12 +738,16 @@ export const layer = Layer.effect(
yield* fs yield* fs
.writeFileString(file, JSON.stringify(mergeDeep(writable(existing), writable(config)), null, 2)) .writeFileString(file, JSON.stringify(mergeDeep(writable(existing), writable(config)), null, 2))
.pipe(Effect.orDie) .pipe(Effect.orDie)
if (options?.dispose !== false) yield* Effect.promise(() => Instance.dispose()) if (options?.dispose !== false) {
const ctx = yield* InstanceRef
if (ctx) yield* Effect.promise(() => InstanceStore.runtime.runPromise((s) => s.dispose(ctx)))
}
}) })
const invalidate = Effect.fn("Config.invalidate")(function* (wait?: boolean) { const invalidate = Effect.fn("Config.invalidate")(function* (wait?: boolean) {
yield* invalidateGlobal yield* invalidateGlobal
const task = Instance.disposeAll() const task = InstanceStore.runtime
.runPromise((s) => s.disposeAll())
.catch(() => undefined) .catch(() => undefined)
.finally(() => .finally(() =>
GlobalBus.emit("event", { GlobalBus.emit("event", {

View file

@ -39,6 +39,7 @@ import { Command } from "@/command"
import { Truncate } from "@/tool/truncate" import { Truncate } from "@/tool/truncate"
import { ToolRegistry } from "@/tool/registry" import { ToolRegistry } from "@/tool/registry"
import { Format } from "@/format" import { Format } from "@/format"
import { InstanceStore } from "@/project/instance-store"
import { Project } from "@/project/project" import { Project } from "@/project/project"
import { Vcs } from "@/project/vcs" import { Vcs } from "@/project/vcs"
import { Workspace } from "@/control-plane/workspace" import { Workspace } from "@/control-plane/workspace"
@ -90,6 +91,7 @@ export const AppLayer = Layer.mergeAll(
Truncate.defaultLayer, Truncate.defaultLayer,
ToolRegistry.defaultLayer, ToolRegistry.defaultLayer,
Format.defaultLayer, Format.defaultLayer,
InstanceStore.defaultLayer,
Project.defaultLayer, Project.defaultLayer,
Vcs.defaultLayer, Vcs.defaultLayer,
Workspace.defaultLayer, Workspace.defaultLayer,

View file

@ -6,13 +6,11 @@ export type { InstanceContext } from "./instance-context"
export type { LoadInput } from "./instance-store" export type { LoadInput } from "./instance-store"
export const Instance = { export const Instance = {
load(input: InstanceStore.LoadInput): Promise<InstanceContext> {
return InstanceStore.runtime.runPromise((store) => store.load(input))
},
async provide<R>(input: { directory: string; init?: Effect.Effect<void>; fn: () => R }): Promise<R> { async provide<R>(input: { directory: string; init?: Effect.Effect<void>; fn: () => R }): Promise<R> {
return context.provide(await Instance.load({ directory: input.directory, init: input.init }), async () => const ctx = await InstanceStore.runtime.runPromise((store) =>
input.fn(), store.load({ directory: input.directory, init: input.init }),
) )
return context.provide(ctx, async () => input.fn())
}, },
get current() { get current() {
return context.use() return context.use()
@ -50,7 +48,4 @@ export const Instance = {
async dispose() { async dispose() {
return InstanceStore.runtime.runPromise((store) => store.dispose(Instance.current)) return InstanceStore.runtime.runPromise((store) => store.dispose(Instance.current))
}, },
async disposeAll() {
return InstanceStore.runtime.runPromise((store) => store.disposeAll())
},
} }

View file

@ -8,7 +8,7 @@ import { SyncEvent } from "@/sync"
import { GlobalBus } from "@/bus/global" import { GlobalBus } from "@/bus/global"
import { AppRuntime } from "@/effect/app-runtime" import { AppRuntime } from "@/effect/app-runtime"
import { AsyncQueue } from "@/util/queue" import { AsyncQueue } from "@/util/queue"
import { Instance } from "../../project/instance" import { InstanceStore } from "../../project/instance-store"
import { Installation } from "@/installation" import { Installation } from "@/installation"
import { InstallationVersion } from "@opencode-ai/core/installation/version" import { InstallationVersion } from "@opencode-ai/core/installation/version"
import * as Log from "@opencode-ai/core/util/log" import * as Log from "@opencode-ai/core/util/log"
@ -200,7 +200,7 @@ export const GlobalRoutes = lazy(() =>
}, },
}), }),
async (c) => { async (c) => {
await Instance.disposeAll() await InstanceStore.runtime.runPromise((s) => s.disposeAll())
GlobalBus.emit("event", { GlobalBus.emit("event", {
directory: "global", directory: "global",
payload: { payload: {

View file

@ -6,6 +6,7 @@ import z from "zod"
import { Format } from "@/format" import { Format } from "@/format"
import { TuiRoutes } from "./tui" import { TuiRoutes } from "./tui"
import { Instance } from "@/project/instance" import { Instance } from "@/project/instance"
import { InstanceStore } from "@/project/instance-store"
import { Vcs } from "@/project/vcs" import { Vcs } from "@/project/vcs"
import { Agent } from "@/agent/agent" import { Agent } from "@/agent/agent"
import { Skill } from "@/skill" import { Skill } from "@/skill"
@ -62,7 +63,7 @@ export const InstanceRoutes = (upgrade: UpgradeWebSocket): Hono => {
}, },
}), }),
async (c) => { async (c) => {
await Instance.dispose() await InstanceStore.runtime.runPromise((s) => s.dispose(Instance.current))
return c.json(true) return c.json(true)
}, },
) )

View file

@ -81,11 +81,7 @@ export const ProjectRoutes = lazy(() =>
Project.Service.use((svc) => svc.initGit({ directory: dir, project: prev })), Project.Service.use((svc) => svc.initGit({ directory: dir, project: prev })),
) )
if (next.id === prev.id && next.vcs === prev.vcs && next.worktree === prev.worktree) return c.json(next) if (next.id === prev.id && next.vcs === prev.vcs && next.worktree === prev.worktree) return c.json(next)
await Instance.reload({ await Instance.reload({ directory: dir, worktree: dir, project: next })
directory: dir,
worktree: dir,
project: next,
})
return c.json(next) return c.json(next)
}, },
) )

View file

@ -1,7 +1,7 @@
import { afterEach, test, expect } from "bun:test" import { afterEach, test, expect } from "bun:test"
import { Effect } from "effect" import { Effect } from "effect"
import path from "path" import path from "path"
import { provideInstance, tmpdir } from "../fixture/fixture" import { disposeAllInstances, provideInstance, tmpdir } from "../fixture/fixture"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { Agent } from "../../src/agent/agent" import { Agent } from "../../src/agent/agent"
import { Permission } from "../../src/permission" import { Permission } from "../../src/permission"
@ -18,7 +18,7 @@ function load<A>(dir: string, fn: (svc: Agent.Interface) => Effect.Effect<A>) {
} }
afterEach(async () => { afterEach(async () => {
await Instance.disposeAll() await disposeAllInstances()
}) })
test("returns default native agents when no config", async () => { test("returns default native agents when no config", async () => {

View file

@ -4,7 +4,7 @@ import { Bus } from "../../src/bus"
import { BusEvent } from "../../src/bus/bus-event" import { BusEvent } from "../../src/bus/bus-event"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
import { provideInstance, provideTmpdirInstance, tmpdirScoped } from "../fixture/fixture" import { disposeAllInstances, provideInstance, provideTmpdirInstance, tmpdirScoped } from "../fixture/fixture"
import { testEffect } from "../lib/effect" import { testEffect } from "../lib/effect"
const TestEvent = { const TestEvent = {
@ -151,7 +151,7 @@ describe("Bus (Effect-native)", () => {
}).pipe(provideInstance(dir)) }).pipe(provideInstance(dir))
// Dispose from OUTSIDE the instance scope // Dispose from OUTSIDE the instance scope
yield* Effect.promise(() => Instance.disposeAll()) yield* Effect.promise(disposeAllInstances)
yield* Deferred.await(disposed).pipe(Effect.timeout("2 seconds")) yield* Deferred.await(disposed).pipe(Effect.timeout("2 seconds"))
expect(types).toContain("test.effect.ping") expect(types).toContain("test.effect.ping")

View file

@ -3,7 +3,7 @@ import { Schema } from "effect"
import { Bus } from "../../src/bus" import { Bus } from "../../src/bus"
import { BusEvent } from "../../src/bus/bus-event" import { BusEvent } from "../../src/bus/bus-event"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { tmpdir } from "../fixture/fixture" import { disposeAllInstances, tmpdir } from "../fixture/fixture"
const TestEvent = BusEvent.define("test.integration", Schema.Struct({ value: Schema.Number })) const TestEvent = BusEvent.define("test.integration", Schema.Struct({ value: Schema.Number }))
@ -12,7 +12,7 @@ function withInstance(directory: string, fn: () => Promise<void>) {
} }
describe("Bus integration: acquireRelease subscriber pattern", () => { describe("Bus integration: acquireRelease subscriber pattern", () => {
afterEach(() => Instance.disposeAll()) afterEach(() => disposeAllInstances())
test("subscriber via callback facade receives events and cleans up on unsub", async () => { test("subscriber via callback facade receives events and cleans up on unsub", async () => {
await using tmp = await tmpdir() await using tmp = await tmpdir()
@ -78,7 +78,7 @@ describe("Bus integration: acquireRelease subscriber pattern", () => {
await Bun.sleep(10) await Bun.sleep(10)
}) })
await Instance.disposeAll() await disposeAllInstances()
await Bun.sleep(50) await Bun.sleep(50)
expect(received).toEqual([1]) expect(received).toEqual([1])

View file

@ -3,7 +3,7 @@ import { Schema } from "effect"
import { Bus } from "../../src/bus" import { Bus } from "../../src/bus"
import { BusEvent } from "../../src/bus/bus-event" import { BusEvent } from "../../src/bus/bus-event"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { tmpdir } from "../fixture/fixture" import { disposeAllInstances, tmpdir } from "../fixture/fixture"
const TestEvent = { const TestEvent = {
Ping: BusEvent.define("test.ping", Schema.Struct({ value: Schema.Number })), Ping: BusEvent.define("test.ping", Schema.Struct({ value: Schema.Number })),
@ -15,7 +15,7 @@ function withInstance(directory: string, fn: () => Promise<void>) {
} }
describe("Bus", () => { describe("Bus", () => {
afterEach(() => Instance.disposeAll()) afterEach(() => disposeAllInstances())
describe("publish + subscribe", () => { describe("publish + subscribe", () => {
test("subscriber is live immediately after subscribe returns", async () => { test("subscriber is live immediately after subscribe returns", async () => {
@ -208,8 +208,8 @@ describe("Bus", () => {
await Bun.sleep(10) await Bun.sleep(10)
}) })
// Instance.disposeAll triggers the finalizer which publishes InstanceDisposed // disposeAllInstances triggers the finalizer which publishes InstanceDisposed
await Instance.disposeAll() await disposeAllInstances()
await Bun.sleep(50) await Bun.sleep(50)
expect(received).toContain("test.ping") expect(received).toContain("test.ping")

View file

@ -12,7 +12,7 @@ import { Account } from "../../src/account/account"
import { AccessToken, AccountID, OrgID } from "../../src/account/schema" import { AccessToken, AccountID, OrgID } from "../../src/account/schema"
import { AppFileSystem } from "@opencode-ai/core/filesystem" import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { Env } from "../../src/env" import { Env } from "../../src/env"
import { provideTmpdirInstance } from "../fixture/fixture" import { disposeAllInstances, provideTmpdirInstance } from "../fixture/fixture"
import { tmpdir } from "../fixture/fixture" import { tmpdir } from "../fixture/fixture"
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
import { testEffect } from "../lib/effect" import { testEffect } from "../lib/effect"
@ -108,7 +108,7 @@ async function check(map: (dir: string) => string) {
}, },
}) })
} finally { } finally {
await Instance.disposeAll() await disposeAllInstances()
;(Global.Path as { config: string }).config = prev ;(Global.Path as { config: string }).config = prev
await clear() await clear()
} }

View file

@ -21,7 +21,7 @@ import { ModelID, ProviderID } from "@/provider/schema"
import { SyncEvent } from "@/sync" import { SyncEvent } from "@/sync"
import { EventSequenceTable, EventTable } from "@/sync/event.sql" import { EventSequenceTable, EventTable } from "@/sync/event.sql"
import { resetDatabase } from "../fixture/db" import { resetDatabase } from "../fixture/db"
import { provideTmpdirInstance, tmpdir } from "../fixture/fixture" import { disposeAllInstances, provideTmpdirInstance, tmpdir } from "../fixture/fixture"
import { testEffect } from "../lib/effect" import { testEffect } from "../lib/effect"
import { registerAdapter } from "../../src/control-plane/adapters" import { registerAdapter } from "../../src/control-plane/adapters"
import { WorkspaceID } from "../../src/control-plane/schema" import { WorkspaceID } from "../../src/control-plane/schema"
@ -93,7 +93,7 @@ beforeEach(() => {
afterEach(async () => { afterEach(async () => {
mock.restore() mock.restore()
await Instance.disposeAll() await disposeAllInstances()
Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = originalWorkspacesFlag Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = originalWorkspacesFlag
restoreEnv() restoreEnv()
await resetDatabase() await resetDatabase()

View file

@ -4,7 +4,7 @@ import { $ } from "bun"
import { Context, Deferred, Duration, Effect, Exit, Fiber, Layer } from "effect" import { Context, Deferred, Duration, Effect, Exit, Fiber, Layer } from "effect"
import { InstanceState } from "@/effect/instance-state" import { InstanceState } from "@/effect/instance-state"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { provideInstance, tmpdirScoped } from "../fixture/fixture" import { disposeAllInstances, provideInstance, tmpdirScoped } from "../fixture/fixture"
import { testEffect } from "../lib/effect" import { testEffect } from "../lib/effect"
const it = testEffect(CrossSpawnSpawner.defaultLayer) const it = testEffect(CrossSpawnSpawner.defaultLayer)
@ -19,7 +19,7 @@ const tmpdirGitScoped = Effect.gen(function* () {
}) })
afterEach(async () => { afterEach(async () => {
await Instance.disposeAll() await disposeAllInstances()
}) })
it.live("InstanceState caches values per directory", () => it.live("InstanceState caches values per directory", () =>
@ -94,7 +94,7 @@ it.live("InstanceState invalidates on disposeAll", () =>
yield* access(state, one) yield* access(state, one)
yield* access(state, two) yield* access(state, two)
yield* Effect.promise(() => Instance.disposeAll()) yield* Effect.promise(disposeAllInstances)
expect(seen.sort()).toEqual([one, two].sort()) expect(seen.sort()).toEqual([one, two].sort())
}), }),

View file

@ -6,10 +6,10 @@ import fs from "fs/promises"
import { File } from "../../src/file" import { File } from "../../src/file"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { Filesystem } from "@/util/filesystem" import { Filesystem } from "@/util/filesystem"
import { provideInstance, tmpdir } from "../fixture/fixture" import { disposeAllInstances, provideInstance, tmpdir } from "../fixture/fixture"
afterEach(async () => { afterEach(async () => {
await Instance.disposeAll() await disposeAllInstances()
}) })
const init = () => run(File.Service.use((svc) => svc.init())) const init = () => run(File.Service.use((svc) => svc.init()))
@ -936,7 +936,7 @@ describe("file/index Filesystem patterns", () => {
}, },
}) })
await Instance.disposeAll() await disposeAllInstances()
await fs.writeFile(path.join(tmp.path, "after.ts"), "after", "utf-8") await fs.writeFile(path.join(tmp.path, "after.ts"), "after", "utf-8")
await fs.rm(path.join(tmp.path, "before.ts")) await fs.rm(path.join(tmp.path, "before.ts"))

View file

@ -3,7 +3,7 @@ import { afterEach, describe, expect, test } from "bun:test"
import fs from "fs/promises" import fs from "fs/promises"
import path from "path" import path from "path"
import { ConfigProvider, Deferred, Effect, Layer, ManagedRuntime, Option } from "effect" import { ConfigProvider, Deferred, Effect, Layer, ManagedRuntime, Option } from "effect"
import { tmpdir } from "../fixture/fixture" import { disposeAllInstances, tmpdir } from "../fixture/fixture"
import { Bus } from "../../src/bus" import { Bus } from "../../src/bus"
import { Config } from "@/config/config" import { Config } from "@/config/config"
import { FileWatcher } from "../../src/file/watcher" import { FileWatcher } from "../../src/file/watcher"
@ -147,7 +147,7 @@ function ready(directory: string) {
describeWatcher("FileWatcher", () => { describeWatcher("FileWatcher", () => {
afterEach(async () => { afterEach(async () => {
await Instance.disposeAll() await disposeAllInstances()
}) })
test("publishes root create, update, and delete events", async () => { test("publishes root create, update, and delete events", async () => {

View file

@ -1,9 +1,9 @@
import { rm } from "fs/promises" import { rm } from "fs/promises"
import { Instance } from "../../src/project/instance"
import { Database } from "@/storage/db" import { Database } from "@/storage/db"
import { disposeAllInstances } from "./fixture"
export async function resetDatabase() { export async function resetDatabase() {
await Instance.disposeAll().catch(() => undefined) await disposeAllInstances().catch(() => undefined)
Database.close() Database.close()
await rm(Database.Path, { force: true }).catch(() => undefined) await rm(Database.Path, { force: true }).catch(() => undefined)
await rm(`${Database.Path}-wal`, { force: true }).catch(() => undefined) await rm(`${Database.Path}-wal`, { force: true }).catch(() => undefined)

View file

@ -9,8 +9,16 @@ import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
import type { Config } from "@/config/config" import type { Config } from "@/config/config"
import { InstanceRef } from "../../src/effect/instance-ref" import { InstanceRef } from "../../src/effect/instance-ref"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { InstanceStore } from "../../src/project/instance-store"
import { TestLLMServer } from "../lib/llm-server" import { TestLLMServer } from "../lib/llm-server"
// Test helper for tearing down all loaded instances. Used in afterEach hooks.
// Replaces direct Instance.disposeAll() calls so the legacy promise method can be removed.
// IMPORTANT: must use InstanceStore.runtime, not AppRuntime or a test-layer Service —
// Instance.provide loads instances into InstanceStore.runtime's Service cache, and that
// Service is built per-runtime (not shared via memoMap across Effect.runPromise boundaries).
export const disposeAllInstances = () => InstanceStore.runtime.runPromise((s) => s.disposeAll())
// Strip null bytes from paths (defensive fix for CI environment issues) // Strip null bytes from paths (defensive fix for CI environment issues)
function sanitizePath(p: string): string { function sanitizePath(p: string): string {
return p.replace(/\0/g, "") return p.replace(/\0/g, "")

View file

@ -2,13 +2,13 @@ import { afterEach, describe, test, expect } from "bun:test"
import { Permission } from "../src/permission" import { Permission } from "../src/permission"
import { Config } from "@/config/config" import { Config } from "@/config/config"
import { Instance } from "../src/project/instance" import { Instance } from "../src/project/instance"
import { tmpdir } from "./fixture/fixture" import { disposeAllInstances, tmpdir } from "./fixture/fixture"
import { AppRuntime } from "../src/effect/app-runtime" import { AppRuntime } from "../src/effect/app-runtime"
const load = () => AppRuntime.runPromise(Config.Service.use((svc) => svc.get())) const load = () => AppRuntime.runPromise(Config.Service.use((svc) => svc.get()))
afterEach(async () => { afterEach(async () => {
await Instance.disposeAll() await disposeAllInstances()
}) })
describe("Permission.evaluate for permission.task", () => { describe("Permission.evaluate for permission.task", () => {

View file

@ -6,7 +6,7 @@ import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
import { Permission } from "../../src/permission" import { Permission } from "../../src/permission"
import { PermissionID } from "../../src/permission/schema" import { PermissionID } from "../../src/permission/schema"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { provideInstance, provideTmpdirInstance, tmpdirScoped } from "../fixture/fixture" import { disposeAllInstances, provideInstance, provideTmpdirInstance, tmpdirScoped } from "../fixture/fixture"
import { testEffect } from "../lib/effect" import { testEffect } from "../lib/effect"
import { MessageID, SessionID } from "../../src/session/schema" import { MessageID, SessionID } from "../../src/session/schema"
@ -15,7 +15,7 @@ const env = Layer.mergeAll(Permission.layer.pipe(Layer.provide(bus)), bus, Cross
const it = testEffect(env) const it = testEffect(env)
afterEach(async () => { afterEach(async () => {
await Instance.disposeAll() await disposeAllInstances()
}) })
const rejectAll = (message?: string) => const rejectAll = (message?: string) =>

View file

@ -3,7 +3,7 @@ import { Effect } from "effect"
import fs from "fs/promises" import fs from "fs/promises"
import path from "path" import path from "path"
import { pathToFileURL } from "url" import { pathToFileURL } from "url"
import { tmpdir } from "../fixture/fixture" import { disposeAllInstances, tmpdir } from "../fixture/fixture"
import { Filesystem } from "@/util/filesystem" import { Filesystem } from "@/util/filesystem"
const disableDefault = process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS const disableDefault = process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS
@ -24,7 +24,7 @@ afterAll(() => {
}) })
afterEach(async () => { afterEach(async () => {
await Instance.disposeAll() await disposeAllInstances()
}) })
async function load(dir: string) { async function load(dir: string) {

View file

@ -3,7 +3,7 @@ import { Effect, Layer } from "effect"
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
import path from "path" import path from "path"
import { pathToFileURL } from "url" import { pathToFileURL } from "url"
import { provideTmpdirInstance } from "../fixture/fixture" import { disposeAllInstances, provideTmpdirInstance } from "../fixture/fixture"
import { testEffect } from "../lib/effect" import { testEffect } from "../lib/effect"
const disableDefault = process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS const disableDefault = process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS
@ -20,7 +20,7 @@ const experimental = Flag.OPENCODE_EXPERIMENTAL_WORKSPACES
Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = true Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = true
afterEach(async () => { afterEach(async () => {
await Instance.disposeAll() await disposeAllInstances()
}) })
afterAll(() => { afterAll(() => {

View file

@ -5,13 +5,13 @@ import { InstanceRef } from "../../src/effect/instance-ref"
import { registerDisposer } from "../../src/effect/instance-registry" import { registerDisposer } from "../../src/effect/instance-registry"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { InstanceStore } from "../../src/project/instance-store" import { InstanceStore } from "../../src/project/instance-store"
import { tmpdirScoped } from "../fixture/fixture" import { disposeAllInstances, tmpdirScoped } from "../fixture/fixture"
import { testEffect } from "../lib/effect" import { testEffect } from "../lib/effect"
const it = testEffect(Layer.mergeAll(InstanceStore.defaultLayer, CrossSpawnSpawner.defaultLayer)) const it = testEffect(Layer.mergeAll(InstanceStore.defaultLayer, CrossSpawnSpawner.defaultLayer))
afterEach(async () => { afterEach(async () => {
await Instance.disposeAll() await disposeAllInstances()
}) })
describe("InstanceStore", () => { describe("InstanceStore", () => {

View file

@ -3,7 +3,7 @@ import { afterEach, describe, expect, test } from "bun:test"
import { Effect } from "effect" import { Effect } from "effect"
import fs from "fs/promises" import fs from "fs/promises"
import path from "path" import path from "path"
import { tmpdir } from "../fixture/fixture" import { disposeAllInstances, tmpdir } from "../fixture/fixture"
import { AppRuntime } from "../../src/effect/app-runtime" import { AppRuntime } from "../../src/effect/app-runtime"
import { FileWatcher } from "../../src/file/watcher" import { FileWatcher } from "../../src/file/watcher"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
@ -85,7 +85,7 @@ function nextBranchUpdate(directory: string, timeout = 10_000) {
describeVcs("Vcs", () => { describeVcs("Vcs", () => {
afterEach(async () => { afterEach(async () => {
await Instance.disposeAll() await disposeAllInstances()
}) })
test("branch() returns current branch name", async () => { test("branch() returns current branch name", async () => {
@ -158,7 +158,7 @@ describeVcs("Vcs", () => {
describe("Vcs diff", () => { describe("Vcs diff", () => {
afterEach(async () => { afterEach(async () => {
await Instance.disposeAll() await disposeAllInstances()
}) })
test("defaultBranch() falls back to main", async () => { test("defaultBranch() falls back to main", async () => {

View file

@ -6,7 +6,7 @@ import { Cause, Effect, Exit, Layer } from "effect"
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { Worktree } from "../../src/worktree" import { Worktree } from "../../src/worktree"
import { provideInstance, provideTmpdirInstance } from "../fixture/fixture" import { disposeAllInstances, provideInstance, provideTmpdirInstance } from "../fixture/fixture"
import { testEffect } from "../lib/effect" import { testEffect } from "../lib/effect"
const it = testEffect(Layer.mergeAll(Worktree.defaultLayer, CrossSpawnSpawner.defaultLayer)) const it = testEffect(Layer.mergeAll(Worktree.defaultLayer, CrossSpawnSpawner.defaultLayer))
@ -37,7 +37,7 @@ async function waitReady() {
} }
describe("Worktree", () => { describe("Worktree", () => {
afterEach(() => Instance.disposeAll()) afterEach(() => disposeAllInstances())
describe("makeWorktreeInfo", () => { describe("makeWorktreeInfo", () => {
it.live("returns info with name, branch, and directory", () => it.live("returns info with name, branch, and directory", () =>

View file

@ -2,7 +2,7 @@ import { test, expect } from "bun:test"
import { mkdir, unlink } from "fs/promises" import { mkdir, unlink } from "fs/promises"
import path from "path" import path from "path"
import { tmpdir } from "../fixture/fixture" import { disposeAllInstances, tmpdir } from "../fixture/fixture"
import { Global } from "@opencode-ai/core/global" import { Global } from "@opencode-ai/core/global"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { Plugin } from "../../src/plugin/index" import { Plugin } from "../../src/plugin/index"
@ -2557,7 +2557,7 @@ test("plugin config providers persist after instance dispose", async () => {
expect(first[ProviderID.make("demo")]).toBeDefined() expect(first[ProviderID.make("demo")]).toBeDefined()
expect(first[ProviderID.make("demo")].models[ModelID.make("chat")]).toBeDefined() expect(first[ProviderID.make("demo")].models[ModelID.make("chat")]).toBeDefined()
await Instance.disposeAll() await disposeAllInstances()
const second = await Instance.provide({ const second = await Instance.provide({
directory: tmp.path, directory: tmp.path,

View file

@ -2,7 +2,7 @@ import { afterEach, test, expect } from "bun:test"
import { Question } from "../../src/question" import { Question } from "../../src/question"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { QuestionID } from "../../src/question/schema" import { QuestionID } from "../../src/question/schema"
import { tmpdir } from "../fixture/fixture" import { disposeAllInstances, tmpdir } from "../fixture/fixture"
import { SessionID } from "../../src/session/schema" import { SessionID } from "../../src/session/schema"
import { AppRuntime } from "../../src/effect/app-runtime" import { AppRuntime } from "../../src/effect/app-runtime"
@ -17,7 +17,7 @@ const reply = (input: { requestID: QuestionID; answers: ReadonlyArray<Question.A
const reject = (id: QuestionID) => AppRuntime.runPromise(Question.Service.use((svc) => svc.reject(id))) const reject = (id: QuestionID) => AppRuntime.runPromise(Question.Service.use((svc) => svc.reject(id)))
afterEach(async () => { afterEach(async () => {
await Instance.disposeAll() await disposeAllInstances()
}) })
/** Reject all pending questions so dangling Deferred fibers don't hang the test. */ /** Reject all pending questions so dangling Deferred fibers don't hang the test. */

View file

@ -12,7 +12,7 @@ import { ConfigProvider, Layer } from "effect"
import { HttpRouter } from "effect/unstable/http" import { HttpRouter } from "effect/unstable/http"
import { OpenApi } from "effect/unstable/httpapi" import { OpenApi } from "effect/unstable/httpapi"
import { resetDatabase } from "../fixture/db" import { resetDatabase } from "../fixture/db"
import { tmpdir } from "../fixture/fixture" import { disposeAllInstances, tmpdir } from "../fixture/fixture"
void Log.init({ print: false }) void Log.init({ print: false })
@ -208,7 +208,7 @@ afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original.OPENCODE_EXPERIMENTAL_HTTPAPI Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original.OPENCODE_EXPERIMENTAL_HTTPAPI
Flag.OPENCODE_SERVER_PASSWORD = original.OPENCODE_SERVER_PASSWORD Flag.OPENCODE_SERVER_PASSWORD = original.OPENCODE_SERVER_PASSWORD
Flag.OPENCODE_SERVER_USERNAME = original.OPENCODE_SERVER_USERNAME Flag.OPENCODE_SERVER_USERNAME = original.OPENCODE_SERVER_USERNAME
await Instance.disposeAll() await disposeAllInstances()
await resetDatabase() await resetDatabase()
}) })

View file

@ -6,7 +6,7 @@ import { Instance } from "../../src/project/instance"
import { Server } from "../../src/server/server" import { Server } from "../../src/server/server"
import * as Log from "@opencode-ai/core/util/log" import * as Log from "@opencode-ai/core/util/log"
import { resetDatabase } from "../fixture/db" import { resetDatabase } from "../fixture/db"
import { tmpdir } from "../fixture/fixture" import { disposeAllInstances, tmpdir } from "../fixture/fixture"
void Log.init({ print: false }) void Log.init({ print: false })
@ -37,7 +37,7 @@ async function waitDisposed(directory: string) {
afterEach(async () => { afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original
await Instance.disposeAll() await disposeAllInstances()
await resetDatabase() await resetDatabase()
}) })

View file

@ -5,7 +5,7 @@ import { Server } from "../../src/server/server"
import { EventPaths } from "../../src/server/routes/instance/httpapi/event" import { EventPaths } from "../../src/server/routes/instance/httpapi/event"
import * as Log from "@opencode-ai/core/util/log" import * as Log from "@opencode-ai/core/util/log"
import { resetDatabase } from "../fixture/db" import { resetDatabase } from "../fixture/db"
import { tmpdir } from "../fixture/fixture" import { disposeAllInstances, tmpdir } from "../fixture/fixture"
void Log.init({ print: false }) void Log.init({ print: false })
@ -29,7 +29,7 @@ async function readFirstChunk(response: Response) {
afterEach(async () => { afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original
await Instance.disposeAll() await disposeAllInstances()
await resetDatabase() await resetDatabase()
}) })

View file

@ -10,7 +10,7 @@ import { Database } from "@/storage/db"
import * as Log from "@opencode-ai/core/util/log" import * as Log from "@opencode-ai/core/util/log"
import { Worktree } from "../../src/worktree" import { Worktree } from "../../src/worktree"
import { resetDatabase } from "../fixture/db" import { resetDatabase } from "../fixture/db"
import { tmpdir } from "../fixture/fixture" import { disposeAllInstances, tmpdir } from "../fixture/fixture"
void Log.init({ print: false }) void Log.init({ print: false })
@ -50,7 +50,7 @@ async function waitReady(directory: string) {
afterEach(async () => { afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original
await Instance.disposeAll() await disposeAllInstances()
await resetDatabase() await resetDatabase()
}) })

View file

@ -6,7 +6,7 @@ import { FilePaths } from "../../src/server/routes/instance/httpapi/groups/file"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import * as Log from "@opencode-ai/core/util/log" import * as Log from "@opencode-ai/core/util/log"
import { resetDatabase } from "../fixture/db" import { resetDatabase } from "../fixture/db"
import { tmpdir } from "../fixture/fixture" import { disposeAllInstances, tmpdir } from "../fixture/fixture"
void Log.init({ print: false }) void Log.init({ print: false })
@ -28,7 +28,7 @@ function request(route: string, directory: string, query?: Record<string, string
} }
afterEach(async () => { afterEach(async () => {
await Instance.disposeAll() await disposeAllInstances()
await resetDatabase() await resetDatabase()
}) })

View file

@ -19,7 +19,7 @@ import { disposeMiddleware, markInstanceForDisposal } from "../../src/server/rou
import { instanceRouterMiddleware } from "../../src/server/routes/instance/httpapi/middleware/instance-context" import { instanceRouterMiddleware } from "../../src/server/routes/instance/httpapi/middleware/instance-context"
import { workspaceRouterMiddleware } from "../../src/server/routes/instance/httpapi/middleware/workspace-routing" import { workspaceRouterMiddleware } from "../../src/server/routes/instance/httpapi/middleware/workspace-routing"
import { resetDatabase } from "../fixture/db" import { resetDatabase } from "../fixture/db"
import { tmpdirScoped } from "../fixture/fixture" import { disposeAllInstances, tmpdirScoped } from "../fixture/fixture"
import { testEffect } from "../lib/effect" import { testEffect } from "../lib/effect"
const testStateLayer = Layer.effectDiscard( const testStateLayer = Layer.effectDiscard(
@ -30,7 +30,7 @@ const testStateLayer = Layer.effectDiscard(
yield* Effect.addFinalizer(() => yield* Effect.addFinalizer(() =>
Effect.promise(async () => { Effect.promise(async () => {
Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = originalWorkspaces Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = originalWorkspaces
await Instance.disposeAll() await disposeAllInstances()
await resetDatabase() await resetDatabase()
}), }),
) )

View file

@ -6,7 +6,7 @@ import { Server } from "../../src/server/server"
import { InstancePaths } from "../../src/server/routes/instance/httpapi/groups/instance" import { InstancePaths } from "../../src/server/routes/instance/httpapi/groups/instance"
import * as Log from "@opencode-ai/core/util/log" import * as Log from "@opencode-ai/core/util/log"
import { resetDatabase } from "../fixture/db" import { resetDatabase } from "../fixture/db"
import { tmpdir } from "../fixture/fixture" import { disposeAllInstances, tmpdir } from "../fixture/fixture"
void Log.init({ print: false }) void Log.init({ print: false })
@ -37,7 +37,7 @@ async function waitDisposed(directory: string) {
afterEach(async () => { afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original
await Instance.disposeAll() await disposeAllInstances()
await resetDatabase() await resetDatabase()
}) })

View file

@ -7,13 +7,13 @@ import * as Socket from "effect/unstable/socket/Socket"
import { InstancePaths } from "../../src/server/routes/instance/httpapi/groups/instance" import { InstancePaths } from "../../src/server/routes/instance/httpapi/groups/instance"
import { ExperimentalHttpApiServer } from "../../src/server/routes/instance/httpapi/server" import { ExperimentalHttpApiServer } from "../../src/server/routes/instance/httpapi/server"
import { resetDatabase } from "../fixture/db" import { resetDatabase } from "../fixture/db"
import { tmpdirScoped } from "../fixture/fixture" import { disposeAllInstances, tmpdirScoped } from "../fixture/fixture"
import { testEffect } from "../lib/effect" import { testEffect } from "../lib/effect"
// Flip the experimental HttpApi flag so backend selection telemetry on the // Flip the experimental HttpApi flag so backend selection telemetry on the
// production routes reports the right backend, and reset the database around // production routes reports the right backend, and reset the database around
// the test so per-instance state does not leak between runs. resetDatabase() // the test so per-instance state does not leak between runs. resetDatabase()
// already calls Instance.disposeAll(), so we don't repeat it. // already calls disposeAllInstances(), so we don't repeat it.
const testStateLayer = Layer.effectDiscard( const testStateLayer = Layer.effectDiscard(
Effect.gen(function* () { Effect.gen(function* () {
const originalHttpApi = Flag.OPENCODE_EXPERIMENTAL_HTTPAPI const originalHttpApi = Flag.OPENCODE_EXPERIMENTAL_HTTPAPI

View file

@ -15,7 +15,7 @@ import { MessageID, PartID } from "../../src/session/schema"
import { Session } from "@/session/session" import { Session } from "@/session/session"
import * as Log from "@opencode-ai/core/util/log" import * as Log from "@opencode-ai/core/util/log"
import { resetDatabase } from "../fixture/db" import { resetDatabase } from "../fixture/db"
import { provideInstance, tmpdir } from "../fixture/fixture" import { disposeAllInstances, provideInstance, tmpdir } from "../fixture/fixture"
import { it } from "../lib/effect" import { it } from "../lib/effect"
void Log.init({ print: false }) void Log.init({ print: false })
@ -89,7 +89,7 @@ function expectJsonParity(input: {
afterEach(async () => { afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original
await Instance.disposeAll() await disposeAllInstances()
await resetDatabase() await resetDatabase()
}) })

View file

@ -8,7 +8,7 @@ import { Instance } from "../../src/project/instance"
import { Server } from "../../src/server/server" import { Server } from "../../src/server/server"
import * as Log from "@opencode-ai/core/util/log" import * as Log from "@opencode-ai/core/util/log"
import { resetDatabase } from "../fixture/db" import { resetDatabase } from "../fixture/db"
import { provideInstance, tmpdir } from "../fixture/fixture" import { disposeAllInstances, provideInstance, tmpdir } from "../fixture/fixture"
import { testEffect } from "../lib/effect" import { testEffect } from "../lib/effect"
void Log.init({ print: false }) void Log.init({ print: false })
@ -76,7 +76,7 @@ const readResponse = Effect.fnUntraced(function* (input: { app: TestApp; path: s
afterEach(async () => { afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original
await Instance.disposeAll() await disposeAllInstances()
await resetDatabase() await resetDatabase()
}) })

View file

@ -6,7 +6,7 @@ import { Instance } from "../../src/project/instance"
import { Server } from "../../src/server/server" import { Server } from "../../src/server/server"
import * as Log from "@opencode-ai/core/util/log" import * as Log from "@opencode-ai/core/util/log"
import { resetDatabase } from "../fixture/db" import { resetDatabase } from "../fixture/db"
import { provideInstance } from "../fixture/fixture" import { disposeAllInstances, provideInstance } from "../fixture/fixture"
import { testEffect } from "../lib/effect" import { testEffect } from "../lib/effect"
void Log.init({ print: false }) void Log.init({ print: false })
@ -98,7 +98,7 @@ function withProviderProject<A, E, R>(self: (dir: string) => Effect.Effect<A, E,
afterEach(async () => { afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original
await Instance.disposeAll() await disposeAllInstances()
await resetDatabase() await resetDatabase()
}) })

View file

@ -7,7 +7,7 @@ import { Server } from "../../src/server/server"
import { PtyPaths } from "../../src/server/routes/instance/httpapi/groups/pty" import { PtyPaths } from "../../src/server/routes/instance/httpapi/groups/pty"
import * as Log from "@opencode-ai/core/util/log" import * as Log from "@opencode-ai/core/util/log"
import { resetDatabase } from "../fixture/db" import { resetDatabase } from "../fixture/db"
import { tmpdir, tmpdirScoped } from "../fixture/fixture" import { disposeAllInstances, tmpdir, tmpdirScoped } from "../fixture/fixture"
import { Config, Effect, Layer, Queue, Schema } from "effect" import { Config, Effect, Layer, Queue, Schema } from "effect"
import { HttpClient, HttpClientRequest, HttpRouter, HttpServer } from "effect/unstable/http" import { HttpClient, HttpClientRequest, HttpRouter, HttpServer } from "effect/unstable/http"
import * as Socket from "effect/unstable/socket/Socket" import * as Socket from "effect/unstable/socket/Socket"
@ -63,7 +63,7 @@ const directoryHeader = (dir: string) => HttpClientRequest.setHeader("x-opencode
afterEach(async () => { afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original
await Instance.disposeAll() await disposeAllInstances()
await resetDatabase() await resetDatabase()
}) })

View file

@ -8,7 +8,7 @@ import { PtyPaths } from "../../src/server/routes/instance/httpapi/groups/pty"
import { ExperimentalHttpApiServer } from "../../src/server/routes/instance/httpapi/server" import { ExperimentalHttpApiServer } from "../../src/server/routes/instance/httpapi/server"
import { PtyID } from "../../src/pty/schema" import { PtyID } from "../../src/pty/schema"
import { resetDatabase } from "../fixture/db" import { resetDatabase } from "../fixture/db"
import { tmpdir } from "../fixture/fixture" import { disposeAllInstances, tmpdir } from "../fixture/fixture"
import * as Log from "@opencode-ai/core/util/log" import * as Log from "@opencode-ai/core/util/log"
void Log.init({ print: false }) void Log.init({ print: false })
@ -49,7 +49,7 @@ async function cancelBody(response: Response) {
afterEach(async () => { afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = originalHttpApi Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = originalHttpApi
await Instance.disposeAll() await disposeAllInstances()
await resetDatabase() await resetDatabase()
}) })

View file

@ -15,7 +15,7 @@ import { Session as SessionNs } from "@/session/session"
import { TestLLMServer } from "../lib/llm-server" import { TestLLMServer } from "../lib/llm-server"
import path from "path" import path from "path"
import { resetDatabase } from "../fixture/db" import { resetDatabase } from "../fixture/db"
import { tmpdir } from "../fixture/fixture" import { disposeAllInstances, tmpdir } from "../fixture/fixture"
import { it } from "../lib/effect" import { it } from "../lib/effect"
const original = { const original = {
@ -169,7 +169,7 @@ function sessionTitles(value: unknown) {
function resetState() { function resetState() {
return Effect.promise(async () => { return Effect.promise(async () => {
await Instance.disposeAll() await disposeAllInstances()
await resetDatabase() await resetDatabase()
}) })
} }
@ -260,7 +260,7 @@ afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original.OPENCODE_EXPERIMENTAL_HTTPAPI Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original.OPENCODE_EXPERIMENTAL_HTTPAPI
Flag.OPENCODE_SERVER_PASSWORD = original.OPENCODE_SERVER_PASSWORD Flag.OPENCODE_SERVER_PASSWORD = original.OPENCODE_SERVER_PASSWORD
Flag.OPENCODE_SERVER_USERNAME = original.OPENCODE_SERVER_USERNAME Flag.OPENCODE_SERVER_USERNAME = original.OPENCODE_SERVER_USERNAME
await Instance.disposeAll() await disposeAllInstances()
await resetDatabase() await resetDatabase()
}) })

View file

@ -20,7 +20,7 @@ import { SessionTable } from "@/session/session.sql"
import * as Log from "@opencode-ai/core/util/log" import * as Log from "@opencode-ai/core/util/log"
import { eq } from "drizzle-orm" import { eq } from "drizzle-orm"
import { resetDatabase } from "../fixture/db" import { resetDatabase } from "../fixture/db"
import { tmpdir } from "../fixture/fixture" import { disposeAllInstances, tmpdir } from "../fixture/fixture"
import { it } from "../lib/effect" import { it } from "../lib/effect"
void Log.init({ print: false }) void Log.init({ print: false })
@ -138,7 +138,7 @@ function withTmp<A, E, R>(
afterEach(async () => { afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original
Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = originalWorkspaces Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = originalWorkspaces
await Instance.disposeAll() await disposeAllInstances()
await resetDatabase() await resetDatabase()
}) })

View file

@ -7,7 +7,7 @@ import { SyncPaths } from "../../src/server/routes/instance/httpapi/groups/sync"
import { Session } from "@/session/session" import { Session } from "@/session/session"
import * as Log from "@opencode-ai/core/util/log" import * as Log from "@opencode-ai/core/util/log"
import { resetDatabase } from "../fixture/db" import { resetDatabase } from "../fixture/db"
import { tmpdir } from "../fixture/fixture" import { disposeAllInstances, tmpdir } from "../fixture/fixture"
void Log.init({ print: false }) void Log.init({ print: false })
@ -27,7 +27,7 @@ afterEach(async () => {
mock.restore() mock.restore()
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = originalHttpApi Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = originalHttpApi
Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = originalWorkspaces Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = originalWorkspaces
await Instance.disposeAll() await disposeAllInstances()
await resetDatabase() await resetDatabase()
}) })

View file

@ -11,7 +11,7 @@ import { Server } from "../../src/server/server"
import * as Log from "@opencode-ai/core/util/log" import * as Log from "@opencode-ai/core/util/log"
import { OpenApi } from "effect/unstable/httpapi" import { OpenApi } from "effect/unstable/httpapi"
import { resetDatabase } from "../fixture/db" import { resetDatabase } from "../fixture/db"
import { tmpdir } from "../fixture/fixture" import { disposeAllInstances, tmpdir } from "../fixture/fixture"
void Log.init({ print: false }) void Log.init({ print: false })
@ -45,7 +45,7 @@ async function expectTrue(path: string, headers: Record<string, string>, body?:
afterEach(async () => { afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original
await Instance.disposeAll() await disposeAllInstances()
await resetDatabase() await resetDatabase()
}) })

View file

@ -12,7 +12,7 @@ import { Session } from "@/session/session"
import * as Log from "@opencode-ai/core/util/log" import * as Log from "@opencode-ai/core/util/log"
import { Server } from "../../src/server/server" import { Server } from "../../src/server/server"
import { resetDatabase } from "../fixture/db" import { resetDatabase } from "../fixture/db"
import { provideInstance, tmpdirScoped } from "../fixture/fixture" import { disposeAllInstances, provideInstance, tmpdirScoped } from "../fixture/fixture"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { Project } from "../../src/project/project" import { Project } from "../../src/project/project"
import { InstancePaths } from "../../src/server/routes/instance/httpapi/groups/instance" import { InstancePaths } from "../../src/server/routes/instance/httpapi/groups/instance"
@ -128,7 +128,7 @@ afterEach(async () => {
mock.restore() mock.restore()
Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = originalWorkspaces Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = originalWorkspaces
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = originalHttpApi Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = originalHttpApi
await Instance.disposeAll() await disposeAllInstances()
await resetDatabase() await resetDatabase()
}) })

View file

@ -8,7 +8,7 @@ import { Server } from "../../src/server/server"
import { Filesystem } from "@/util/filesystem" import { Filesystem } from "@/util/filesystem"
import * as Log from "@opencode-ai/core/util/log" import * as Log from "@opencode-ai/core/util/log"
import { resetDatabase } from "../fixture/db" import { resetDatabase } from "../fixture/db"
import { provideInstance, tmpdir } from "../fixture/fixture" import { disposeAllInstances, provideInstance, tmpdir } from "../fixture/fixture"
void Log.init({ print: false }) void Log.init({ print: false })
@ -69,7 +69,7 @@ describe("project.initGit endpoint", () => {
), ),
).toBeTruthy() ).toBeTruthy()
} finally { } finally {
await Instance.disposeAll() await disposeAllInstances()
reloadSpy.mockRestore() reloadSpy.mockRestore()
GlobalBus.off("event", fn) GlobalBus.off("event", fn)
} }
@ -114,7 +114,7 @@ describe("project.initGit endpoint", () => {
worktree: tmp.path, worktree: tmp.path,
}) })
} finally { } finally {
await Instance.disposeAll() await disposeAllInstances()
reloadSpy.mockRestore() reloadSpy.mockRestore()
GlobalBus.off("event", fn) GlobalBus.off("event", fn)
} }

View file

@ -5,7 +5,7 @@ import { Server } from "../../src/server/server"
import { Session as SessionNs } from "@/session/session" import { Session as SessionNs } from "@/session/session"
import type { SessionID } from "../../src/session/schema" import type { SessionID } from "../../src/session/schema"
import * as Log from "@opencode-ai/core/util/log" import * as Log from "@opencode-ai/core/util/log"
import { tmpdir } from "../fixture/fixture" import { disposeAllInstances, tmpdir } from "../fixture/fixture"
void Log.init({ print: false }) void Log.init({ print: false })
@ -25,7 +25,7 @@ const svc = {
afterEach(async () => { afterEach(async () => {
mock.restore() mock.restore()
await Instance.disposeAll() await disposeAllInstances()
}) })
describe("session action routes", () => { describe("session action routes", () => {

View file

@ -3,7 +3,7 @@ import { Effect } from "effect"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { Session as SessionNs } from "@/session/session" import { Session as SessionNs } from "@/session/session"
import * as Log from "@opencode-ai/core/util/log" import * as Log from "@opencode-ai/core/util/log"
import { tmpdir } from "../fixture/fixture" import { disposeAllInstances, tmpdir } from "../fixture/fixture"
import { Flag } from "@opencode-ai/core/flag/flag" import { Flag } from "@opencode-ai/core/flag/flag"
import { mkdir } from "fs/promises" import { mkdir } from "fs/promises"
import path from "path" import path from "path"
@ -30,7 +30,7 @@ const svc = {
afterEach(async () => { afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = originalWorkspaces Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = originalWorkspaces
await Instance.disposeAll() await disposeAllInstances()
}) })
describe("session.list", () => { describe("session.list", () => {

View file

@ -6,7 +6,7 @@ import { Session as SessionNs } from "@/session/session"
import { MessageV2 } from "../../src/session/message-v2" import { MessageV2 } from "../../src/session/message-v2"
import { MessageID, PartID, type SessionID } from "../../src/session/schema" import { MessageID, PartID, type SessionID } from "../../src/session/schema"
import * as Log from "@opencode-ai/core/util/log" import * as Log from "@opencode-ai/core/util/log"
import { tmpdir } from "../fixture/fixture" import { disposeAllInstances, tmpdir } from "../fixture/fixture"
void Log.init({ print: false }) void Log.init({ print: false })
@ -31,7 +31,7 @@ const svc = {
} }
afterEach(async () => { afterEach(async () => {
await Instance.disposeAll() await disposeAllInstances()
}) })
async function withoutWatcher<T>(fn: () => Promise<T>) { async function withoutWatcher<T>(fn: () => Promise<T>) {

View file

@ -5,7 +5,7 @@ import type { SessionID } from "../../src/session/schema"
import * as Log from "@opencode-ai/core/util/log" import * as Log from "@opencode-ai/core/util/log"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { Server } from "../../src/server/server" import { Server } from "../../src/server/server"
import { tmpdir } from "../fixture/fixture" import { disposeAllInstances, tmpdir } from "../fixture/fixture"
void Log.init({ print: false }) void Log.init({ print: false })
@ -24,7 +24,7 @@ const svc = {
} }
afterEach(async () => { afterEach(async () => {
await Instance.disposeAll() await disposeAllInstances()
}) })
describe("tui.selectSession endpoint", () => { describe("tui.selectSession endpoint", () => {

View file

@ -6,7 +6,7 @@ import { Effect } from "effect"
import { Snapshot } from "../../src/snapshot" import { Snapshot } from "../../src/snapshot"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { Filesystem } from "@/util/filesystem" import { Filesystem } from "@/util/filesystem"
import { provideInstance, tmpdir } from "../fixture/fixture" import { disposeAllInstances, provideInstance, tmpdir } from "../fixture/fixture"
// Git always outputs /-separated paths internally. Snapshot.patch() joins them // Git always outputs /-separated paths internally. Snapshot.patch() joins them
// with path.join (which produces \ on Windows) then normalizes back to /. // with path.join (which produces \ on Windows) then normalizes back to /.
@ -14,7 +14,7 @@ import { provideInstance, tmpdir } from "../fixture/fixture"
const fwd = (...parts: string[]) => path.join(...parts).replaceAll("\\", "/") const fwd = (...parts: string[]) => path.join(...parts).replaceAll("\\", "/")
afterEach(async () => { afterEach(async () => {
await Instance.disposeAll() await disposeAllInstances()
}) })
async function bootstrap() { async function bootstrap() {

View file

@ -4,7 +4,7 @@ import fs from "fs/promises"
import { Effect, Layer, ManagedRuntime } from "effect" import { Effect, Layer, ManagedRuntime } from "effect"
import { EditTool } from "../../src/tool/edit" import { EditTool } from "../../src/tool/edit"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { tmpdir } from "../fixture/fixture" import { disposeAllInstances, tmpdir } from "../fixture/fixture"
import { LSP } from "@/lsp/lsp" import { LSP } from "@/lsp/lsp"
import { AppFileSystem } from "@opencode-ai/core/filesystem" import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { Format } from "../../src/format" import { Format } from "../../src/format"
@ -26,7 +26,7 @@ const ctx = {
} }
afterEach(async () => { afterEach(async () => {
await Instance.disposeAll() await disposeAllInstances()
}) })
const runtime = ManagedRuntime.make( const runtime = ManagedRuntime.make(

View file

@ -11,11 +11,11 @@ import { MessageID, SessionID } from "../../src/session/schema"
import { Tool } from "@/tool/tool" import { Tool } from "@/tool/tool"
import { Truncate } from "@/tool/truncate" import { Truncate } from "@/tool/truncate"
import { LspTool } from "../../src/tool/lsp" import { LspTool } from "../../src/tool/lsp"
import { provideTmpdirInstance } from "../fixture/fixture" import { disposeAllInstances, provideTmpdirInstance } from "../fixture/fixture"
import { testEffect } from "../lib/effect" import { testEffect } from "../lib/effect"
afterEach(async () => { afterEach(async () => {
await Instance.disposeAll() await disposeAllInstances()
}) })
const ctx = { const ctx = {

View file

@ -13,13 +13,13 @@ import { ReadTool } from "../../src/tool/read"
import { Truncate } from "@/tool/truncate" import { Truncate } from "@/tool/truncate"
import { Tool } from "@/tool/tool" import { Tool } from "@/tool/tool"
import { Filesystem } from "@/util/filesystem" import { Filesystem } from "@/util/filesystem"
import { provideInstance, tmpdirScoped } from "../fixture/fixture" import { disposeAllInstances, provideInstance, tmpdirScoped } from "../fixture/fixture"
import { testEffect } from "../lib/effect" import { testEffect } from "../lib/effect"
const FIXTURES_DIR = path.join(import.meta.dir, "fixtures") const FIXTURES_DIR = path.join(import.meta.dir, "fixtures")
afterEach(async () => { afterEach(async () => {
await Instance.disposeAll() await disposeAllInstances()
}) })
const ctx = { const ctx = {

View file

@ -5,7 +5,7 @@ import { Effect, Layer } from "effect"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
import { ToolRegistry } from "@/tool/registry" import { ToolRegistry } from "@/tool/registry"
import { provideTmpdirInstance } from "../fixture/fixture" import { disposeAllInstances, provideTmpdirInstance } from "../fixture/fixture"
import { testEffect } from "../lib/effect" import { testEffect } from "../lib/effect"
const node = CrossSpawnSpawner.defaultLayer const node = CrossSpawnSpawner.defaultLayer
@ -13,7 +13,7 @@ const node = CrossSpawnSpawner.defaultLayer
const it = testEffect(Layer.mergeAll(ToolRegistry.defaultLayer, node)) const it = testEffect(Layer.mergeAll(ToolRegistry.defaultLayer, node))
afterEach(async () => { afterEach(async () => {
await Instance.disposeAll() await disposeAllInstances()
}) })
describe("tool.registry", () => { describe("tool.registry", () => {

View file

@ -8,7 +8,7 @@ import type { Tool } from "@/tool/tool"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { SkillTool } from "../../src/tool/skill" import { SkillTool } from "../../src/tool/skill"
import { ToolRegistry } from "@/tool/registry" import { ToolRegistry } from "@/tool/registry"
import { provideTmpdirInstance } from "../fixture/fixture" import { disposeAllInstances, provideTmpdirInstance } from "../fixture/fixture"
import { SessionID, MessageID } from "../../src/session/schema" import { SessionID, MessageID } from "../../src/session/schema"
import { testEffect } from "../lib/effect" import { testEffect } from "../lib/effect"
@ -23,7 +23,7 @@ const baseCtx: Omit<Tool.Context, "ask"> = {
} }
afterEach(async () => { afterEach(async () => {
await Instance.disposeAll() await disposeAllInstances()
}) })
const node = CrossSpawnSpawner.defaultLayer const node = CrossSpawnSpawner.defaultLayer

View file

@ -12,11 +12,11 @@ import { ModelID, ProviderID } from "../../src/provider/schema"
import { TaskTool, type TaskPromptOps } from "../../src/tool/task" import { TaskTool, type TaskPromptOps } from "../../src/tool/task"
import { Truncate } from "@/tool/truncate" import { Truncate } from "@/tool/truncate"
import { ToolRegistry } from "@/tool/registry" import { ToolRegistry } from "@/tool/registry"
import { provideTmpdirInstance } from "../fixture/fixture" import { disposeAllInstances, provideTmpdirInstance } from "../fixture/fixture"
import { testEffect } from "../lib/effect" import { testEffect } from "../lib/effect"
afterEach(async () => { afterEach(async () => {
await Instance.disposeAll() await disposeAllInstances()
}) })
const ref = { const ref = {

View file

@ -13,7 +13,7 @@ import { Tool } from "@/tool/tool"
import { Agent } from "../../src/agent/agent" import { Agent } from "../../src/agent/agent"
import { SessionID, MessageID } from "../../src/session/schema" import { SessionID, MessageID } from "../../src/session/schema"
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
import { provideTmpdirInstance } from "../fixture/fixture" import { disposeAllInstances, provideTmpdirInstance } from "../fixture/fixture"
import { testEffect } from "../lib/effect" import { testEffect } from "../lib/effect"
const ctx = { const ctx = {
@ -28,7 +28,7 @@ const ctx = {
} }
afterEach(async () => { afterEach(async () => {
await Instance.disposeAll() await disposeAllInstances()
}) })
const it = testEffect( const it = testEffect(