@@ -7,11 +7,39 @@ import { UI } from "@/cli/ui"
77import { iife } from "@/util/iife"
88import { Log } from "@/util/log"
99import { withNetworkOptions , resolveNetworkOptions } from "@/cli/network"
10+ import type { Event } from "@opencode-ai/sdk/v2"
11+ import type { EventSource } from "./context/sdk"
1012
1113declare global {
1214 const OPENCODE_WORKER_PATH : string
1315}
1416
17+ type RpcClient = ReturnType < typeof Rpc . client < typeof rpc > >
18+
19+ function createWorkerFetch ( client : RpcClient ) : typeof fetch {
20+ const fn = async ( input : RequestInfo | URL , init ?: RequestInit ) : Promise < Response > => {
21+ const request = new Request ( input , init )
22+ const body = request . body ? await request . text ( ) : undefined
23+ const result = await client . call ( "fetch" , {
24+ url : request . url ,
25+ method : request . method ,
26+ headers : Object . fromEntries ( request . headers . entries ( ) ) ,
27+ body,
28+ } )
29+ return new Response ( result . body , {
30+ status : result . status ,
31+ headers : result . headers ,
32+ } )
33+ }
34+ return fn as typeof fetch
35+ }
36+
37+ function createEventSource ( client : RpcClient ) : EventSource {
38+ return {
39+ on : ( handler ) => client . on < Event > ( "event" , handler ) ,
40+ }
41+ }
42+
1543export const TuiThreadCommand = cmd ( {
1644 command : "$0 [project]" ,
1745 describe : "start opencode tui" ,
@@ -80,16 +108,45 @@ export const TuiThreadCommand = cmd({
80108 process . on ( "SIGUSR2" , async ( ) => {
81109 await client . call ( "reload" , undefined )
82110 } )
83- const opts = await resolveNetworkOptions ( args )
84- const server = await client . call ( "server" , opts )
111+
85112 const prompt = await iife ( async ( ) => {
86113 const piped = ! process . stdin . isTTY ? await Bun . stdin . text ( ) : undefined
87114 if ( ! args . prompt ) return piped
88115 return piped ? piped + "\n" + args . prompt : args . prompt
89116 } )
90117
118+ // Check if server should be started (port or hostname explicitly set in CLI or config)
119+ const networkOpts = await resolveNetworkOptions ( args )
120+ const shouldStartServer =
121+ process . argv . includes ( "--port" ) ||
122+ process . argv . includes ( "--hostname" ) ||
123+ process . argv . includes ( "--mdns" ) ||
124+ networkOpts . mdns ||
125+ networkOpts . port !== 0 ||
126+ networkOpts . hostname !== "127.0.0.1"
127+
128+ // Subscribe to events from worker
129+ await client . call ( "subscribe" , { directory : cwd } )
130+
131+ let url : string
132+ let customFetch : typeof fetch | undefined
133+ let events : EventSource | undefined
134+
135+ if ( shouldStartServer ) {
136+ // Start HTTP server for external access
137+ const server = await client . call ( "server" , networkOpts )
138+ url = server . url
139+ } else {
140+ // Use direct RPC communication (no HTTP)
141+ url = "http://opencode.internal"
142+ customFetch = createWorkerFetch ( client )
143+ events = createEventSource ( client )
144+ }
145+
91146 const tuiPromise = tui ( {
92- url : server . url ,
147+ url,
148+ fetch : customFetch ,
149+ events,
93150 args : {
94151 continue : args . continue ,
95152 sessionID : args . session ,
0 commit comments