Skip to content

Commit 94f71f5

Browse files
core: make InstanceBootstrap into an effect (#22274)
Co-authored-by: Kit Langton <kit.langton@gmail.com>
1 parent 3eb6508 commit 94f71f5

10 files changed

Lines changed: 52 additions & 28 deletions

File tree

packages/opencode/script/seed-e2e.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { AppRuntime } from "@/effect/app-runtime"
2+
13
const dir = process.env.OPENCODE_E2E_PROJECT_DIR ?? process.cwd()
24
const title = process.env.OPENCODE_E2E_SESSION_TITLE ?? "E2E Session"
35
const text = process.env.OPENCODE_E2E_MESSAGE ?? "Seeded for UI e2e"
@@ -20,7 +22,7 @@ const seed = async () => {
2022
try {
2123
await Instance.provide({
2224
directory: dir,
23-
init: InstanceBootstrap,
25+
init: () => AppRuntime.runPromise(InstanceBootstrap),
2426
fn: async () => {
2527
await Config.waitForDependencies()
2628
await ToolRegistry.ids()

packages/opencode/src/cli/bootstrap.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
import { AppRuntime } from "@/effect/app-runtime"
12
import { InstanceBootstrap } from "../project/bootstrap"
23
import { Instance } from "../project/instance"
34

45
export async function bootstrap<T>(directory: string, cb: () => Promise<T>) {
56
return Instance.provide({
67
directory,
7-
init: InstanceBootstrap,
8+
init: () => AppRuntime.runPromise(InstanceBootstrap),
89
fn: async () => {
910
try {
1011
const result = await cb()

packages/opencode/src/cli/cmd/tui/worker.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ import { Rpc } from "@/util/rpc"
77
import { upgrade } from "@/cli/upgrade"
88
import { Config } from "@/config/config"
99
import { GlobalBus } from "@/bus/global"
10-
import type { GlobalEvent } from "@opencode-ai/sdk/v2"
1110
import { Flag } from "@/flag/flag"
1211
import { writeHeapSnapshot } from "node:v8"
1312
import { Heap } from "@/cli/heap"
13+
import { AppRuntime } from "@/effect/app-runtime"
1414

1515
await Log.init({
1616
print: process.argv.includes("--print-logs"),
@@ -74,7 +74,7 @@ export const rpc = {
7474
async checkUpgrade(input: { directory: string }) {
7575
await Instance.provide({
7676
directory: input.directory,
77-
init: InstanceBootstrap,
77+
init: () => AppRuntime.runPromise(InstanceBootstrap),
7878
fn: async () => {
7979
await upgrade().catch(() => {})
8080
},

packages/opencode/src/effect/app-runtime.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ import { ShareNext } from "@/share/share-next"
4949
import { SessionShare } from "@/share/session"
5050

5151
export const AppLayer = Layer.mergeAll(
52-
Observability.layer,
52+
// Observability.layer,
5353
AppFileSystem.defaultLayer,
5454
Bus.defaultLayer,
5555
Auth.defaultLayer,
@@ -95,6 +95,6 @@ export const AppLayer = Layer.mergeAll(
9595
Installation.defaultLayer,
9696
ShareNext.defaultLayer,
9797
SessionShare.defaultLayer,
98-
)
98+
).pipe(Layer.provide(Observability.layer))
9999

100100
export const AppRuntime = ManagedRuntime.make(AppLayer, { memoMap })
Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,27 @@
11
import { Layer, ManagedRuntime } from "effect"
22
import { memoMap } from "./run-service"
33

4+
import { Plugin } from "@/plugin"
5+
import { LSP } from "@/lsp"
46
import { FileWatcher } from "@/file/watcher"
57
import { Format } from "@/format"
68
import { ShareNext } from "@/share/share-next"
9+
import { File } from "@/file"
10+
import { Vcs } from "@/project/vcs"
11+
import { Snapshot } from "@/snapshot"
12+
import { Bus } from "@/bus"
13+
import { Observability } from "./oltp"
714

8-
export const BootstrapLayer = Layer.mergeAll(Format.defaultLayer, ShareNext.defaultLayer, FileWatcher.defaultLayer)
15+
export const BootstrapLayer = Layer.mergeAll(
16+
Plugin.defaultLayer,
17+
ShareNext.defaultLayer,
18+
Format.defaultLayer,
19+
LSP.defaultLayer,
20+
File.defaultLayer,
21+
FileWatcher.defaultLayer,
22+
Vcs.defaultLayer,
23+
Snapshot.defaultLayer,
24+
Bus.defaultLayer,
25+
).pipe(Layer.provide(Observability.layer))
926

1027
export const BootstrapRuntime = ManagedRuntime.make(BootstrapLayer, { memoMap })

packages/opencode/src/project/bootstrap.ts

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,26 @@ import { Bus } from "../bus"
99
import { Command } from "../command"
1010
import { Instance } from "./instance"
1111
import { Log } from "@/util/log"
12-
import { BootstrapRuntime } from "@/effect/bootstrap-runtime"
1312
import { FileWatcher } from "@/file/watcher"
1413
import { ShareNext } from "@/share/share-next"
14+
import * as Effect from "effect/Effect"
1515

16-
export async function InstanceBootstrap() {
16+
export const InstanceBootstrap = Effect.gen(function* () {
1717
Log.Default.info("bootstrapping", { directory: Instance.directory })
18-
await Plugin.init()
19-
void BootstrapRuntime.runPromise(ShareNext.Service.use((svc) => svc.init()))
20-
void BootstrapRuntime.runPromise(Format.Service.use((svc) => svc.init()))
21-
await LSP.init()
22-
File.init()
23-
void BootstrapRuntime.runPromise(FileWatcher.Service.use((svc) => svc.init()))
24-
Vcs.init()
25-
Snapshot.init()
18+
yield* Plugin.Service.use((svc) => svc.init())
19+
yield* ShareNext.Service.use((svc) => svc.init()).pipe(Effect.forkDetach)
20+
yield* Format.Service.use((svc) => svc.init()).pipe(Effect.forkDetach)
21+
yield* LSP.Service.use((svc) => svc.init())
22+
yield* File.Service.use((svc) => svc.init()).pipe(Effect.forkDetach)
23+
yield* FileWatcher.Service.use((svc) => svc.init()).pipe(Effect.forkDetach)
24+
yield* Vcs.Service.use((svc) => svc.init()).pipe(Effect.forkDetach)
25+
yield* Snapshot.Service.use((svc) => svc.init()).pipe(Effect.forkDetach)
2626

27-
Bus.subscribe(Command.Event.Executed, async (payload) => {
28-
if (payload.properties.name === Command.Default.INIT) {
29-
Project.setInitialized(Instance.project.id)
30-
}
31-
})
32-
}
27+
yield* Bus.Service.use((svc) =>
28+
svc.subscribeCallback(Command.Event.Executed, async (payload) => {
29+
if (payload.properties.name === Command.Default.INIT) {
30+
Project.setInitialized(Instance.project.id)
31+
}
32+
}),
33+
)
34+
}).pipe(Effect.withSpan("InstanceBootstrap"))

packages/opencode/src/server/instance/middleware.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { InstanceBootstrap } from "@/project/bootstrap"
1010
import { Session } from "@/session"
1111
import { SessionID } from "@/session/schema"
1212
import { WorkspaceContext } from "@/control-plane/workspace-context"
13+
import { AppRuntime } from "@/effect/app-runtime"
1314

1415
type Rule = { method?: string; path: string; exact?: boolean; action: "local" | "forward" }
1516

@@ -66,7 +67,7 @@ export function WorkspaceRouterMiddleware(upgrade: UpgradeWebSocket): Middleware
6667
if (!workspaceID) {
6768
return Instance.provide({
6869
directory,
69-
init: InstanceBootstrap,
70+
init: () => AppRuntime.runPromise(InstanceBootstrap),
7071
async fn() {
7172
return next()
7273
},
@@ -103,7 +104,7 @@ export function WorkspaceRouterMiddleware(upgrade: UpgradeWebSocket): Middleware
103104
fn: () =>
104105
Instance.provide({
105106
directory: target.directory,
106-
init: InstanceBootstrap,
107+
init: () => AppRuntime.runPromise(InstanceBootstrap),
107108
async fn() {
108109
return next()
109110
},

packages/opencode/src/server/instance/project.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { ProjectID } from "../../project/schema"
88
import { errors } from "../error"
99
import { lazy } from "../../util/lazy"
1010
import { InstanceBootstrap } from "../../project/bootstrap"
11+
import { AppRuntime } from "@/effect/app-runtime"
1112

1213
export const ProjectRoutes = lazy(() =>
1314
new Hono()
@@ -83,7 +84,7 @@ export const ProjectRoutes = lazy(() =>
8384
directory: dir,
8485
worktree: dir,
8586
project: next,
86-
init: InstanceBootstrap,
87+
init: () => AppRuntime.runPromise(InstanceBootstrap),
8788
})
8889
return c.json(next)
8990
},

packages/opencode/src/worktree/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { AppFileSystem } from "@/filesystem"
2020
import { makeRuntime } from "@/effect/run-service"
2121
import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
2222
import { InstanceState } from "@/effect/instance-state"
23+
import { AppRuntime } from "@/effect/app-runtime"
2324

2425
export namespace Worktree {
2526
const log = Log.create({ service: "worktree" })
@@ -266,7 +267,7 @@ export namespace Worktree {
266267
const booted = yield* Effect.promise(() =>
267268
Instance.provide({
268269
directory: info.directory,
269-
init: InstanceBootstrap,
270+
init: () => AppRuntime.runPromise(InstanceBootstrap),
270271
fn: () => undefined,
271272
})
272273
.then(() => true)

packages/opencode/test/server/project-init-git.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ describe("project.initGit endpoint", () => {
4343
worktree: tmp.path,
4444
})
4545
expect(reloadSpy).toHaveBeenCalledTimes(1)
46-
expect(reloadSpy.mock.calls[0]?.[0]?.init).toBe(InstanceBootstrap)
4746
expect(seen.some((evt) => evt.directory === tmp.path && evt.payload.type === "server.instance.disposed")).toBe(
4847
true,
4948
)

0 commit comments

Comments
 (0)