diff --git a/packages/opencode/src/git/index.ts b/packages/opencode/src/git/index.ts index 349bbad466..4c88edaea3 100644 --- a/packages/opencode/src/git/index.ts +++ b/packages/opencode/src/git/index.ts @@ -1,6 +1,6 @@ -import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" +import { AppProcess } from "@opencode-ai/core/process" import { Effect, Layer, Context, Stream } from "effect" -import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" +import { ChildProcess } from "effect/unstable/process" const cfg = [ "--no-optional-locks", @@ -102,49 +102,31 @@ export class Service extends Context.Service()("@opencode/Gi export const layer = Layer.effect( Service, Effect.gen(function* () { - const spawner = yield* ChildProcessSpawner.ChildProcessSpawner + const appProcess = yield* AppProcess.Service const encoder = new TextEncoder() const stdin = (text: string) => Stream.make(encoder.encode(text)) const run = Effect.fn("Git.run")( function* (args: string[], opts: Options) { - const proc = ChildProcess.make("git", [...cfg, ...args], { - cwd: opts.cwd, - env: opts.env, - extendEnv: true, - stdin: opts.stdin ?? "ignore", - stdout: "pipe", - stderr: "pipe", - }) - const handle = yield* spawner.spawn(proc) - const collect = (stream: typeof handle.stdout) => - Stream.runFold( - stream, - () => ({ chunks: [] as Uint8Array[], bytes: 0, truncated: false }), - (acc, chunk) => { - if (opts.maxOutputBytes === undefined) { - acc.chunks.push(chunk) - acc.bytes += chunk.length - return acc - } - - const remaining = opts.maxOutputBytes - acc.bytes - if (remaining > 0) acc.chunks.push(remaining >= chunk.length ? chunk : chunk.slice(0, remaining)) - acc.bytes += chunk.length - acc.truncated = acc.truncated || acc.bytes > opts.maxOutputBytes - return acc - }, - ).pipe(Effect.map((x) => ({ buffer: Buffer.concat(x.chunks), truncated: x.truncated }))) - const [stdout, stderr] = yield* Effect.all([collect(handle.stdout), collect(handle.stderr)], { concurrency: 2 }) + const result = yield* appProcess.run( + ChildProcess.make("git", [...cfg, ...args], { + cwd: opts.cwd, + env: opts.env, + extendEnv: true, + stdin: opts.stdin ?? "ignore", + stdout: "pipe", + stderr: "pipe", + }), + { maxOutputBytes: opts.maxOutputBytes }, + ) return { - exitCode: yield* handle.exitCode, - text: () => stdout.buffer.toString("utf8"), - stdout: stdout.buffer, - stderr: stderr.buffer, - truncated: stdout.truncated || stderr.truncated, + exitCode: result.exitCode, + text: () => result.stdout.toString("utf8"), + stdout: result.stdout, + stderr: result.stderr, + truncated: result.truncated, } satisfies Result }, - Effect.scoped, Effect.catch((err) => Effect.succeed(fail(err))), ) @@ -360,6 +342,6 @@ export const layer = Layer.effect( }), ) -export const defaultLayer = layer.pipe(Layer.provide(CrossSpawnSpawner.defaultLayer)) +export const defaultLayer = layer.pipe(Layer.provide(AppProcess.defaultLayer)) export * as Git from "."