mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-24 13:03:37 +00:00
fix(cli): prevent Node stdout EPIPE failures
Keep draining standalone server stdout after reading its readiness message so later server output does not write into a closed pipe. Install the Node CLI broken-pipe handler before loading the main entrypoint. Ignore only EPIPE while preserving all unrelated stdout errors. This prevents Windows Node builds from failing when the TUI prints its exit epilogue after renderer teardown.
This commit is contained in:
parent
a1b274e6f8
commit
42e2dde739
2 changed files with 18 additions and 4 deletions
|
|
@ -1,3 +1,9 @@
|
|||
import "./plugin-runtime.promise"
|
||||
import "./plugin-runtime.effect"
|
||||
import "../index"
|
||||
|
||||
process.stdout.on("error", (error) => {
|
||||
if ("code" in error && error.code === "EPIPE") return
|
||||
throw error
|
||||
})
|
||||
|
||||
await import("../index")
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Service, type Endpoint } from "@opencode-ai/client/effect/service"
|
||||
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
|
||||
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
|
||||
import { Effect, Schema, Stream } from "effect"
|
||||
import { Deferred, Effect, Schema, Stream } from "effect"
|
||||
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
|
||||
import { randomBytes } from "node:crypto"
|
||||
import { selfCommand } from "../util/process"
|
||||
|
|
@ -36,8 +36,16 @@ const makeEndpoint = Effect.fn("cli.standalone.endpoint")(
|
|||
const password = randomBytes(32).toString("base64url")
|
||||
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner
|
||||
const proc = yield* spawner.spawn(command(password, options))
|
||||
const output = yield* proc.stdout.pipe(Stream.decodeText(), Stream.splitLines, Stream.take(1), Stream.mkString)
|
||||
if (!output) return yield* Effect.fail(new Error("Standalone server exited before reporting readiness"))
|
||||
const readyLine = yield* Deferred.make<string, Error>()
|
||||
// Keep draining stdout after readiness so later server writes cannot hit EPIPE.
|
||||
yield* proc.stdout.pipe(
|
||||
Stream.decodeText(),
|
||||
Stream.splitLines,
|
||||
Stream.runForEach((line) => Deferred.succeed(readyLine, line)),
|
||||
Effect.ensuring(Deferred.fail(readyLine, new Error("Standalone server exited before reporting readiness"))),
|
||||
Effect.forkScoped,
|
||||
)
|
||||
const output = yield* Deferred.await(readyLine)
|
||||
const ready = yield* Effect.tryPromise(() => decodeReady(output))
|
||||
return {
|
||||
url: ready.url,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue