fix: gate run event traces behind --verbose

This commit is contained in:
YeonGyu-Kim 2026-02-17 14:34:22 +09:00
parent 991dcdb6c1
commit 5f5b476f12
5 changed files with 64 additions and 4 deletions

View File

@ -75,6 +75,7 @@ program
.option("--attach <url>", "Attach to existing opencode server URL")
.option("--on-complete <command>", "Shell command to run after completion")
.option("--json", "Output structured JSON result to stdout")
.option("--verbose", "Show full event stream (default: messages/tools only)")
.option("--session-id <id>", "Resume existing session instead of creating new one")
.addHelpText("after", `
Examples:
@ -114,6 +115,7 @@ Unlike 'opencode run', this command waits until:
attach: options.attach,
onComplete: options.onComplete,
json: options.json ?? false,
verbose: options.verbose ?? false,
sessionId: options.sessionId,
}
const exitCode = await run(runOptions)

View File

@ -24,11 +24,15 @@ export async function processEvents(
try {
const payload = event as EventPayload
if (!payload?.type) {
console.error(pc.dim(`[event] no type: ${JSON.stringify(event)}`))
if (ctx.verbose) {
console.error(pc.dim(`[event] no type: ${JSON.stringify(event)}`))
}
continue
}
logEventVerbose(ctx, payload)
if (ctx.verbose) {
logEventVerbose(ctx, payload)
}
handleSessionError(ctx, payload, state)
handleSessionIdle(ctx, payload, state)

View File

@ -1,4 +1,4 @@
import { describe, it, expect } from "bun:test"
import { describe, it, expect, spyOn } from "bun:test"
import { createEventState, serializeError, type EventState } from "./events"
import type { RunContext, EventPayload } from "./types"
@ -87,6 +87,52 @@ describe("createEventState", () => {
})
describe("event handling", () => {
it("does not log verbose event traces by default", async () => {
// given
const ctx = createMockContext("my-session")
const state = createEventState()
const errorSpy = spyOn(console, "error").mockImplementation(() => {})
const payload: EventPayload = {
type: "custom.event",
properties: { sessionID: "my-session" },
}
const events = toAsyncIterable([payload])
const { processEvents } = await import("./events")
// when
await processEvents(ctx, events, state)
// then
expect(errorSpy).not.toHaveBeenCalled()
errorSpy.mockRestore()
})
it("logs full event traces when verbose is enabled", async () => {
// given
const ctx = { ...createMockContext("my-session"), verbose: true }
const state = createEventState()
const errorSpy = spyOn(console, "error").mockImplementation(() => {})
const payload: EventPayload = {
type: "custom.event",
properties: { sessionID: "my-session" },
}
const events = toAsyncIterable([payload])
const { processEvents } = await import("./events")
// when
await processEvents(ctx, events, state)
// then
expect(errorSpy).toHaveBeenCalledTimes(1)
const firstCall = errorSpy.mock.calls[0]
expect(String(firstCall?.[0] ?? "")).toContain("custom.event")
errorSpy.mockRestore()
})
it("session.idle sets mainSessionIdle to true for matching session", async () => {
// given
const ctx = createMockContext("my-session")

View File

@ -84,7 +84,13 @@ export async function run(options: RunOptions): Promise<number> {
console.log(pc.dim(`Session: ${sessionID}`))
const ctx: RunContext = { client, sessionID, directory, abortController }
const ctx: RunContext = {
client,
sessionID,
directory,
abortController,
verbose: options.verbose ?? false,
}
const events = await client.event.subscribe({ query: { directory } })
const eventState = createEventState()
const eventProcessor = processEvents(ctx, events.stream, eventState).catch(

View File

@ -4,6 +4,7 @@ export type { OpencodeClient }
export interface RunOptions {
message: string
agent?: string
verbose?: boolean
directory?: string
timeout?: number
port?: number
@ -31,6 +32,7 @@ export interface RunContext {
sessionID: string
directory: string
abortController: AbortController
verbose?: boolean
}
export interface Todo {