@@ -63,9 +63,18 @@ export function logPhaseFailure(
6363 phase : ReadinessPhase ,
6464 error : unknown
6565) : void {
66- phaseReporter ( reporter , phase ) . error ( formatPhaseMessage ( phase , 'failed' ) , {
67- error : serialiseUnknown ( error ) ,
68- } ) ;
66+ const { summary, detailLines, serialized } = describeReadableError ( error ) ;
67+ const phaseLog = phaseReporter ( reporter , phase ) ;
68+ const base = formatPhaseMessage ( phase , 'failed' ) ;
69+ const headline = summary ? appendSummary ( base , summary ) : base ;
70+
71+ phaseLog . error ( headline ) ;
72+
73+ for ( const detail of detailLines ) {
74+ phaseLog . error ( ` • ${ detail } ` ) ;
75+ }
76+
77+ phaseLog . debug ( 'Failure details.' , { error : serialized } ) ;
6978}
7079
7180export function logDetectionResult (
@@ -148,3 +157,115 @@ export function serialiseUnknown(error: unknown) {
148157 } )
149158 ) ;
150159}
160+
161+ type SerializedKernelError = ReturnType < typeof serializeWPKernelError > ;
162+
163+ function describeReadableError ( error : unknown ) : {
164+ summary : string ;
165+ detailLines : string [ ] ;
166+ serialized : SerializedKernelError ;
167+ } {
168+ const serialized = serialiseUnknown ( error ) ;
169+ return {
170+ summary : buildErrorSummary ( serialized ) ,
171+ detailLines : buildErrorDetailLines ( serialized ) ,
172+ serialized,
173+ } ;
174+ }
175+
176+ function buildErrorSummary ( error : SerializedKernelError ) : string {
177+ const reason = extractReason ( error ) ;
178+ const headline = reason ?? error . code ?? error . name ;
179+ const fallback = extractString ( error . data , 'message' ) ;
180+ const message = error . message ?? fallback ?? '' ;
181+
182+ if ( headline && message ) {
183+ return `${ headline } : ${ message } ` ;
184+ }
185+
186+ return headline ?? message ?? 'Unexpected readiness failure' ;
187+ }
188+
189+ function buildErrorDetailLines ( error : SerializedKernelError ) : string [ ] {
190+ const lines : string [ ] = [ ] ;
191+ const stderrSummary = extractStringArray ( error . data , 'stderrSummary' ) ;
192+
193+ if ( stderrSummary . length > 0 ) {
194+ lines . push ( ...stderrSummary ) ;
195+ } else {
196+ const stderr = extractString ( error . data , 'stderr' ) ;
197+ if ( stderr ) {
198+ lines . push ( ...stderr . split ( / \r ? \n / u) . filter ( Boolean ) . slice ( 0 , 3 ) ) ;
199+ }
200+ }
201+
202+ const filePath = extractString ( error . data , 'filePath' ) ;
203+ if ( filePath ) {
204+ lines . push ( `file: ${ filePath } ` ) ;
205+ }
206+
207+ const manifestPath = extractString ( error . data , 'manifestPath' ) ;
208+ if ( manifestPath ) {
209+ lines . push ( `manifest: ${ manifestPath } ` ) ;
210+ }
211+
212+ const exitCode = extractNumber ( error . data , 'exitCode' ) ;
213+ if ( typeof exitCode === 'number' ) {
214+ lines . push ( `exit code: ${ exitCode } ` ) ;
215+ }
216+
217+ return lines ;
218+ }
219+
220+ function extractString (
221+ data : SerializedKernelError [ 'data' ] ,
222+ key : string
223+ ) : string | undefined {
224+ if ( ! data || typeof data !== 'object' ) {
225+ return undefined ;
226+ }
227+
228+ const value = ( data as Record < string , unknown > ) [ key ] ;
229+ return typeof value === 'string' ? value : undefined ;
230+ }
231+
232+ function extractNumber (
233+ data : SerializedKernelError [ 'data' ] ,
234+ key : string
235+ ) : number | undefined {
236+ if ( ! data || typeof data !== 'object' ) {
237+ return undefined ;
238+ }
239+
240+ const value = ( data as Record < string , unknown > ) [ key ] ;
241+ return typeof value === 'number' ? value : undefined ;
242+ }
243+
244+ function extractStringArray (
245+ data : SerializedKernelError [ 'data' ] ,
246+ key : string
247+ ) : string [ ] {
248+ if ( ! data || typeof data !== 'object' ) {
249+ return [ ] ;
250+ }
251+
252+ const value = ( data as Record < string , unknown > ) [ key ] ;
253+ if ( ! Array . isArray ( value ) ) {
254+ return [ ] ;
255+ }
256+
257+ return value
258+ . filter ( ( entry ) => typeof entry === 'string' )
259+ . map ( ( entry ) => ( entry as string ) . trim ( ) )
260+ . filter ( ( entry ) => entry . length > 0 ) ;
261+ }
262+
263+ function extractReason ( error : SerializedKernelError ) : string | undefined {
264+ const candidate = ( error as { reason ?: unknown } ) . reason ;
265+ return typeof candidate === 'string' ? candidate : undefined ;
266+ }
267+
268+ function appendSummary ( base : string , summary : string ) : string {
269+ const trimmed = base . endsWith ( '.' ) ? base . slice ( 0 , - 1 ) : base ;
270+ return `${ trimmed } : ${ summary } ` ;
271+ }
0 commit comments