mirror of
https://github.com/anomalyco/opencode.git
synced 2026-06-01 19:05:38 +00:00
core: make InstanceBootstrap into an effect (#22274)
Co-authored-by: Kit Langton <kit.langton@gmail.com>
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
import { AppRuntime } from "@/effect/app-runtime"
|
||||||
|
|
||||||
const dir = process.env.OPENCODE_E2E_PROJECT_DIR ?? process.cwd()
|
const dir = process.env.OPENCODE_E2E_PROJECT_DIR ?? process.cwd()
|
||||||
const title = process.env.OPENCODE_E2E_SESSION_TITLE ?? "E2E Session"
|
const title = process.env.OPENCODE_E2E_SESSION_TITLE ?? "E2E Session"
|
||||||
const text = process.env.OPENCODE_E2E_MESSAGE ?? "Seeded for UI e2e"
|
const text = process.env.OPENCODE_E2E_MESSAGE ?? "Seeded for UI e2e"
|
||||||
@@ -20,7 +22,7 @@ const seed = async () => {
|
|||||||
try {
|
try {
|
||||||
await Instance.provide({
|
await Instance.provide({
|
||||||
directory: dir,
|
directory: dir,
|
||||||
init: InstanceBootstrap,
|
init: () => AppRuntime.runPromise(InstanceBootstrap),
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
await Config.waitForDependencies()
|
await Config.waitForDependencies()
|
||||||
await ToolRegistry.ids()
|
await ToolRegistry.ids()
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
|
import { AppRuntime } from "@/effect/app-runtime"
|
||||||
import { InstanceBootstrap } from "../project/bootstrap"
|
import { InstanceBootstrap } from "../project/bootstrap"
|
||||||
import { Instance } from "../project/instance"
|
import { Instance } from "../project/instance"
|
||||||
|
|
||||||
export async function bootstrap<T>(directory: string, cb: () => Promise<T>) {
|
export async function bootstrap<T>(directory: string, cb: () => Promise<T>) {
|
||||||
return Instance.provide({
|
return Instance.provide({
|
||||||
directory,
|
directory,
|
||||||
init: InstanceBootstrap,
|
init: () => AppRuntime.runPromise(InstanceBootstrap),
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
try {
|
try {
|
||||||
const result = await cb()
|
const result = await cb()
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import { Rpc } from "@/util/rpc"
|
|||||||
import { upgrade } from "@/cli/upgrade"
|
import { upgrade } from "@/cli/upgrade"
|
||||||
import { Config } from "@/config/config"
|
import { Config } from "@/config/config"
|
||||||
import { GlobalBus } from "@/bus/global"
|
import { GlobalBus } from "@/bus/global"
|
||||||
import type { GlobalEvent } from "@opencode-ai/sdk/v2"
|
|
||||||
import { Flag } from "@/flag/flag"
|
import { Flag } from "@/flag/flag"
|
||||||
import { writeHeapSnapshot } from "node:v8"
|
import { writeHeapSnapshot } from "node:v8"
|
||||||
import { Heap } from "@/cli/heap"
|
import { Heap } from "@/cli/heap"
|
||||||
|
import { AppRuntime } from "@/effect/app-runtime"
|
||||||
|
|
||||||
await Log.init({
|
await Log.init({
|
||||||
print: process.argv.includes("--print-logs"),
|
print: process.argv.includes("--print-logs"),
|
||||||
@@ -74,7 +74,7 @@ export const rpc = {
|
|||||||
async checkUpgrade(input: { directory: string }) {
|
async checkUpgrade(input: { directory: string }) {
|
||||||
await Instance.provide({
|
await Instance.provide({
|
||||||
directory: input.directory,
|
directory: input.directory,
|
||||||
init: InstanceBootstrap,
|
init: () => AppRuntime.runPromise(InstanceBootstrap),
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
await upgrade().catch(() => {})
|
await upgrade().catch(() => {})
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ import { ShareNext } from "@/share/share-next"
|
|||||||
import { SessionShare } from "@/share/session"
|
import { SessionShare } from "@/share/session"
|
||||||
|
|
||||||
export const AppLayer = Layer.mergeAll(
|
export const AppLayer = Layer.mergeAll(
|
||||||
Observability.layer,
|
// Observability.layer,
|
||||||
AppFileSystem.defaultLayer,
|
AppFileSystem.defaultLayer,
|
||||||
Bus.defaultLayer,
|
Bus.defaultLayer,
|
||||||
Auth.defaultLayer,
|
Auth.defaultLayer,
|
||||||
@@ -95,6 +95,6 @@ export const AppLayer = Layer.mergeAll(
|
|||||||
Installation.defaultLayer,
|
Installation.defaultLayer,
|
||||||
ShareNext.defaultLayer,
|
ShareNext.defaultLayer,
|
||||||
SessionShare.defaultLayer,
|
SessionShare.defaultLayer,
|
||||||
)
|
).pipe(Layer.provide(Observability.layer))
|
||||||
|
|
||||||
export const AppRuntime = ManagedRuntime.make(AppLayer, { memoMap })
|
export const AppRuntime = ManagedRuntime.make(AppLayer, { memoMap })
|
||||||
|
|||||||
@@ -1,10 +1,27 @@
|
|||||||
import { Layer, ManagedRuntime } from "effect"
|
import { Layer, ManagedRuntime } from "effect"
|
||||||
import { memoMap } from "./run-service"
|
import { memoMap } from "./run-service"
|
||||||
|
|
||||||
|
import { Plugin } from "@/plugin"
|
||||||
|
import { LSP } from "@/lsp"
|
||||||
import { FileWatcher } from "@/file/watcher"
|
import { FileWatcher } from "@/file/watcher"
|
||||||
import { Format } from "@/format"
|
import { Format } from "@/format"
|
||||||
import { ShareNext } from "@/share/share-next"
|
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 })
|
export const BootstrapRuntime = ManagedRuntime.make(BootstrapLayer, { memoMap })
|
||||||
|
|||||||
@@ -9,24 +9,26 @@ import { Bus } from "../bus"
|
|||||||
import { Command } from "../command"
|
import { Command } from "../command"
|
||||||
import { Instance } from "./instance"
|
import { Instance } from "./instance"
|
||||||
import { Log } from "@/util/log"
|
import { Log } from "@/util/log"
|
||||||
import { BootstrapRuntime } from "@/effect/bootstrap-runtime"
|
|
||||||
import { FileWatcher } from "@/file/watcher"
|
import { FileWatcher } from "@/file/watcher"
|
||||||
import { ShareNext } from "@/share/share-next"
|
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 })
|
Log.Default.info("bootstrapping", { directory: Instance.directory })
|
||||||
await Plugin.init()
|
yield* Plugin.Service.use((svc) => svc.init())
|
||||||
void BootstrapRuntime.runPromise(ShareNext.Service.use((svc) => svc.init()))
|
yield* ShareNext.Service.use((svc) => svc.init()).pipe(Effect.forkDetach)
|
||||||
void BootstrapRuntime.runPromise(Format.Service.use((svc) => svc.init()))
|
yield* Format.Service.use((svc) => svc.init()).pipe(Effect.forkDetach)
|
||||||
await LSP.init()
|
yield* LSP.Service.use((svc) => svc.init())
|
||||||
File.init()
|
yield* File.Service.use((svc) => svc.init()).pipe(Effect.forkDetach)
|
||||||
void BootstrapRuntime.runPromise(FileWatcher.Service.use((svc) => svc.init()))
|
yield* FileWatcher.Service.use((svc) => svc.init()).pipe(Effect.forkDetach)
|
||||||
Vcs.init()
|
yield* Vcs.Service.use((svc) => svc.init()).pipe(Effect.forkDetach)
|
||||||
Snapshot.init()
|
yield* Snapshot.Service.use((svc) => svc.init()).pipe(Effect.forkDetach)
|
||||||
|
|
||||||
Bus.subscribe(Command.Event.Executed, async (payload) => {
|
yield* Bus.Service.use((svc) =>
|
||||||
if (payload.properties.name === Command.Default.INIT) {
|
svc.subscribeCallback(Command.Event.Executed, async (payload) => {
|
||||||
Project.setInitialized(Instance.project.id)
|
if (payload.properties.name === Command.Default.INIT) {
|
||||||
}
|
Project.setInitialized(Instance.project.id)
|
||||||
})
|
}
|
||||||
}
|
}),
|
||||||
|
)
|
||||||
|
}).pipe(Effect.withSpan("InstanceBootstrap"))
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { InstanceBootstrap } from "@/project/bootstrap"
|
|||||||
import { Session } from "@/session"
|
import { Session } from "@/session"
|
||||||
import { SessionID } from "@/session/schema"
|
import { SessionID } from "@/session/schema"
|
||||||
import { WorkspaceContext } from "@/control-plane/workspace-context"
|
import { WorkspaceContext } from "@/control-plane/workspace-context"
|
||||||
|
import { AppRuntime } from "@/effect/app-runtime"
|
||||||
|
|
||||||
type Rule = { method?: string; path: string; exact?: boolean; action: "local" | "forward" }
|
type Rule = { method?: string; path: string; exact?: boolean; action: "local" | "forward" }
|
||||||
|
|
||||||
@@ -66,7 +67,7 @@ export function WorkspaceRouterMiddleware(upgrade: UpgradeWebSocket): Middleware
|
|||||||
if (!workspaceID) {
|
if (!workspaceID) {
|
||||||
return Instance.provide({
|
return Instance.provide({
|
||||||
directory,
|
directory,
|
||||||
init: InstanceBootstrap,
|
init: () => AppRuntime.runPromise(InstanceBootstrap),
|
||||||
async fn() {
|
async fn() {
|
||||||
return next()
|
return next()
|
||||||
},
|
},
|
||||||
@@ -103,7 +104,7 @@ export function WorkspaceRouterMiddleware(upgrade: UpgradeWebSocket): Middleware
|
|||||||
fn: () =>
|
fn: () =>
|
||||||
Instance.provide({
|
Instance.provide({
|
||||||
directory: target.directory,
|
directory: target.directory,
|
||||||
init: InstanceBootstrap,
|
init: () => AppRuntime.runPromise(InstanceBootstrap),
|
||||||
async fn() {
|
async fn() {
|
||||||
return next()
|
return next()
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { ProjectID } from "../../project/schema"
|
|||||||
import { errors } from "../error"
|
import { errors } from "../error"
|
||||||
import { lazy } from "../../util/lazy"
|
import { lazy } from "../../util/lazy"
|
||||||
import { InstanceBootstrap } from "../../project/bootstrap"
|
import { InstanceBootstrap } from "../../project/bootstrap"
|
||||||
|
import { AppRuntime } from "@/effect/app-runtime"
|
||||||
|
|
||||||
export const ProjectRoutes = lazy(() =>
|
export const ProjectRoutes = lazy(() =>
|
||||||
new Hono()
|
new Hono()
|
||||||
@@ -83,7 +84,7 @@ export const ProjectRoutes = lazy(() =>
|
|||||||
directory: dir,
|
directory: dir,
|
||||||
worktree: dir,
|
worktree: dir,
|
||||||
project: next,
|
project: next,
|
||||||
init: InstanceBootstrap,
|
init: () => AppRuntime.runPromise(InstanceBootstrap),
|
||||||
})
|
})
|
||||||
return c.json(next)
|
return c.json(next)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import { AppFileSystem } from "@/filesystem"
|
|||||||
import { makeRuntime } from "@/effect/run-service"
|
import { makeRuntime } from "@/effect/run-service"
|
||||||
import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
|
import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
|
||||||
import { InstanceState } from "@/effect/instance-state"
|
import { InstanceState } from "@/effect/instance-state"
|
||||||
|
import { AppRuntime } from "@/effect/app-runtime"
|
||||||
|
|
||||||
export namespace Worktree {
|
export namespace Worktree {
|
||||||
const log = Log.create({ service: "worktree" })
|
const log = Log.create({ service: "worktree" })
|
||||||
@@ -266,7 +267,7 @@ export namespace Worktree {
|
|||||||
const booted = yield* Effect.promise(() =>
|
const booted = yield* Effect.promise(() =>
|
||||||
Instance.provide({
|
Instance.provide({
|
||||||
directory: info.directory,
|
directory: info.directory,
|
||||||
init: InstanceBootstrap,
|
init: () => AppRuntime.runPromise(InstanceBootstrap),
|
||||||
fn: () => undefined,
|
fn: () => undefined,
|
||||||
})
|
})
|
||||||
.then(() => true)
|
.then(() => true)
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ describe("project.initGit endpoint", () => {
|
|||||||
worktree: tmp.path,
|
worktree: tmp.path,
|
||||||
})
|
})
|
||||||
expect(reloadSpy).toHaveBeenCalledTimes(1)
|
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(
|
expect(seen.some((evt) => evt.directory === tmp.path && evt.payload.type === "server.instance.disposed")).toBe(
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user