@@ -16,7 +16,7 @@ import type { InitStep, ServerReadyData, SqliteMigrationProgress } from "../prel
1616import { checkAppExists , resolveAppPath , wslPath } from "./apps"
1717import { CHANNEL , UPDATER_ENABLED } from "./constants"
1818import { registerIpcHandlers , sendDeepLinks , sendMenuCommand , sendSqliteMigrationProgress } from "./ipc"
19- import { initLogging } from "./logging"
19+ import { exportDebugLogs , initCrashReporter , initLogging , startNetLog , write as writeLog } from "./logging"
2020import { parseMarkdown } from "./markdown"
2121import { createMenu } from "./menu"
2222import {
@@ -32,6 +32,7 @@ import {
3232 createLoadingWindow ,
3333 createMainWindow ,
3434 registerRendererProtocol ,
35+ setRelaunchHandler ,
3536 setBackgroundColor ,
3637 setDockIcon ,
3738} from "./windows"
@@ -49,6 +50,7 @@ const APP_IDS: Record<string, string> = {
4950 prod : "ai.opencode.desktop" ,
5051}
5152const TEST_ONBOARDING = process . env . OPENCODE_TEST_ONBOARDING === "1"
53+ const jsCallStackFeature = "DocumentPolicyIncludeJSCallStacksInCrashReports"
5254
5355let logger : ReturnType < typeof initLogging >
5456let mainWindow : BrowserWindow | null = null
@@ -141,6 +143,7 @@ const main = Effect.gen(function* () {
141143 )
142144 if ( onboardingTestRoot ) app . setPath ( "sessionData" , join ( onboardingTestRoot , "session" ) )
143145 logger = initLogging ( )
146+ initCrashReporter ( )
144147
145148 const wslServers = createWslServersController (
146149 app . getVersion ( ) ,
@@ -181,6 +184,8 @@ const main = Effect.gen(function* () {
181184 ensureLoopbackNoProxy ( )
182185 useEnvProxy ( )
183186 app . commandLine . appendSwitch ( "proxy-bypass-list" , "<-loopback>" )
187+ const features = app . commandLine . getSwitchValue ( "enable-features" )
188+ app . commandLine . appendSwitch ( "enable-features" , features ? `${ jsCallStackFeature } ,${ features } ` : jsCallStackFeature )
184189 if ( ! app . isPackaged ) app . commandLine . appendSwitch ( "remote-debugging-port" , "9222" )
185190
186191 if ( ! app . requestSingleInstanceLock ( ) ) {
@@ -216,6 +221,21 @@ const main = Effect.gen(function* () {
216221 void stopSidecars ( )
217222 } )
218223
224+ app . on ( "child-process-gone" , ( _event , details ) => {
225+ writeLog ( "utility" , "child process gone" , { details } , "error" )
226+ } )
227+
228+ app . on ( "render-process-gone" , ( _event , webContents , details ) => {
229+ writeLog ( "window" , "app render process gone" , { url : webContents . getURL ( ) , details } , "error" )
230+ } )
231+
232+ setRelaunchHandler ( ( ) => {
233+ void killSidecar ( ) . finally ( ( ) => {
234+ app . relaunch ( )
235+ app . exit ( 0 )
236+ } )
237+ } )
238+
219239 for ( const signal of [ "SIGINT" , "SIGTERM" ] as const ) {
220240 process . on ( signal , ( ) => {
221241 void stopSidecars ( ) . finally ( ( ) => app . exit ( 0 ) )
@@ -272,6 +292,8 @@ const main = Effect.gen(function* () {
272292 checkUpdate : async ( ) => checkUpdate ( ) ,
273293 installUpdate : async ( ) => installUpdate ( stopSidecars ) ,
274294 setBackgroundColor : ( color ) => setBackgroundColor ( color ) ,
295+ exportDebugLogs : ( ) => exportDebugLogs ( ) ,
296+ recordFatalRendererError : ( error ) => writeLog ( "renderer" , "fatal renderer error" , { ...error } , "error" ) ,
275297 } )
276298
277299 yield * Effect . promise ( ( ) => app . whenReady ( ) )
@@ -281,6 +303,13 @@ const main = Effect.gen(function* () {
281303 registerRendererProtocol ( )
282304 setDockIcon ( )
283305 setupAutoUpdater ( )
306+ yield * Effect . promise ( ( ) => startNetLog ( ) ) . pipe (
307+ Effect . catch ( ( error ) =>
308+ Effect . sync ( ( ) => {
309+ logger . warn ( "failed to start net log" , error )
310+ } ) ,
311+ ) ,
312+ )
284313
285314 const needsMigration = ( ( ) : boolean => {
286315 if ( process . env . OPENCODE_DB === ":memory:" ) return false
@@ -336,9 +365,9 @@ const main = Effect.gen(function* () {
336365 needsMigration,
337366 userDataPath : app . getPath ( "userData" ) ,
338367 onSqliteProgress : ( progress ) => initEmitter . emit ( "sqlite" , progress ) ,
339- onStdout : ( message ) => logger . log ( "sidecar stdout", { message } ) ,
340- onStderr : ( message ) => logger . warn ( "sidecar stderr", { message } ) ,
341- onExit : ( code ) => logger . warn ( " sidecar exited", { code } ) ,
368+ onStdout : ( message ) => writeLog ( "server" , " stdout", { message } ) ,
369+ onStderr : ( message ) => writeLog ( "server" , " stderr", { message } , "warn" ) ,
370+ onExit : ( code ) => writeLog ( "utility" , " sidecar exited", { code } , "warn" ) ,
342371 } ) ,
343372 )
344373 server = listener
@@ -391,6 +420,9 @@ const main = Effect.gen(function* () {
391420 } ,
392421 reload : ( ) => mainWindow ?. reload ( ) ,
393422 relaunch,
423+ exportDebugLogs : ( ) => {
424+ void exportDebugLogs ( ) . catch ( ( error ) => logger . error ( "failed to export debug logs" , error ) )
425+ } ,
394426 } )
395427 }
396428
0 commit comments