diff options
| author | Kit Langton <[email protected]> | 2026-03-26 22:14:46 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-03-27 02:14:46 +0000 |
| commit | e96eead32eb28c8b78be9def46cb1688d49468ae (patch) | |
| tree | 4adb238961e364c4dcdfe321a481c481ad3da56e | |
| parent | b242a8d8e42839496c7213d020e8cba19a76e111 (diff) | |
| download | opencode-e96eead32eb28c8b78be9def46cb1688d49468ae.tar.gz opencode-e96eead32eb28c8b78be9def46cb1688d49468ae.zip | |
refactor(vcs): replace async git() with ChildProcessSpawner (#19361)
| -rw-r--r-- | packages/opencode/src/project/vcs.ts | 39 |
1 files changed, 26 insertions, 13 deletions
diff --git a/packages/opencode/src/project/vcs.ts b/packages/opencode/src/project/vcs.ts index 1c595f7f1..25f172b8a 100644 --- a/packages/opencode/src/project/vcs.ts +++ b/packages/opencode/src/project/vcs.ts @@ -1,12 +1,12 @@ import { Effect, Layer, ServiceMap, Stream } from "effect" +import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" import { Bus } from "@/bus" import { BusEvent } from "@/bus/bus-event" +import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner" import { InstanceState } from "@/effect/instance-state" import { makeRuntime } from "@/effect/run-service" import { FileWatcher } from "@/file/watcher" import { Log } from "@/util/log" -import { git } from "@/util/git" -import { Instance } from "./instance" import z from "zod" export namespace Vcs { @@ -41,10 +41,25 @@ export namespace Vcs { export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Vcs") {} - export const layer: Layer.Layer<Service, never, Bus.Service> = Layer.effect( + export const layer: Layer.Layer<Service, never, Bus.Service | ChildProcessSpawner.ChildProcessSpawner> = Layer.effect( Service, Effect.gen(function* () { const bus = yield* Bus.Service + const spawner = yield* ChildProcessSpawner.ChildProcessSpawner + + const git = Effect.fnUntraced( + function* (args: string[], opts: { cwd: string }) { + const handle = yield* spawner.spawn( + ChildProcess.make("git", args, { cwd: opts.cwd, extendEnv: true, stdin: "ignore" }), + ) + const text = yield* Stream.mkString(Stream.decodeText(handle.stdout)) + const code = yield* handle.exitCode + return { code, text } + }, + Effect.scoped, + Effect.catch(() => Effect.succeed({ code: ChildProcessSpawner.ExitCode(1), text: "" })), + ) + const state = yield* InstanceState.make<State>( Effect.fn("Vcs.state")((ctx) => Effect.gen(function* () { @@ -52,17 +67,15 @@ export namespace Vcs { return { current: undefined } } - const get = async () => { - const result = await git(["rev-parse", "--abbrev-ref", "HEAD"], { - cwd: ctx.worktree, - }) - if (result.exitCode !== 0) return undefined - const text = result.text().trim() + const getBranch = Effect.fnUntraced(function* () { + const result = yield* git(["rev-parse", "--abbrev-ref", "HEAD"], { cwd: ctx.worktree }) + if (result.code !== 0) return undefined + const text = result.text.trim() return text || undefined - } + }) const value = { - current: yield* Effect.promise(() => get()), + current: yield* getBranch(), } log.info("initialized", { branch: value.current }) @@ -70,7 +83,7 @@ export namespace Vcs { Stream.filter((evt) => evt.properties.file.endsWith("HEAD")), Stream.runForEach(() => Effect.gen(function* () { - const next = yield* Effect.promise(() => get()) + const next = yield* getBranch() if (next !== value.current) { log.info("branch changed", { from: value.current, to: next }) value.current = next @@ -97,7 +110,7 @@ export namespace Vcs { }), ) - export const defaultLayer = layer.pipe(Layer.provide(Bus.layer)) + export const defaultLayer = layer.pipe(Layer.provide(Bus.layer), Layer.provide(CrossSpawnSpawner.defaultLayer)) const { runPromise } = makeRuntime(Service, defaultLayer) |
