@@ -484,6 +484,11 @@ function parseJsonStdout<T>(label: string, stdout: string): T {
484484 if ( ! trimmed ) {
485485 throw new Error ( `${ label } produced no JSON output` ) ;
486486 }
487+ try {
488+ return JSON . parse ( trimmed ) as T ;
489+ } catch {
490+ // Fall back to the last parseable line for commands that mix logs and JSON.
491+ }
487492 const lines = trimmed . split ( / \r ? \n / ) . filter ( Boolean ) ;
488493 for ( let index = lines . length - 1 ; index >= 0 ; index -= 1 ) {
489494 try {
@@ -500,11 +505,13 @@ function runJsonCommand<T>(
500505 command : string ,
501506 args : string [ ] ,
502507 env ?: Record < string , string > ,
508+ timeoutMs ?: number ,
503509) : T {
504510 const result = spawnSync ( command , args , {
505511 cwd : rootDir ,
506512 env : { ...process . env , ...env } ,
507513 encoding : "utf8" ,
514+ timeout : timeoutMs ,
508515 } ) ;
509516 const combinedOutput = `${ result . stdout ?? "" } ${ result . stderr ?? "" } ` . trim ( ) ;
510517 writeJsonArtifact ( artifactRoot , `${ label } .command.json` , {
@@ -514,6 +521,16 @@ function runJsonCommand<T>(
514521 stdout : result . stdout ?? "" ,
515522 stderr : result . stderr ?? "" ,
516523 } ) ;
524+ if ( result . error ) {
525+ const timedOut =
526+ result . error instanceof Error &&
527+ "code" in result . error &&
528+ result . error . code === "ETIMEDOUT" ;
529+ if ( timedOut && ( result . stdout ?? "" ) . trim ( ) ) {
530+ return parseJsonStdout < T > ( label , result . stdout ?? "" ) ;
531+ }
532+ throw result . error ;
533+ }
517534 if ( result . status !== 0 ) {
518535 throw new Error (
519536 `${ label } failed with exit ${ result . status ?? 1 } ${ combinedOutput ? `\n${ combinedOutput } ` : "" } ` ,
@@ -626,6 +643,7 @@ function runVerifyChains(
626643 `--chains=${ chains . join ( "," ) } ` ,
627644 ] ,
628645 env ,
646+ 25_000 ,
629647 ) ;
630648 writeJsonArtifact ( artifactRoot , "verify-chains.json" , results ) ;
631649 return results ;
0 commit comments