@@ -8,8 +8,6 @@ import { getCACertificates, setDefaultCACertificates } from "node:tls"
88import type { Event } from "electron"
99import { app , BrowserWindow , dialog } from "electron"
1010import pkg from "electron-updater"
11- import { drizzle } from "drizzle-orm/node-sqlite/driver"
12- import type { Server } from "virtual:opencode-server"
1311
1412import contextMenu from "electron-context-menu"
1513contextMenu ( { showSaveImageAs : true , showLookUpSelection : false , showSearchWithGoogle : false } )
@@ -48,7 +46,15 @@ import { registerIpcHandlers, sendDeepLinks, sendMenuCommand, sendSqliteMigratio
4846import { initLogging } from "./logging"
4947import { parseMarkdown } from "./markdown"
5048import { createMenu } from "./menu"
51- import { allocatePort , getDefaultServerUrl , setDefaultServerUrl , spawnLocalServer , spawnWslSidecar } from "./server"
49+ import {
50+ allocatePort ,
51+ getDefaultServerUrl ,
52+ preferAppEnv ,
53+ setDefaultServerUrl ,
54+ spawnLocalServer ,
55+ type SidecarListener ,
56+ spawnWslSidecar ,
57+ } from "./server"
5258import { createWslServersController } from "./wsl-servers"
5359import {
5460 createLoadingWindow ,
@@ -63,7 +69,7 @@ const initEmitter = new EventEmitter()
6369let initStep : InitStep = { phase : "server_waiting" }
6470
6571let mainWindow : BrowserWindow | null = null
66- let server : Server . Listener | null = null
72+ let server : SidecarListener | null = null
6773const loadingComplete = defer < void > ( )
6874
6975const pendingDeepLinks : string [ ] = [ ]
@@ -120,6 +126,8 @@ function setupApp() {
120126 return
121127 }
122128
129+ preferAppEnv ( app . getPath ( "userData" ) )
130+
123131 app . on ( "second-instance" , ( _event : Event , argv : string [ ] ) => {
124132 const urls = argv . filter ( ( arg : string ) => arg . startsWith ( "opencode://" ) )
125133 if ( urls . length ) {
@@ -136,20 +144,19 @@ function setupApp() {
136144 } )
137145
138146 app . on ( "before-quit" , ( ) => {
139- killSidecar ( )
147+ void killSidecar ( )
140148 wslServers . stopAll ( )
141149 } )
142150
143151 app . on ( "will-quit" , ( ) => {
144- killSidecar ( )
152+ void killSidecar ( )
145153 wslServers . stopAll ( )
146154 } )
147155
148156 for ( const signal of [ "SIGINT" , "SIGTERM" ] as const ) {
149157 process . on ( signal , ( ) => {
150- killSidecar ( )
151158 wslServers . stopAll ( )
152- app . exit ( 0 )
159+ void killSidecar ( ) . finally ( ( ) => app . exit ( 0 ) )
153160 } )
154161 }
155162
@@ -216,22 +223,24 @@ async function initialize() {
216223 if ( mainWindow ) sendSqliteMigrationProgress ( mainWindow , progress )
217224 } )
218225
219- if ( needsMigration ) {
220- const { Database, JsonMigration } = await import ( "virtual:opencode-server" )
221- await JsonMigration . run ( drizzle ( { client : Database . Client ( ) . $client } ) , {
222- progress : ( event : { current : number ; total : number } ) => {
223- const percent = Math . round ( ( event . current / event . total ) * 100 )
224- initEmitter . emit ( "sqlite" , { type : "InProgress" , value : percent } )
225- } ,
226- } )
227- initEmitter . emit ( "sqlite" , { type : "Done" } )
228- }
229-
230226 logger . log ( "spawning sidecar" , { url } )
231- const { listener, health } = await spawnLocalServer ( hostname , port , password , ( ) => {
232- ensureLoopbackNoProxy ( )
233- useEnvProxy ( )
234- } )
227+ const { listener, health } = await spawnLocalServer (
228+ hostname ,
229+ port ,
230+ password ,
231+ ( ) => {
232+ ensureLoopbackNoProxy ( )
233+ useEnvProxy ( )
234+ } ,
235+ {
236+ needsMigration,
237+ userDataPath : app . getPath ( "userData" ) ,
238+ onSqliteProgress : ( progress ) => initEmitter . emit ( "sqlite" , progress ) ,
239+ onStdout : ( message ) => logger . log ( "sidecar stdout" , { message } ) ,
240+ onStderr : ( message ) => logger . warn ( "sidecar stderr" , { message } ) ,
241+ onExit : ( code ) => logger . warn ( "sidecar exited" , { code } ) ,
242+ } ,
243+ )
235244 server = listener
236245 serverReady . resolve ( {
237246 url,
@@ -333,19 +342,21 @@ registerIpcHandlers({
333342 setBackgroundColor : ( color ) => setBackgroundColor ( color ) ,
334343} )
335344
336- function killSidecar ( ) {
345+ async function killSidecar ( ) {
337346 if ( ! server ) return
338- server . stop ( )
347+ const current = server
339348 server = null
349+ await current . stop ( )
340350}
341351
342352function relaunchApp ( ) {
343353 // app.exit() skips before-quit / will-quit, so relaunch callers must
344354 // explicitly stop sidecars here rather than relying on process hooks.
345- killSidecar ( )
346355 wslServers . stopAll ( )
347- app . relaunch ( )
348- app . exit ( 0 )
356+ void killSidecar ( ) . finally ( ( ) => {
357+ app . relaunch ( )
358+ app . exit ( 0 )
359+ } )
349360}
350361
351362function ensureLoopbackNoProxy ( ) {
@@ -445,7 +456,7 @@ async function installUpdate() {
445456 logger . log ( "installing downloaded update" , {
446457 version : downloadedUpdateVersion ,
447458 } )
448- killSidecar ( )
459+ await killSidecar ( )
449460 wslServers . stopAll ( )
450461 autoUpdater . quitAndInstall ( )
451462}
0 commit comments