@@ -15,7 +15,7 @@ import type { InitStep, ServerReadyData, SqliteMigrationProgress, WslConfig } fr
1515import { checkAppExists , resolveAppPath , wslPath } from "./apps"
1616import { CHANNEL , UPDATER_ENABLED } from "./constants"
1717import { registerIpcHandlers , sendDeepLinks , sendMenuCommand , sendSqliteMigrationProgress } from "./ipc"
18- import { initLogging } from "./logging"
18+ import { exportDebugLogs , initCrashReporter , initLogging , startNetLog , write as writeLog } from "./logging"
1919import { parseMarkdown } from "./markdown"
2020import { createMenu } from "./menu"
2121import {
@@ -31,6 +31,7 @@ import {
3131 createLoadingWindow ,
3232 createMainWindow ,
3333 registerRendererProtocol ,
34+ setRelaunchHandler ,
3435 setBackgroundColor ,
3536 setDockIcon ,
3637} 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 try {
146149 setDefaultCACertificates ( [ ...new Set ( [ ...getCACertificates ( "default" ) , ...getCACertificates ( "system" ) ] ) ] )
@@ -157,6 +160,8 @@ const main = Effect.gen(function* () {
157160 ensureLoopbackNoProxy ( )
158161 useEnvProxy ( )
159162 app . commandLine . appendSwitch ( "proxy-bypass-list" , "<-loopback>" )
163+ const features = app . commandLine . getSwitchValue ( "enable-features" )
164+ app . commandLine . appendSwitch ( "enable-features" , features ? `${ jsCallStackFeature } ,${ features } ` : jsCallStackFeature )
160165 if ( ! app . isPackaged ) app . commandLine . appendSwitch ( "remote-debugging-port" , "9222" )
161166
162167 if ( ! app . requestSingleInstanceLock ( ) ) {
@@ -192,6 +197,21 @@ const main = Effect.gen(function* () {
192197 void killSidecar ( )
193198 } )
194199
200+ app . on ( "child-process-gone" , ( _event , details ) => {
201+ writeLog ( "utility" , "child process gone" , { details } , "error" )
202+ } )
203+
204+ app . on ( "render-process-gone" , ( _event , webContents , details ) => {
205+ writeLog ( "window" , "app render process gone" , { url : webContents . getURL ( ) , details } , "error" )
206+ } )
207+
208+ setRelaunchHandler ( ( ) => {
209+ void killSidecar ( ) . finally ( ( ) => {
210+ app . relaunch ( )
211+ app . exit ( 0 )
212+ } )
213+ } )
214+
195215 for ( const signal of [ "SIGINT" , "SIGTERM" ] as const ) {
196216 process . on ( signal , ( ) => {
197217 void killSidecar ( ) . finally ( ( ) => app . exit ( 0 ) )
@@ -236,6 +256,8 @@ const main = Effect.gen(function* () {
236256 checkUpdate : async ( ) => checkUpdate ( ) ,
237257 installUpdate : async ( ) => installUpdate ( killSidecar ) ,
238258 setBackgroundColor : ( color ) => setBackgroundColor ( color ) ,
259+ exportDebugLogs : ( ) => exportDebugLogs ( ) ,
260+ recordFatalRendererError : ( error ) => writeLog ( "renderer" , "fatal renderer error" , { ...error } , "error" ) ,
239261 } )
240262
241263 yield * Effect . promise ( ( ) => app . whenReady ( ) )
@@ -245,6 +267,13 @@ const main = Effect.gen(function* () {
245267 registerRendererProtocol ( )
246268 setDockIcon ( )
247269 setupAutoUpdater ( )
270+ yield * Effect . promise ( ( ) => startNetLog ( ) ) . pipe (
271+ Effect . catch ( ( error ) =>
272+ Effect . sync ( ( ) => {
273+ logger . warn ( "failed to start net log" , error )
274+ } ) ,
275+ ) ,
276+ )
248277
249278 const needsMigration = ( ( ) : boolean => {
250279 if ( process . env . OPENCODE_DB === ":memory:" ) return false
@@ -300,9 +329,9 @@ const main = Effect.gen(function* () {
300329 needsMigration,
301330 userDataPath : app . getPath ( "userData" ) ,
302331 onSqliteProgress : ( progress ) => initEmitter . emit ( "sqlite" , progress ) ,
303- onStdout : ( message ) => logger . log ( "sidecar stdout", { message } ) ,
304- onStderr : ( message ) => logger . warn ( "sidecar stderr", { message } ) ,
305- onExit : ( code ) => logger . warn ( " sidecar exited", { code } ) ,
332+ onStdout : ( message ) => writeLog ( "server" , " stdout", { message } ) ,
333+ onStderr : ( message ) => writeLog ( "server" , " stderr", { message } , "warn" ) ,
334+ onExit : ( code ) => writeLog ( "utility" , " sidecar exited", { code } , "warn" ) ,
306335 } ) ,
307336 )
308337 server = listener
0 commit comments