mirror of
https://github.com/anomalyco/opencode.git
synced 2026-05-16 09:33:24 +00:00
refactor(cli): dispose bootstrap instance explicitly (#27721)
This commit is contained in:
@@ -1,17 +1,11 @@
|
||||
import { Instance } from "../project/instance"
|
||||
import { InstanceRuntime } from "../project/instance-runtime"
|
||||
import { WithInstance } from "../project/with-instance"
|
||||
import { context } from "../project/instance-context"
|
||||
|
||||
export async function bootstrap<T>(directory: string, cb: () => Promise<T>) {
|
||||
return WithInstance.provide({
|
||||
directory,
|
||||
fn: async () => {
|
||||
try {
|
||||
const result = await cb()
|
||||
return result
|
||||
} finally {
|
||||
await InstanceRuntime.disposeInstance(Instance.current)
|
||||
}
|
||||
},
|
||||
})
|
||||
const ctx = await InstanceRuntime.load({ directory })
|
||||
try {
|
||||
return await context.provide(ctx, cb)
|
||||
} finally {
|
||||
await InstanceRuntime.disposeInstance(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,13 @@ import { existsSync } from "node:fs"
|
||||
import path from "node:path"
|
||||
import { pathToFileURL } from "node:url"
|
||||
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
|
||||
import { Effect, Layer } from "effect"
|
||||
import { Cause, Effect, Exit, Fiber, Layer } from "effect"
|
||||
import { bootstrap as cliBootstrap } from "../../src/cli/bootstrap"
|
||||
import { InstanceLayer } from "../../src/project/instance-layer"
|
||||
import { InstanceStore } from "../../src/project/instance-store"
|
||||
import { disposeAllInstances, tmpdirScoped } from "../fixture/fixture"
|
||||
import { testEffect } from "../lib/effect"
|
||||
import { waitGlobalBusEvent } from "../server/global-bus"
|
||||
|
||||
const it = testEffect(Layer.mergeAll(InstanceLayer.layer, CrossSpawnSpawner.defaultLayer))
|
||||
|
||||
@@ -54,6 +55,13 @@ const bootstrapFixture = Effect.gen(function* () {
|
||||
return { directory: dir, marker }
|
||||
})
|
||||
|
||||
function waitDisposed(directory: string) {
|
||||
return waitGlobalBusEvent({
|
||||
message: "timed out waiting for CLI bootstrap instance disposal",
|
||||
predicate: (event) => event.payload.type === "server.instance.disposed" && event.directory === directory,
|
||||
})
|
||||
}
|
||||
|
||||
it.live("InstanceStore.provide runs InstanceBootstrap before effect", () =>
|
||||
Effect.gen(function* () {
|
||||
const tmp = yield* bootstrapFixture
|
||||
@@ -75,6 +83,21 @@ it.live("CLI bootstrap runs InstanceBootstrap before callback", () =>
|
||||
}),
|
||||
)
|
||||
|
||||
it.live("CLI bootstrap disposes the instance when the callback rejects", () =>
|
||||
Effect.gen(function* () {
|
||||
const tmp = yield* bootstrapFixture
|
||||
const disposed = yield* waitDisposed(tmp.directory).pipe(Effect.forkScoped)
|
||||
|
||||
const exit = yield* Effect.promise(() => cliBootstrap(tmp.directory, async () => Promise.reject(new Error("boom")))).pipe(
|
||||
Effect.exit,
|
||||
)
|
||||
|
||||
expect(Exit.isFailure(exit)).toBe(true)
|
||||
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toMatchObject({ message: "boom" })
|
||||
yield* Fiber.join(disposed)
|
||||
}),
|
||||
)
|
||||
|
||||
it.live("InstanceStore.reload runs InstanceBootstrap", () =>
|
||||
Effect.gen(function* () {
|
||||
const tmp = yield* bootstrapFixture
|
||||
|
||||
Reference in New Issue
Block a user