diff options
| author | Brendan Allan <[email protected]> | 2026-04-13 22:16:40 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-04-13 10:16:40 -0400 |
| commit | 94f71f59a3eb3a4d376e371c5958a7f0cbf0a27e (patch) | |
| tree | dd1f922330e264452b45b845c3abd4e552ae57c3 | |
| parent | 3eb6508a64d33922930d18c8659a9e1a5819e9ea (diff) | |
| download | opencode-94f71f59a3eb3a4d376e371c5958a7f0cbf0a27e.tar.gz opencode-94f71f59a3eb3a4d376e371c5958a7f0cbf0a27e.zip | |
core: make InstanceBootstrap into an effect (#22274)
Co-authored-by: Kit Langton <[email protected]>
| -rw-r--r-- | packages/opencode/script/seed-e2e.ts | 4 | ||||
| -rw-r--r-- | packages/opencode/src/cli/bootstrap.ts | 3 | ||||
| -rw-r--r-- | packages/opencode/src/cli/cmd/tui/worker.ts | 4 | ||||
| -rw-r--r-- | packages/opencode/src/effect/app-runtime.ts | 4 | ||||
| -rw-r--r-- | packages/opencode/src/effect/bootstrap-runtime.ts | 19 | ||||
| -rw-r--r-- | packages/opencode/src/project/bootstrap.ts | 34 | ||||
| -rw-r--r-- | packages/opencode/src/server/instance/middleware.ts | 5 | ||||
| -rw-r--r-- | packages/opencode/src/server/instance/project.ts | 3 | ||||
| -rw-r--r-- | packages/opencode/src/worktree/index.ts | 3 | ||||
| -rw-r--r-- | packages/opencode/test/server/project-init-git.test.ts | 1 |
10 files changed, 52 insertions, 28 deletions
diff --git a/packages/opencode/script/seed-e2e.ts b/packages/opencode/script/seed-e2e.ts index f5bd7194f..6d414ec7f 100644 --- a/packages/opencode/script/seed-e2e.ts +++ b/packages/opencode/script/seed-e2e.ts @@ -1,3 +1,5 @@ +import { AppRuntime } from "@/effect/app-runtime" + const dir = process.env.OPENCODE_E2E_PROJECT_DIR ?? process.cwd() const title = process.env.OPENCODE_E2E_SESSION_TITLE ?? "E2E Session" const text = process.env.OPENCODE_E2E_MESSAGE ?? "Seeded for UI e2e" @@ -20,7 +22,7 @@ const seed = async () => { try { await Instance.provide({ directory: dir, - init: InstanceBootstrap, + init: () => AppRuntime.runPromise(InstanceBootstrap), fn: async () => { await Config.waitForDependencies() await ToolRegistry.ids() diff --git a/packages/opencode/src/cli/bootstrap.ts b/packages/opencode/src/cli/bootstrap.ts index 984d5723d..2604e703e 100644 --- a/packages/opencode/src/cli/bootstrap.ts +++ b/packages/opencode/src/cli/bootstrap.ts @@ -1,10 +1,11 @@ +import { AppRuntime } from "@/effect/app-runtime" import { InstanceBootstrap } from "../project/bootstrap" import { Instance } from "../project/instance" export async function bootstrap<T>(directory: string, cb: () => Promise<T>) { return Instance.provide({ directory, - init: InstanceBootstrap, + init: () => AppRuntime.runPromise(InstanceBootstrap), fn: async () => { try { const result = await cb() diff --git a/packages/opencode/src/cli/cmd/tui/worker.ts b/packages/opencode/src/cli/cmd/tui/worker.ts index a71b95ce4..5e9bc62c1 100644 --- a/packages/opencode/src/cli/cmd/tui/worker.ts +++ b/packages/opencode/src/cli/cmd/tui/worker.ts @@ -7,10 +7,10 @@ import { Rpc } from "@/util/rpc" import { upgrade } from "@/cli/upgrade" import { Config } from "@/config/config" import { GlobalBus } from "@/bus/global" -import type { GlobalEvent } from "@opencode-ai/sdk/v2" import { Flag } from "@/flag/flag" import { writeHeapSnapshot } from "node:v8" import { Heap } from "@/cli/heap" +import { AppRuntime } from "@/effect/app-runtime" await Log.init({ print: process.argv.includes("--print-logs"), @@ -74,7 +74,7 @@ export const rpc = { async checkUpgrade(input: { directory: string }) { await Instance.provide({ directory: input.directory, - init: InstanceBootstrap, + init: () => AppRuntime.runPromise(InstanceBootstrap), fn: async () => { await upgrade().catch(() => {}) }, diff --git a/packages/opencode/src/effect/app-runtime.ts b/packages/opencode/src/effect/app-runtime.ts index 674ca1a2a..9e1fb8bd2 100644 --- a/packages/opencode/src/effect/app-runtime.ts +++ b/packages/opencode/src/effect/app-runtime.ts @@ -49,7 +49,7 @@ import { ShareNext } from "@/share/share-next" import { SessionShare } from "@/share/session" export const AppLayer = Layer.mergeAll( - Observability.layer, + // Observability.layer, AppFileSystem.defaultLayer, Bus.defaultLayer, Auth.defaultLayer, @@ -95,6 +95,6 @@ export const AppLayer = Layer.mergeAll( Installation.defaultLayer, ShareNext.defaultLayer, SessionShare.defaultLayer, -) +).pipe(Layer.provide(Observability.layer)) export const AppRuntime = ManagedRuntime.make(AppLayer, { memoMap }) diff --git a/packages/opencode/src/effect/bootstrap-runtime.ts b/packages/opencode/src/effect/bootstrap-runtime.ts index 78df313e8..0db46fe3e 100644 --- a/packages/opencode/src/effect/bootstrap-runtime.ts +++ b/packages/opencode/src/effect/bootstrap-runtime.ts @@ -1,10 +1,27 @@ import { Layer, ManagedRuntime } from "effect" import { memoMap } from "./run-service" +import { Plugin } from "@/plugin" +import { LSP } from "@/lsp" import { FileWatcher } from "@/file/watcher" import { Format } from "@/format" import { ShareNext } from "@/share/share-next" +import { File } from "@/file" +import { Vcs } from "@/project/vcs" +import { Snapshot } from "@/snapshot" +import { Bus } from "@/bus" +import { Observability } from "./oltp" -export const BootstrapLayer = Layer.mergeAll(Format.defaultLayer, ShareNext.defaultLayer, FileWatcher.defaultLayer) +export const BootstrapLayer = Layer.mergeAll( + Plugin.defaultLayer, + ShareNext.defaultLayer, + Format.defaultLayer, + LSP.defaultLayer, + File.defaultLayer, + FileWatcher.defaultLayer, + Vcs.defaultLayer, + Snapshot.defaultLayer, + Bus.defaultLayer, +).pipe(Layer.provide(Observability.layer)) export const BootstrapRuntime = ManagedRuntime.make(BootstrapLayer, { memoMap }) diff --git a/packages/opencode/src/project/bootstrap.ts b/packages/opencode/src/project/bootstrap.ts index b7d739fcd..75e3244e1 100644 --- a/packages/opencode/src/project/bootstrap.ts +++ b/packages/opencode/src/project/bootstrap.ts @@ -9,24 +9,26 @@ import { Bus } from "../bus" import { Command } from "../command" import { Instance } from "./instance" import { Log } from "@/util/log" -import { BootstrapRuntime } from "@/effect/bootstrap-runtime" import { FileWatcher } from "@/file/watcher" import { ShareNext } from "@/share/share-next" +import * as Effect from "effect/Effect" -export async function InstanceBootstrap() { +export const InstanceBootstrap = Effect.gen(function* () { Log.Default.info("bootstrapping", { directory: Instance.directory }) - await Plugin.init() - void BootstrapRuntime.runPromise(ShareNext.Service.use((svc) => svc.init())) - void BootstrapRuntime.runPromise(Format.Service.use((svc) => svc.init())) - await LSP.init() - File.init() - void BootstrapRuntime.runPromise(FileWatcher.Service.use((svc) => svc.init())) - Vcs.init() - Snapshot.init() + yield* Plugin.Service.use((svc) => svc.init()) + yield* ShareNext.Service.use((svc) => svc.init()).pipe(Effect.forkDetach) + yield* Format.Service.use((svc) => svc.init()).pipe(Effect.forkDetach) + yield* LSP.Service.use((svc) => svc.init()) + yield* File.Service.use((svc) => svc.init()).pipe(Effect.forkDetach) + yield* FileWatcher.Service.use((svc) => svc.init()).pipe(Effect.forkDetach) + yield* Vcs.Service.use((svc) => svc.init()).pipe(Effect.forkDetach) + yield* Snapshot.Service.use((svc) => svc.init()).pipe(Effect.forkDetach) - Bus.subscribe(Command.Event.Executed, async (payload) => { - if (payload.properties.name === Command.Default.INIT) { - Project.setInitialized(Instance.project.id) - } - }) -} + yield* Bus.Service.use((svc) => + svc.subscribeCallback(Command.Event.Executed, async (payload) => { + if (payload.properties.name === Command.Default.INIT) { + Project.setInitialized(Instance.project.id) + } + }), + ) +}).pipe(Effect.withSpan("InstanceBootstrap")) diff --git a/packages/opencode/src/server/instance/middleware.ts b/packages/opencode/src/server/instance/middleware.ts index 1a5011477..19bd26535 100644 --- a/packages/opencode/src/server/instance/middleware.ts +++ b/packages/opencode/src/server/instance/middleware.ts @@ -10,6 +10,7 @@ import { InstanceBootstrap } from "@/project/bootstrap" import { Session } from "@/session" import { SessionID } from "@/session/schema" import { WorkspaceContext } from "@/control-plane/workspace-context" +import { AppRuntime } from "@/effect/app-runtime" type Rule = { method?: string; path: string; exact?: boolean; action: "local" | "forward" } @@ -66,7 +67,7 @@ export function WorkspaceRouterMiddleware(upgrade: UpgradeWebSocket): Middleware if (!workspaceID) { return Instance.provide({ directory, - init: InstanceBootstrap, + init: () => AppRuntime.runPromise(InstanceBootstrap), async fn() { return next() }, @@ -103,7 +104,7 @@ export function WorkspaceRouterMiddleware(upgrade: UpgradeWebSocket): Middleware fn: () => Instance.provide({ directory: target.directory, - init: InstanceBootstrap, + init: () => AppRuntime.runPromise(InstanceBootstrap), async fn() { return next() }, diff --git a/packages/opencode/src/server/instance/project.ts b/packages/opencode/src/server/instance/project.ts index e5dd5782d..a24953954 100644 --- a/packages/opencode/src/server/instance/project.ts +++ b/packages/opencode/src/server/instance/project.ts @@ -8,6 +8,7 @@ import { ProjectID } from "../../project/schema" import { errors } from "../error" import { lazy } from "../../util/lazy" import { InstanceBootstrap } from "../../project/bootstrap" +import { AppRuntime } from "@/effect/app-runtime" export const ProjectRoutes = lazy(() => new Hono() @@ -83,7 +84,7 @@ export const ProjectRoutes = lazy(() => directory: dir, worktree: dir, project: next, - init: InstanceBootstrap, + init: () => AppRuntime.runPromise(InstanceBootstrap), }) return c.json(next) }, diff --git a/packages/opencode/src/worktree/index.ts b/packages/opencode/src/worktree/index.ts index f4ec0af83..3a3a39c31 100644 --- a/packages/opencode/src/worktree/index.ts +++ b/packages/opencode/src/worktree/index.ts @@ -20,6 +20,7 @@ import { AppFileSystem } from "@/filesystem" import { makeRuntime } from "@/effect/run-service" import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner" import { InstanceState } from "@/effect/instance-state" +import { AppRuntime } from "@/effect/app-runtime" export namespace Worktree { const log = Log.create({ service: "worktree" }) @@ -266,7 +267,7 @@ export namespace Worktree { const booted = yield* Effect.promise(() => Instance.provide({ directory: info.directory, - init: InstanceBootstrap, + init: () => AppRuntime.runPromise(InstanceBootstrap), fn: () => undefined, }) .then(() => true) diff --git a/packages/opencode/test/server/project-init-git.test.ts b/packages/opencode/test/server/project-init-git.test.ts index eca562a0f..8cb159d9a 100644 --- a/packages/opencode/test/server/project-init-git.test.ts +++ b/packages/opencode/test/server/project-init-git.test.ts @@ -43,7 +43,6 @@ describe("project.initGit endpoint", () => { worktree: tmp.path, }) expect(reloadSpy).toHaveBeenCalledTimes(1) - expect(reloadSpy.mock.calls[0]?.[0]?.init).toBe(InstanceBootstrap) expect(seen.some((evt) => evt.directory === tmp.path && evt.payload.type === "server.instance.disposed")).toBe( true, ) |
