@@ -5,10 +5,12 @@ import { ServerAuth } from "@opencode-ai/server/auth"
55import { Context , Effect , FileSystem , Layer , Option , Schedule , Schema , Scope } from "effect"
66import { HttpServer } from "effect/unstable/http"
77import { randomBytes , randomUUID } from "crypto"
8+ import { spawn } from "node:child_process"
89import path from "path"
910
1011export interface Interface {
1112 readonly client : ( ) => Effect . Effect < ReturnType < typeof createOpencodeClient > , unknown >
13+ readonly transport : ( ) => Effect . Effect < { url : string ; headers : RequestInit [ "headers" ] } , unknown >
1214 readonly start : ( ) => Effect . Effect < string , Error >
1315 readonly status : ( ) => Effect . Effect < string | undefined >
1416 readonly stop : ( ) => Effect . Effect < void , unknown >
@@ -108,16 +110,20 @@ export const layer = Layer.effect(
108110 const start = Effect . fn ( "cli.daemon.start" ) ( function * ( ) {
109111 const existing = yield * healthy ( ) . pipe ( Effect . option )
110112 const found = Option . getOrUndefined ( existing )
111- if ( found ?. version === InstallationVersion ) return found . url
113+ const compiled = path . basename ( process . execPath ) . replace ( / \. e x e $ / , "" ) !== "bun"
114+ if ( found ?. version === InstallationVersion && compiled ) return found . url
112115 if ( found ) yield * stopProcess ( found ) . pipe ( Effect . ignore )
113116
114- yield * Effect . sync ( ( ) => {
115- const compiled = path . basename ( process . execPath ) . replace ( / \. e x e $ / , "" ) !== "bun"
116- Bun . spawn ( [ process . execPath , ...( compiled ? [ ] : [ Bun . main ] ) , "serve" , "--register" ] , {
117- stdin : "ignore" ,
118- stdout : "ignore" ,
119- stderr : "ignore" ,
120- } ) . unref ( )
117+ const entrypoint = compiled ? undefined : process . argv [ 1 ]
118+ if ( ! compiled && entrypoint === undefined ) return yield * Effect . fail ( new Error ( "Failed to resolve CLI entrypoint" ) )
119+ yield * Effect . try ( {
120+ try : ( ) => {
121+ spawn ( process . execPath , [ ...( entrypoint ? [ entrypoint ] : [ ] ) , "serve" , "--register" ] , {
122+ detached : true ,
123+ stdio : "ignore" ,
124+ } ) . unref ( )
125+ } ,
126+ catch : ( cause ) => new Error ( "Failed to start server" , { cause } ) ,
121127 } )
122128
123129 return yield * compatible ( ) . pipe (
@@ -127,8 +133,13 @@ export const layer = Layer.effect(
127133 )
128134 } )
129135
136+ const transport = Effect . fn ( "cli.daemon.transport" ) ( function * ( ) {
137+ return { url : yield * start ( ) , headers : ServerAuth . headers ( { password : yield * password ( ) } ) }
138+ } )
139+
130140 const client = Effect . fn ( "cli.daemon.client" ) ( function * ( ) {
131- return yield * createClient ( yield * start ( ) )
141+ const connection = yield * transport ( )
142+ return createOpencodeClient ( { baseUrl : connection . url , headers : connection . headers } )
132143 } )
133144
134145 const status = Effect . fn ( "cli.daemon.status" ) ( function * ( ) {
@@ -173,7 +184,7 @@ export const layer = Layer.effect(
173184 )
174185 } )
175186
176- return Service . of ( { client, start, status, stop, password, register } )
187+ return Service . of ( { client, transport , start, status, stop, password, register } )
177188 } ) ,
178189)
179190
0 commit comments