Bug Report
When using opencode run in non-interactive mode, the output is truncated after step_start. The assistant response text and step_finish event are never emitted.
This affects all output formats (JSON, plain text, etc.) — not just --format json. The core issue is that the event subscription is fire-and-forget and the process exits before events finish flowing through.
Steps to Reproduce
bun opencode run "What is 2+2?" --format json
Expected Output
All events should be emitted:
text - user message
step_start - step initiated
text - assistant response
step_finish - step completed
Actual Output
Only text (user message) and step_start are emitted. The process exits before emitting:
- The assistant response
text event
- The
step_finish event
Root Cause
In commit eab329d0de (fix(run): restore non-interactive exit behavior #27371), the loop function was changed from await completed to fire-and-forget.
Before (correct):
const completed = loop(client, events)
await client.session.prompt({...})
const error = await completed // waits for event loop to finish
After (broken):
loop(client, events).catch(...) // fire-and-forget
await client.session.prompt({...})
return // process exits before cleanup events emit
The event subscription runs asynchronously. When prompt returns and the function exits, the SSE subscription hasn't finished emitting the remaining events (assistant text stream, step-finish). The process terminates, truncating the output.
Why It Doesn't Affect Interactive Mode
Interactive mode (opencode run "message" without --format json) keeps the TUI/CLI alive until the user exits. Events continue to flow as long as the process is running. Non-interactive mode exits immediately after prompt returns.
Impact
- Programmatic output broken: Any consumer of
opencode run stdout gets an incomplete response
- Sessions appear hung: Users see the assistant appear to not respond
- Tool calls silently dropped: Tool execution events after
step_start are never emitted
Proposed Fix
Either:
- Revert the loop to be awaited (like before commit eab329d), or
- Add a mechanism to wait for session idle before exiting (e.g., polling
session.status() until idle, then a short delay for SSE cleanup)
Bug Report
When using
opencode runin non-interactive mode, the output is truncated afterstep_start. The assistant response text andstep_finishevent are never emitted.This affects all output formats (JSON, plain text, etc.) — not just
--format json. The core issue is that the event subscription is fire-and-forget and the process exits before events finish flowing through.Steps to Reproduce
bun opencode run "What is 2+2?" --format jsonExpected Output
All events should be emitted:
text- user messagestep_start- step initiatedtext- assistant responsestep_finish- step completedActual Output
Only
text(user message) andstep_startare emitted. The process exits before emitting:texteventstep_finisheventRoot Cause
In commit
eab329d0de(fix(run): restore non-interactive exit behavior #27371), theloopfunction was changed fromawait completedto fire-and-forget.Before (correct):
After (broken):
The event subscription runs asynchronously. When
promptreturns and the function exits, the SSE subscription hasn't finished emitting the remaining events (assistant text stream, step-finish). The process terminates, truncating the output.Why It Doesn't Affect Interactive Mode
Interactive mode (
opencode run "message"without--format json) keeps the TUI/CLI alive until the user exits. Events continue to flow as long as the process is running. Non-interactive mode exits immediately afterpromptreturns.Impact
opencode runstdout gets an incomplete responsestep_startare never emittedProposed Fix
Either:
session.status()until idle, then a short delay for SSE cleanup)