effect(core): track stderr truncation; polish AppProcess callers (#27353)
This commit is contained in:
@@ -31,7 +31,8 @@ export interface RunResult {
|
|||||||
readonly exitCode: number
|
readonly exitCode: number
|
||||||
readonly stdout: Buffer
|
readonly stdout: Buffer
|
||||||
readonly stderr: Buffer
|
readonly stderr: Buffer
|
||||||
readonly truncated: boolean
|
readonly stdoutTruncated: boolean
|
||||||
|
readonly stderrTruncated: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Interface = ChildProcessSpawner["Service"] & {
|
export type Interface = ChildProcessSpawner["Service"] & {
|
||||||
@@ -147,7 +148,8 @@ export const layer = Layer.effect(
|
|||||||
exitCode,
|
exitCode,
|
||||||
stdout: stdout.buffer,
|
stdout: stdout.buffer,
|
||||||
stderr: stderr.buffer,
|
stderr: stderr.buffer,
|
||||||
truncated: stdout.truncated,
|
stdoutTruncated: stdout.truncated,
|
||||||
|
stderrTruncated: stderr.truncated,
|
||||||
} satisfies RunResult
|
} satisfies RunResult
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ describe("AppProcess", () => {
|
|||||||
const result = yield* svc.run(cmd("-e", "process.stdout.write('hi\\n')"))
|
const result = yield* svc.run(cmd("-e", "process.stdout.write('hi\\n')"))
|
||||||
expect(result.exitCode).toBe(0)
|
expect(result.exitCode).toBe(0)
|
||||||
expect(result.stdout.toString("utf8")).toBe("hi\n")
|
expect(result.stdout.toString("utf8")).toBe("hi\n")
|
||||||
expect(result.truncated).toBe(false)
|
expect(result.stdoutTruncated).toBe(false)
|
||||||
|
expect(result.stderrTruncated).toBe(false)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -84,17 +85,34 @@ describe("AppProcess", () => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
it.effect(
|
it.effect(
|
||||||
"truncates output when maxOutputBytes is set",
|
"truncates stdout when maxOutputBytes is set",
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const svc = yield* AppProcess.Service
|
const svc = yield* AppProcess.Service
|
||||||
const result = yield* svc.run(cmd("-e", "process.stdout.write('0123456789')"), { maxOutputBytes: 5 })
|
const result = yield* svc.run(cmd("-e", "process.stdout.write('0123456789')"), { maxOutputBytes: 5 })
|
||||||
expect(result.exitCode).toBe(0)
|
expect(result.exitCode).toBe(0)
|
||||||
expect(result.truncated).toBe(true)
|
expect(result.stdoutTruncated).toBe(true)
|
||||||
|
expect(result.stderrTruncated).toBe(false)
|
||||||
expect(result.stdout.length).toBe(5)
|
expect(result.stdout.length).toBe(5)
|
||||||
expect(result.stdout.toString("utf8")).toBe("01234")
|
expect(result.stdout.toString("utf8")).toBe("01234")
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
it.effect(
|
||||||
|
"truncates stderr when maxErrorBytes is set",
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const svc = yield* AppProcess.Service
|
||||||
|
const result = yield* svc.run(
|
||||||
|
cmd("-e", "process.stderr.write('0123456789')"),
|
||||||
|
{ maxErrorBytes: 5 },
|
||||||
|
)
|
||||||
|
expect(result.exitCode).toBe(0)
|
||||||
|
expect(result.stdoutTruncated).toBe(false)
|
||||||
|
expect(result.stderrTruncated).toBe(true)
|
||||||
|
expect(result.stderr.length).toBe(5)
|
||||||
|
expect(result.stderr.toString("utf8")).toBe("01234")
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
it.effect(
|
it.effect(
|
||||||
"result includes command description",
|
"result includes command description",
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { InstanceState } from "@/effect/instance-state"
|
|||||||
import path from "path"
|
import path from "path"
|
||||||
import { mergeDeep } from "remeda"
|
import { mergeDeep } from "remeda"
|
||||||
import { Config } from "@/config/config"
|
import { Config } from "@/config/config"
|
||||||
|
import { errorMessage } from "@/util/error"
|
||||||
import * as Log from "@opencode-ai/core/util/log"
|
import * as Log from "@opencode-ai/core/util/log"
|
||||||
import * as Formatter from "./formatter"
|
import * as Formatter from "./formatter"
|
||||||
|
|
||||||
@@ -100,7 +101,7 @@ export const layer = Layer.effect(
|
|||||||
command: cmd,
|
command: cmd,
|
||||||
...item.environment,
|
...item.environment,
|
||||||
file: filepath,
|
file: filepath,
|
||||||
cause: error.message,
|
cause: errorMessage(error.cause ?? error),
|
||||||
})
|
})
|
||||||
return undefined
|
return undefined
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ export const layer = Layer.effect(
|
|||||||
text: () => result.stdout.toString("utf8"),
|
text: () => result.stdout.toString("utf8"),
|
||||||
stdout: result.stdout,
|
stdout: result.stdout,
|
||||||
stderr: result.stderr,
|
stderr: result.stderr,
|
||||||
truncated: result.truncated,
|
truncated: result.stdoutTruncated || result.stderrTruncated,
|
||||||
} satisfies Result
|
} satisfies Result
|
||||||
},
|
},
|
||||||
Effect.catch((err) => Effect.succeed(fail(err))),
|
Effect.catch((err) => Effect.succeed(fail(err))),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Effect, Layer, Schema, Context, Stream } from "effect"
|
import { Effect, Layer, Schema, Context, Stream } from "effect"
|
||||||
import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
||||||
import { withTransientReadRetry } from "@/util/effect-http-client"
|
import { withTransientReadRetry } from "@/util/effect-http-client"
|
||||||
|
import { errorMessage } from "@/util/error"
|
||||||
import { ChildProcess } from "effect/unstable/process"
|
import { ChildProcess } from "effect/unstable/process"
|
||||||
import { AppProcess } from "@opencode-ai/core/process"
|
import { AppProcess } from "@opencode-ai/core/process"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
@@ -124,7 +125,7 @@ export const layer: Layer.Layer<Service, never, HttpClient.HttpClient | AppProce
|
|||||||
stderr: result.stderr.toString("utf8"),
|
stderr: result.stderr.toString("utf8"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Effect.catch(() => Effect.succeed({ code: 1, stdout: "", stderr: "" })),
|
Effect.catch((err) => Effect.succeed({ code: 1, stdout: "", stderr: errorMessage(err) })),
|
||||||
)
|
)
|
||||||
|
|
||||||
const getBrewFormula = Effect.fnUntraced(function* () {
|
const getBrewFormula = Effect.fnUntraced(function* () {
|
||||||
|
|||||||
Reference in New Issue
Block a user