@@ -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+ spawnWslSidecar ,
56+ type SidecarListener ,
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,21 @@ 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 ( )
151- wslServers . stopAll ( )
152- app . exit ( 0 )
158+ void killSidecar ( ) . finally ( ( ) => {
159+ wslServers . stopAll ( )
160+ app . exit ( 0 )
161+ } )
153162 } )
154163 }
155164
@@ -215,23 +224,24 @@ async function initialize() {
215224 if ( overlay ) sendSqliteMigrationProgress ( overlay , progress )
216225 if ( mainWindow ) sendSqliteMigrationProgress ( mainWindow , progress )
217226 } )
218-
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-
230227 logger . log ( "spawning sidecar" , { url } )
231- const { listener, health } = await spawnLocalServer ( hostname , port , password , ( ) => {
232- ensureLoopbackNoProxy ( )
233- useEnvProxy ( )
234- } )
228+ const { listener, health } = await spawnLocalServer (
229+ hostname ,
230+ port ,
231+ password ,
232+ ( ) => {
233+ ensureLoopbackNoProxy ( )
234+ useEnvProxy ( )
235+ } ,
236+ {
237+ needsMigration,
238+ userDataPath : app . getPath ( "userData" ) ,
239+ onSqliteProgress : ( progress ) => initEmitter . emit ( "sqlite" , progress ) ,
240+ onStdout : ( message ) => logger . log ( "sidecar stdout" , { message } ) ,
241+ onStderr : ( message ) => logger . warn ( "sidecar stderr" , { message } ) ,
242+ onExit : ( code ) => logger . warn ( "sidecar exited" , { code } ) ,
243+ } ,
244+ )
235245 server = listener
236246 serverReady . resolve ( {
237247 url,
@@ -333,19 +343,21 @@ registerIpcHandlers({
333343 setBackgroundColor : ( color ) => setBackgroundColor ( color ) ,
334344} )
335345
336- function killSidecar ( ) {
346+ async function killSidecar ( ) {
337347 if ( ! server ) return
338- server . stop ( )
348+ const current = server
339349 server = null
350+ await current . stop ( )
340351}
341352
342353function relaunchApp ( ) {
343354 // app.exit() skips before-quit / will-quit, so relaunch callers must
344355 // explicitly stop sidecars here rather than relying on process hooks.
345- killSidecar ( )
346- wslServers . stopAll ( )
347- app . relaunch ( )
348- app . exit ( 0 )
356+ void killSidecar ( ) . finally ( ( ) => {
357+ wslServers . stopAll ( )
358+ app . relaunch ( )
359+ app . exit ( 0 )
360+ } )
349361}
350362
351363function ensureLoopbackNoProxy ( ) {
@@ -445,7 +457,7 @@ async function installUpdate() {
445457 logger . log ( "installing downloaded update" , {
446458 version : downloadedUpdateVersion ,
447459 } )
448- killSidecar ( )
460+ await killSidecar ( )
449461 wslServers . stopAll ( )
450462 autoUpdater . quitAndInstall ( )
451463}
0 commit comments