File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change 1+ export type FlushableWriteStream = {
2+ destroyed ?: boolean
3+ writableEnded ?: boolean
4+ write ( chunk : string , callback : ( ) => void ) : boolean
5+ }
6+
7+ export function flushWriteStream ( stream : FlushableWriteStream ) {
8+ if ( stream . destroyed || stream . writableEnded ) return Promise . resolve ( )
9+ return new Promise < void > ( ( resolve ) => {
10+ stream . write ( "" , ( ) => resolve ( ) )
11+ } )
12+ }
Original file line number Diff line number Diff line change @@ -40,6 +40,7 @@ import { Heap } from "./cli/heap"
4040import { drizzle } from "drizzle-orm/bun-sqlite"
4141import { ensureProcessMetadata } from "@opencode-ai/core/util/opencode-process"
4242import { isRecord } from "@/util/record"
43+ import { flushWriteStream } from "@/cli/stdout"
4344
4445const processMetadata = ensureProcessMetadata ( "main" )
4546
@@ -247,5 +248,6 @@ try {
247248 // Most notably, some docker-container-based MCP servers don't handle such signals unless
248249 // run using `docker run --init`.
249250 // Explicitly exit to avoid any hanging subprocesses.
251+ await Promise . all ( [ flushWriteStream ( process . stdout ) , flushWriteStream ( process . stderr ) ] )
250252 process . exit ( )
251253}
Original file line number Diff line number Diff line change 1+ import { describe , expect , test } from "bun:test"
2+ import { flushWriteStream } from "../../src/cli/stdout"
3+
4+ describe ( "flushWriteStream" , ( ) => {
5+ test ( "waits for the stream write callback" , async ( ) => {
6+ let flush : ( ( ) => void ) | undefined
7+ let resolved = false
8+
9+ const pending = flushWriteStream ( {
10+ write ( _chunk , callback ) {
11+ flush = ( ) => callback ( )
12+ return false
13+ } ,
14+ } ) . then ( ( ) => {
15+ resolved = true
16+ } )
17+
18+ await Promise . resolve ( )
19+ expect ( resolved ) . toBe ( false )
20+
21+ flush ?.( )
22+ await pending
23+
24+ expect ( resolved ) . toBe ( true )
25+ } )
26+
27+ test ( "skips destroyed streams" , async ( ) => {
28+ let wrote = false
29+
30+ await flushWriteStream ( {
31+ destroyed : true ,
32+ write ( ) {
33+ wrote = true
34+ return true
35+ } ,
36+ } )
37+
38+ expect ( wrote ) . toBe ( false )
39+ } )
40+ } )
You can’t perform that action at this time.
0 commit comments