summaryrefslogtreecommitdiffhomepage
path: root/packages
diff options
context:
space:
mode:
authorBrendan Allan <[email protected]>2026-04-13 22:16:40 +0800
committerGitHub <[email protected]>2026-04-13 10:16:40 -0400
commit94f71f59a3eb3a4d376e371c5958a7f0cbf0a27e (patch)
treedd1f922330e264452b45b845c3abd4e552ae57c3 /packages
parent3eb6508a64d33922930d18c8659a9e1a5819e9ea (diff)
downloadopencode-94f71f59a3eb3a4d376e371c5958a7f0cbf0a27e.tar.gz
opencode-94f71f59a3eb3a4d376e371c5958a7f0cbf0a27e.zip
core: make InstanceBootstrap into an effect (#22274)
Co-authored-by: Kit Langton <[email protected]>
Diffstat (limited to 'packages')
-rw-r--r--packages/opencode/script/seed-e2e.ts4
-rw-r--r--packages/opencode/src/cli/bootstrap.ts3
-rw-r--r--packages/opencode/src/cli/cmd/tui/worker.ts4
-rw-r--r--packages/opencode/src/effect/app-runtime.ts4
-rw-r--r--packages/opencode/src/effect/bootstrap-runtime.ts19
-rw-r--r--packages/opencode/src/project/bootstrap.ts34
-rw-r--r--packages/opencode/src/server/instance/middleware.ts5
-rw-r--r--packages/opencode/src/server/instance/project.ts3
-rw-r--r--packages/opencode/src/worktree/index.ts3
-rw-r--r--packages/opencode/test/server/project-init-git.test.ts1
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,
)