From 3f7df08be97a0a6f6d224c1c8c93ace80ad97c33 Mon Sep 17 00:00:00 2001 From: Dax Date: Thu, 16 Apr 2026 03:02:19 -0400 Subject: [PATCH] perf: make vcs init non-blocking by forking git branch resolution (#22771) --- packages/opencode/AGENTS.md | 6 ++++++ packages/opencode/src/project/vcs.ts | 5 +++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/opencode/AGENTS.md b/packages/opencode/AGENTS.md index fd9e597e7d..f0f32fdd16 100644 --- a/packages/opencode/AGENTS.md +++ b/packages/opencode/AGENTS.md @@ -39,6 +39,12 @@ See `specs/effect/migration.md` for the compact pattern reference and examples. - Do the work directly in the `InstanceState.make` closure — `ScopedCache` handles run-once semantics. Don't add fibers, `ensure()` callbacks, or `started` flags on top. - Use `Effect.addFinalizer` or `Effect.acquireRelease` inside the `InstanceState.make` closure for cleanup (subscriptions, process teardown, etc.). - Use `Effect.forkScoped` inside the closure for background stream consumers — the fiber is interrupted when the instance is disposed. +- To make a service's `init()` non-blocking, fork `InstanceState.get(state)` at the `init()` call site (e.g. `Effect.forkIn(scope)`), not by forking work inside the `InstanceState.make` closure. Forking inside the closure leaves state incomplete for other methods that read it. +- `src/project/bootstrap.ts` already wraps every service `init()` in `Effect.forkDetach`, so `init()` is fire-and-forget in production. Keep `init()` methods synchronous internally; the caller controls concurrency. + +## Effect v4 beta API + +- `Effect.fork` and `Effect.forkDaemon` do not exist. Use `Effect.forkIn(scope)` to fork a fiber into a specific scope. ## Preferred Effect services diff --git a/packages/opencode/src/project/vcs.ts b/packages/opencode/src/project/vcs.ts index 559371859f..b1375a7b78 100644 --- a/packages/opencode/src/project/vcs.ts +++ b/packages/opencode/src/project/vcs.ts @@ -1,4 +1,4 @@ -import { Effect, Layer, Context, Stream } from "effect" +import { Effect, Layer, Context, Stream, Scope } from "effect" import { formatPatch, structuredPatch } from "diff" import path from "path" import { Bus } from "@/bus" @@ -157,6 +157,7 @@ export const layer: Layer.Layer( Effect.fn("Vcs.state")(function* (ctx) { @@ -194,7 +195,7 @@ export const layer: Layer.Layer x.current)