@@ -138,6 +138,61 @@ export function createSessionStats(): SessionStats {
138138 }
139139}
140140
141+ /**
142+ * Build actionable error message with suggestions
143+ */
144+ function buildErrorMessage ( error : unknown , context : string ) : string {
145+ const errorStr = error instanceof Error ? error . message : String ( error )
146+ const suggestions : string [ ] = [ ]
147+
148+ // Provide context-specific suggestions
149+ if ( context === "init" ) {
150+ if ( errorStr . includes ( "OPENCODE_TOKEN" ) || errorStr . includes ( "token" ) ) {
151+ suggestions . push ( "Ensure OPENCODE_TOKEN environment variable is set" )
152+ suggestions . push ( "Run 'opencode' command to verify your OpenCode installation" )
153+ }
154+ if ( errorStr . includes ( "port" ) || errorStr . includes ( "already in use" ) ) {
155+ suggestions . push ( "Check if another instance of OpenCode is running" )
156+ suggestions . push ( "Try waiting a few seconds before restarting" )
157+ }
158+ } else if ( context === "session" ) {
159+ suggestions . push ( "Check your internet connection" )
160+ suggestions . push ( "Verify the OpenCode server is running and accessible" )
161+ suggestions . push ( "Try increasing cycleTimeoutMinutes in configuration" )
162+ suggestions . push ( "Check for firewall or proxy issues blocking OpenCode" )
163+ } else if ( context === "model" ) {
164+ if ( errorStr . includes ( "model" ) || errorStr . includes ( "provider" ) ) {
165+ suggestions . push (
166+ "Verify model format is 'provider/model' (e.g., 'anthropic/claude-sonnet-4')" ,
167+ )
168+ suggestions . push ( "Check that you have API access to the specified model" )
169+ suggestions . push ( "Ensure API credentials are correctly configured" )
170+ }
171+ } else if ( context === "response" ) {
172+ suggestions . push ( "Check the OpenCode server logs for detailed error information" )
173+ suggestions . push ( "Verify the prompt is well-formed and not too long" )
174+ suggestions . push ( "Try reducing verbosity to see clearer error details" )
175+ suggestions . push ( "Check .opencode/opencoder/logs/main.log for debugging information" )
176+ } else if ( context === "task" ) {
177+ suggestions . push ( "Review the task description for clarity and specificity" )
178+ suggestions . push ( "Check if the task depends on external services or files" )
179+ suggestions . push ( "Try simplifying the task or breaking it into smaller steps" )
180+ suggestions . push ( "Use ideas queue to provide more detailed task guidance" )
181+ }
182+
183+ let message = errorStr
184+
185+ // Add suggestions if available
186+ if ( suggestions . length > 0 ) {
187+ message += "\n\nSuggestions:"
188+ suggestions . forEach ( ( s , i ) => {
189+ message += `\n ${ i + 1 } . ${ s } `
190+ } )
191+ }
192+
193+ return message
194+ }
195+
141196/**
142197 * Extract contextual information from tool input for display
143198 */
@@ -403,7 +458,8 @@ export class Builder {
403458 // Start event subscription
404459 await this . subscribeToEvents ( )
405460 } catch ( err ) {
406- this . logger . logError ( `Failed to start OpenCode server: ${ err } ` )
461+ const message = buildErrorMessage ( err , "init" )
462+ this . logger . logError ( `Failed to start OpenCode server:\n${ message } ` )
407463 throw err
408464 }
409465 }
@@ -422,7 +478,8 @@ export class Builder {
422478 } )
423479
424480 if ( ! session . data ) {
425- throw new Error ( "Failed to create session" )
481+ const message = buildErrorMessage ( "Failed to create session for planning" , "session" )
482+ throw new Error ( message )
426483 }
427484
428485 this . sessionId = session . data . id
@@ -451,7 +508,8 @@ export class Builder {
451508 try {
452509 await this . ensureSession ( cycle , `Cycle ${ cycle } - Recovery` )
453510 } catch ( err ) {
454- return { success : false , error : `Failed to create session: ${ err } ` }
511+ const message = buildErrorMessage ( err , "session" )
512+ return { success : false , error : `Failed to create session:\n${ message } ` }
455513 }
456514 }
457515
@@ -461,7 +519,8 @@ export class Builder {
461519 const result = await this . sendPrompt ( prompt , this . config . buildModel , "Building" )
462520 return { success : true , output : result }
463521 } catch ( err ) {
464- return { success : false , error : String ( err ) }
522+ const message = buildErrorMessage ( err , "task" )
523+ return { success : false , error : message }
465524 }
466525 }
467526
@@ -493,7 +552,8 @@ export class Builder {
493552 } )
494553
495554 if ( ! session . data ) {
496- throw new Error ( "Failed to create session for idea selection" )
555+ const message = buildErrorMessage ( "Failed to create session for idea selection" , "session" )
556+ throw new Error ( message )
497557 }
498558
499559 const tempSessionId = session . data . id
@@ -549,7 +609,8 @@ export class Builder {
549609 */
550610 private async sendPrompt ( prompt : string , model : string , phase : string ) : Promise < string > {
551611 if ( ! this . sessionId ) {
552- throw new Error ( "No active session" )
612+ const message = buildErrorMessage ( "No active session available" , "session" )
613+ throw new Error ( message )
553614 }
554615
555616 return this . sendPromptToSession ( this . sessionId , prompt , model , phase )
@@ -583,12 +644,14 @@ export class Builder {
583644 this . logger . stopSpinner ( )
584645
585646 if ( ! result . data ) {
586- throw new Error ( "No response from OpenCode" )
647+ const message = buildErrorMessage ( "No response received from OpenCode model" , "response" )
648+ throw new Error ( message )
587649 }
588650
589651 const text = extractText ( result . data . parts as Part [ ] | undefined )
590652 if ( ! text ) {
591- throw new Error ( "Empty response from OpenCode" )
653+ const message = buildErrorMessage ( "Empty response from OpenCode model" , "response" )
654+ throw new Error ( message )
592655 }
593656
594657 return text
@@ -606,7 +669,8 @@ export class Builder {
606669 // Process events in background
607670 this . processEvents ( events . stream )
608671 } catch ( err ) {
609- this . logger . logVerbose ( `Event subscription setup: ${ err } ` )
672+ // Event subscription is best-effort and doesn't block execution
673+ this . logger . logVerbose ( `Event subscription setup (non-critical): ${ err } ` )
610674 }
611675 }
612676
@@ -682,7 +746,8 @@ export class Builder {
682746 } )
683747
684748 if ( ! session . data ) {
685- throw new Error ( "Failed to create session" )
749+ const message = buildErrorMessage ( `Failed to create session: ${ sessionTitle } ` , "session" )
750+ throw new Error ( message )
686751 }
687752
688753 this . sessionId = session . data . id
0 commit comments