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
parent 5242a1c6b4
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 { InstanceStore } from "../project/instance-store"
export async function bootstrap<T>(directory: string, cb: () => Promise<T>) {
return Instance.provide({
@ -9,7 +9,7 @@ export async function bootstrap<T>(directory: string, cb: () => Promise<T>) {
const result = await cb()
return result
} 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 * as Log from "@opencode-ai/core/util/log"
import { Instance } from "@/project/instance"
import { InstanceStore } from "@/project/instance-store"
import { Rpc } from "@/util/rpc"
import { upgrade } from "@/cli/upgrade"
import { Config } from "@/config/config"
@ -87,7 +88,7 @@ export const rpc = {
async shutdown() {
Log.Default.info("worker shutting down")
await Instance.disposeAll()
await InstanceStore.runtime.runPromise((s) => s.disposeAll())
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 { Env } from "../env"
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 { existsSync } from "fs"
import { GlobalBus } from "@/bus/global"
@ -736,12 +738,16 @@ export const layer = Layer.effect(
yield* fs
.writeFileString(file, JSON.stringify(mergeDeep(writable(existing), writable(config)), null, 2))
.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) {
yield* invalidateGlobal
const task = Instance.disposeAll()
const task = InstanceStore.runtime
.runPromise((s) => s.disposeAll())
.catch(() => undefined)
.finally(() =>
GlobalBus.emit("event", {

View file

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

View file

@ -6,13 +6,11 @@ export type { InstanceContext } from "./instance-context"
export type { LoadInput } from "./instance-store"
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> {
return context.provide(await Instance.load({ directory: input.directory, init: input.init }), async () =>
input.fn(),
const ctx = await InstanceStore.runtime.runPromise((store) =>
store.load({ directory: input.directory, init: input.init }),
)
return context.provide(ctx, async () => input.fn())
},
get current() {
return context.use()
@ -50,7 +48,4 @@ export const Instance = {
async dispose() {
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 { AppRuntime } from "@/effect/app-runtime"
import { AsyncQueue } from "@/util/queue"
import { Instance } from "../../project/instance"
import { InstanceStore } from "../../project/instance-store"
import { Installation } from "@/installation"
import { InstallationVersion } from "@opencode-ai/core/installation/version"
import * as Log from "@opencode-ai/core/util/log"
@ -200,7 +200,7 @@ export const GlobalRoutes = lazy(() =>
},
}),
async (c) => {
await Instance.disposeAll()
await InstanceStore.runtime.runPromise((s) => s.disposeAll())
GlobalBus.emit("event", {
directory: "global",
payload: {

View file

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

View file

@ -81,11 +81,7 @@ export const ProjectRoutes = lazy(() =>
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)
await Instance.reload({
directory: dir,
worktree: dir,
project: next,
})
await Instance.reload({ directory: dir, worktree: dir, project: next })
return c.json(next)
},
)

View file

@ -1,7 +1,7 @@
import { afterEach, test, expect } from "bun:test"
import { Effect } from "effect"
import path from "path"
import { provideInstance, tmpdir } from "../fixture/fixture"
import { disposeAllInstances, provideInstance, tmpdir } from "../fixture/fixture"
import { Instance } from "../../src/project/instance"
import { Agent } from "../../src/agent/agent"
import { Permission } from "../../src/permission"
@ -18,7 +18,7 @@ function load<A>(dir: string, fn: (svc: Agent.Interface) => Effect.Effect<A>) {
}
afterEach(async () => {
await Instance.disposeAll()
await disposeAllInstances()
})
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 { Instance } from "../../src/project/instance"
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"
const TestEvent = {
@ -151,7 +151,7 @@ describe("Bus (Effect-native)", () => {
}).pipe(provideInstance(dir))
// Dispose from OUTSIDE the instance scope
yield* Effect.promise(() => Instance.disposeAll())
yield* Effect.promise(disposeAllInstances)
yield* Deferred.await(disposed).pipe(Effect.timeout("2 seconds"))
expect(types).toContain("test.effect.ping")

View file

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

View file

@ -3,7 +3,7 @@ import { Schema } from "effect"
import { Bus } from "../../src/bus"
import { BusEvent } from "../../src/bus/bus-event"
import { Instance } from "../../src/project/instance"
import { tmpdir } from "../fixture/fixture"
import { disposeAllInstances, tmpdir } from "../fixture/fixture"
const TestEvent = {
Ping: BusEvent.define("test.ping", Schema.Struct({ value: Schema.Number })),
@ -15,7 +15,7 @@ function withInstance(directory: string, fn: () => Promise<void>) {
}
describe("Bus", () => {
afterEach(() => Instance.disposeAll())
afterEach(() => disposeAllInstances())
describe("publish + subscribe", () => {
test("subscriber is live immediately after subscribe returns", async () => {
@ -208,8 +208,8 @@ describe("Bus", () => {
await Bun.sleep(10)
})
// Instance.disposeAll triggers the finalizer which publishes InstanceDisposed
await Instance.disposeAll()
// disposeAllInstances triggers the finalizer which publishes InstanceDisposed
await disposeAllInstances()
await Bun.sleep(50)
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 { AppFileSystem } from "@opencode-ai/core/filesystem"
import { Env } from "../../src/env"
import { provideTmpdirInstance } from "../fixture/fixture"
import { disposeAllInstances, provideTmpdirInstance } from "../fixture/fixture"
import { tmpdir } from "../fixture/fixture"
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
import { testEffect } from "../lib/effect"
@ -108,7 +108,7 @@ async function check(map: (dir: string) => string) {
},
})
} finally {
await Instance.disposeAll()
await disposeAllInstances()
;(Global.Path as { config: string }).config = prev
await clear()
}

View file

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

View file

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

View file

@ -6,10 +6,10 @@ import fs from "fs/promises"
import { File } from "../../src/file"
import { Instance } from "../../src/project/instance"
import { Filesystem } from "@/util/filesystem"
import { provideInstance, tmpdir } from "../fixture/fixture"
import { disposeAllInstances, provideInstance, tmpdir } from "../fixture/fixture"
afterEach(async () => {
await Instance.disposeAll()
await disposeAllInstances()
})
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.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 path from "path"
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 { Config } from "@/config/config"
import { FileWatcher } from "../../src/file/watcher"
@ -147,7 +147,7 @@ function ready(directory: string) {
describeWatcher("FileWatcher", () => {
afterEach(async () => {
await Instance.disposeAll()
await disposeAllInstances()
})
test("publishes root create, update, and delete events", async () => {

View file

@ -1,9 +1,9 @@
import { rm } from "fs/promises"
import { Instance } from "../../src/project/instance"
import { Database } from "@/storage/db"
import { disposeAllInstances } from "./fixture"
export async function resetDatabase() {
await Instance.disposeAll().catch(() => undefined)
await disposeAllInstances().catch(() => undefined)
Database.close()
await rm(Database.Path, { 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 { InstanceRef } from "../../src/effect/instance-ref"
import { Instance } from "../../src/project/instance"
import { InstanceStore } from "../../src/project/instance-store"
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)
function sanitizePath(p: string): string {
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 { Config } from "@/config/config"
import { Instance } from "../src/project/instance"
import { tmpdir } from "./fixture/fixture"
import { disposeAllInstances, tmpdir } from "./fixture/fixture"
import { AppRuntime } from "../src/effect/app-runtime"
const load = () => AppRuntime.runPromise(Config.Service.use((svc) => svc.get()))
afterEach(async () => {
await Instance.disposeAll()
await disposeAllInstances()
})
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 { PermissionID } from "../../src/permission/schema"
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 { 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)
afterEach(async () => {
await Instance.disposeAll()
await disposeAllInstances()
})
const rejectAll = (message?: string) =>

View file

@ -3,7 +3,7 @@ import { Effect } from "effect"
import fs from "fs/promises"
import path from "path"
import { pathToFileURL } from "url"
import { tmpdir } from "../fixture/fixture"
import { disposeAllInstances, tmpdir } from "../fixture/fixture"
import { Filesystem } from "@/util/filesystem"
const disableDefault = process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS
@ -24,7 +24,7 @@ afterAll(() => {
})
afterEach(async () => {
await Instance.disposeAll()
await disposeAllInstances()
})
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 path from "path"
import { pathToFileURL } from "url"
import { provideTmpdirInstance } from "../fixture/fixture"
import { disposeAllInstances, provideTmpdirInstance } from "../fixture/fixture"
import { testEffect } from "../lib/effect"
const disableDefault = process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS
@ -20,7 +20,7 @@ const experimental = Flag.OPENCODE_EXPERIMENTAL_WORKSPACES
Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = true
afterEach(async () => {
await Instance.disposeAll()
await disposeAllInstances()
})
afterAll(() => {

View file

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

View file

@ -3,7 +3,7 @@ import { afterEach, describe, expect, test } from "bun:test"
import { Effect } from "effect"
import fs from "fs/promises"
import path from "path"
import { tmpdir } from "../fixture/fixture"
import { disposeAllInstances, tmpdir } from "../fixture/fixture"
import { AppRuntime } from "../../src/effect/app-runtime"
import { FileWatcher } from "../../src/file/watcher"
import { Instance } from "../../src/project/instance"
@ -85,7 +85,7 @@ function nextBranchUpdate(directory: string, timeout = 10_000) {
describeVcs("Vcs", () => {
afterEach(async () => {
await Instance.disposeAll()
await disposeAllInstances()
})
test("branch() returns current branch name", async () => {
@ -158,7 +158,7 @@ describeVcs("Vcs", () => {
describe("Vcs diff", () => {
afterEach(async () => {
await Instance.disposeAll()
await disposeAllInstances()
})
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 { Instance } from "../../src/project/instance"
import { Worktree } from "../../src/worktree"
import { provideInstance, provideTmpdirInstance } from "../fixture/fixture"
import { disposeAllInstances, provideInstance, provideTmpdirInstance } from "../fixture/fixture"
import { testEffect } from "../lib/effect"
const it = testEffect(Layer.mergeAll(Worktree.defaultLayer, CrossSpawnSpawner.defaultLayer))
@ -37,7 +37,7 @@ async function waitReady() {
}
describe("Worktree", () => {
afterEach(() => Instance.disposeAll())
afterEach(() => disposeAllInstances())
describe("makeWorktreeInfo", () => {
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 path from "path"
import { tmpdir } from "../fixture/fixture"
import { disposeAllInstances, tmpdir } from "../fixture/fixture"
import { Global } from "@opencode-ai/core/global"
import { Instance } from "../../src/project/instance"
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")].models[ModelID.make("chat")]).toBeDefined()
await Instance.disposeAll()
await disposeAllInstances()
const second = await Instance.provide({
directory: tmp.path,

View file

@ -2,7 +2,7 @@ import { afterEach, test, expect } from "bun:test"
import { Question } from "../../src/question"
import { Instance } from "../../src/project/instance"
import { QuestionID } from "../../src/question/schema"
import { tmpdir } from "../fixture/fixture"
import { disposeAllInstances, tmpdir } from "../fixture/fixture"
import { SessionID } from "../../src/session/schema"
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)))
afterEach(async () => {
await Instance.disposeAll()
await disposeAllInstances()
})
/** 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 { OpenApi } from "effect/unstable/httpapi"
import { resetDatabase } from "../fixture/db"
import { tmpdir } from "../fixture/fixture"
import { disposeAllInstances, tmpdir } from "../fixture/fixture"
void Log.init({ print: false })
@ -208,7 +208,7 @@ afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original.OPENCODE_EXPERIMENTAL_HTTPAPI
Flag.OPENCODE_SERVER_PASSWORD = original.OPENCODE_SERVER_PASSWORD
Flag.OPENCODE_SERVER_USERNAME = original.OPENCODE_SERVER_USERNAME
await Instance.disposeAll()
await disposeAllInstances()
await resetDatabase()
})

View file

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

View file

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

View file

@ -10,7 +10,7 @@ import { Database } from "@/storage/db"
import * as Log from "@opencode-ai/core/util/log"
import { Worktree } from "../../src/worktree"
import { resetDatabase } from "../fixture/db"
import { tmpdir } from "../fixture/fixture"
import { disposeAllInstances, tmpdir } from "../fixture/fixture"
void Log.init({ print: false })
@ -50,7 +50,7 @@ async function waitReady(directory: string) {
afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original
await Instance.disposeAll()
await disposeAllInstances()
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 * as Log from "@opencode-ai/core/util/log"
import { resetDatabase } from "../fixture/db"
import { tmpdir } from "../fixture/fixture"
import { disposeAllInstances, tmpdir } from "../fixture/fixture"
void Log.init({ print: false })
@ -28,7 +28,7 @@ function request(route: string, directory: string, query?: Record<string, string
}
afterEach(async () => {
await Instance.disposeAll()
await disposeAllInstances()
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 { workspaceRouterMiddleware } from "../../src/server/routes/instance/httpapi/middleware/workspace-routing"
import { resetDatabase } from "../fixture/db"
import { tmpdirScoped } from "../fixture/fixture"
import { disposeAllInstances, tmpdirScoped } from "../fixture/fixture"
import { testEffect } from "../lib/effect"
const testStateLayer = Layer.effectDiscard(
@ -30,7 +30,7 @@ const testStateLayer = Layer.effectDiscard(
yield* Effect.addFinalizer(() =>
Effect.promise(async () => {
Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = originalWorkspaces
await Instance.disposeAll()
await disposeAllInstances()
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 * as Log from "@opencode-ai/core/util/log"
import { resetDatabase } from "../fixture/db"
import { tmpdir } from "../fixture/fixture"
import { disposeAllInstances, tmpdir } from "../fixture/fixture"
void Log.init({ print: false })
@ -37,7 +37,7 @@ async function waitDisposed(directory: string) {
afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original
await Instance.disposeAll()
await disposeAllInstances()
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 { ExperimentalHttpApiServer } from "../../src/server/routes/instance/httpapi/server"
import { resetDatabase } from "../fixture/db"
import { tmpdirScoped } from "../fixture/fixture"
import { disposeAllInstances, tmpdirScoped } from "../fixture/fixture"
import { testEffect } from "../lib/effect"
// Flip the experimental HttpApi flag so backend selection telemetry on the
// production routes reports the right backend, and reset the database around
// 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(
Effect.gen(function* () {
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 * as Log from "@opencode-ai/core/util/log"
import { resetDatabase } from "../fixture/db"
import { provideInstance, tmpdir } from "../fixture/fixture"
import { disposeAllInstances, provideInstance, tmpdir } from "../fixture/fixture"
import { it } from "../lib/effect"
void Log.init({ print: false })
@ -89,7 +89,7 @@ function expectJsonParity(input: {
afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original
await Instance.disposeAll()
await disposeAllInstances()
await resetDatabase()
})

View file

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

View file

@ -6,7 +6,7 @@ import { Instance } from "../../src/project/instance"
import { Server } from "../../src/server/server"
import * as Log from "@opencode-ai/core/util/log"
import { resetDatabase } from "../fixture/db"
import { provideInstance } from "../fixture/fixture"
import { disposeAllInstances, provideInstance } from "../fixture/fixture"
import { testEffect } from "../lib/effect"
void Log.init({ print: false })
@ -98,7 +98,7 @@ function withProviderProject<A, E, R>(self: (dir: string) => Effect.Effect<A, E,
afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original
await Instance.disposeAll()
await disposeAllInstances()
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 * as Log from "@opencode-ai/core/util/log"
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 { HttpClient, HttpClientRequest, HttpRouter, HttpServer } from "effect/unstable/http"
import * as Socket from "effect/unstable/socket/Socket"
@ -63,7 +63,7 @@ const directoryHeader = (dir: string) => HttpClientRequest.setHeader("x-opencode
afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original
await Instance.disposeAll()
await disposeAllInstances()
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 { PtyID } from "../../src/pty/schema"
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"
void Log.init({ print: false })
@ -49,7 +49,7 @@ async function cancelBody(response: Response) {
afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = originalHttpApi
await Instance.disposeAll()
await disposeAllInstances()
await resetDatabase()
})

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -5,7 +5,7 @@ import { Server } from "../../src/server/server"
import { Session as SessionNs } from "@/session/session"
import type { SessionID } from "../../src/session/schema"
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 })
@ -25,7 +25,7 @@ const svc = {
afterEach(async () => {
mock.restore()
await Instance.disposeAll()
await disposeAllInstances()
})
describe("session action routes", () => {

View file

@ -3,7 +3,7 @@ import { Effect } from "effect"
import { Instance } from "../../src/project/instance"
import { Session as SessionNs } from "@/session/session"
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 { mkdir } from "fs/promises"
import path from "path"
@ -30,7 +30,7 @@ const svc = {
afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = originalWorkspaces
await Instance.disposeAll()
await disposeAllInstances()
})
describe("session.list", () => {

View file

@ -6,7 +6,7 @@ import { Session as SessionNs } from "@/session/session"
import { MessageV2 } from "../../src/session/message-v2"
import { MessageID, PartID, type SessionID } from "../../src/session/schema"
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 })
@ -31,7 +31,7 @@ const svc = {
}
afterEach(async () => {
await Instance.disposeAll()
await disposeAllInstances()
})
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 { Instance } from "../../src/project/instance"
import { Server } from "../../src/server/server"
import { tmpdir } from "../fixture/fixture"
import { disposeAllInstances, tmpdir } from "../fixture/fixture"
void Log.init({ print: false })
@ -24,7 +24,7 @@ const svc = {
}
afterEach(async () => {
await Instance.disposeAll()
await disposeAllInstances()
})
describe("tui.selectSession endpoint", () => {

View file

@ -6,7 +6,7 @@ import { Effect } from "effect"
import { Snapshot } from "../../src/snapshot"
import { Instance } from "../../src/project/instance"
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
// 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("\\", "/")
afterEach(async () => {
await Instance.disposeAll()
await disposeAllInstances()
})
async function bootstrap() {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -13,7 +13,7 @@ import { Tool } from "@/tool/tool"
import { Agent } from "../../src/agent/agent"
import { SessionID, MessageID } from "../../src/session/schema"
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"
const ctx = {
@ -28,7 +28,7 @@ const ctx = {
}
afterEach(async () => {
await Instance.disposeAll()
await disposeAllInstances()
})
const it = testEffect(