fix(cli): preserve stats server errors (#44685)

This commit is contained in:
Shoubhit Dash 2026-08-24 18:11:46 +05:30 committed by GitHub
parent 11e2bde399
commit 0a60910208
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 29 additions and 5 deletions

View file

@ -1,4 +1,4 @@
import { OpenCode, type SessionStatsInfo } from "@opencode-ai/client"
import { ClientError, OpenCode, type SessionStatsInfo } from "@opencode-ai/client"
import { Service } from "@opencode-ai/client/effect/service"
import { Effect, Option } from "effect"
import { EOL } from "node:os"
@ -67,10 +67,13 @@ export default Runtime.handler(Commands.commands.stats, (input) =>
),
)
function request<A>(url: string, run: (signal: AbortSignal) => Promise<A>) {
export function request<A>(url: string, run: (signal: AbortSignal) => Promise<A>) {
return Effect.tryPromise({
try: () => run(AbortSignal.timeout(30_000)),
catch: (cause) => new Error(`Could not reach server at ${url}`, { cause }),
catch: (cause) =>
cause instanceof ClientError && cause.reason === "Transport"
? new Error(`Could not reach server at ${url}`, { cause })
: cause,
})
}

View file

@ -1,6 +1,7 @@
import { describe, expect, test } from "bun:test"
import type { SessionStatsInfo } from "@opencode-ai/client"
import { renderStats } from "../src/commands/handlers/stats"
import { ClientError, type SessionStatsInfo } from "@opencode-ai/client"
import { Effect } from "effect"
import { renderStats, request } from "../src/commands/handlers/stats"
const tools = {
mode: "detail",
@ -121,6 +122,26 @@ describe("stats rendering", () => {
})
})
describe("stats requests", () => {
test("maps transport failures to the server URL", async () => {
const cause = new ClientError("Transport")
const error = await Effect.runPromise(Effect.flip(request("http://localhost:4096", () => Promise.reject(cause))))
expect(error).toEqual(new Error("Could not reach server at http://localhost:4096", { cause }))
})
test("preserves declared API errors", async () => {
const cause = { _tag: "InvalidRequestError", message: "Stats range must end after it starts" } as const
const error = await Effect.runPromise(Effect.flip(request("http://localhost:4096", () => Promise.reject(cause))))
expect(error).toBe(cause)
})
test("preserves unexpected response failures", async () => {
const cause = new ClientError("UnexpectedStatus", { cause: { status: 500 } })
const error = await Effect.runPromise(Effect.flip(request("http://localhost:4096", () => Promise.reject(cause))))
expect(error).toBe(cause)
})
})
function options(input: Partial<Parameters<typeof renderStats>[1]> = {}): Parameters<typeof renderStats>[1] {
return {
label: "2026 so far",