@@ -392,5 +392,76 @@ config
392392 }
393393 } ) ;
394394
395+ // Web dashboard commands
396+ const web = program . command ( 'web' ) . alias ( 'app' ) . description ( 'Web dashboard for monitoring the job queue' ) ;
397+ web
398+ . command ( 'start' )
399+ . description ( 'Start the web dashboard (foreground by default). Use --daemon to run in background' )
400+ . option ( '-d, --daemon' , 'Run dashboard in background' )
401+ . action ( ( opts ) => {
402+ const serverScript = path . join ( __dirname , '..' , 'web' , 'server.js' ) ;
403+ if ( opts . daemon ) {
404+ try {
405+ const child = spawn ( process . execPath , [ serverScript ] , {
406+ detached : true ,
407+ stdio : 'ignore' ,
408+ cwd : process . cwd ( )
409+ } ) ;
410+ child . unref ( ) ;
411+
412+ try {
413+ const pidFile = path . join ( process . cwd ( ) , '.dashboard.pid' ) ;
414+ //writing pid to stop app afterwards
415+ fs . writeFileSync ( pidFile , String ( child . pid ) , { encoding : 'utf8' } ) ;
416+ console . log ( `[+] Dashboard started in background (pid: ${ child . pid } ). PID written to ${ pidFile } ` ) ;
417+ } catch ( e ) {
418+ console . log ( '[+] Dashboard started in background, but failed to write PID file:' , e . message ) ;
419+ }
420+ } catch ( e ) {
421+ console . error ( '[!!] Failed to start dashboard in background:' , e . message ) ;
422+ process . exit ( 1 ) ;
423+ }
424+ } else {
425+ try {
426+ console . log ( '[*] Starting dashboard (foreground). Press CTRL+C to stop.' ) ;
427+ const fg = spawn ( process . execPath , [ serverScript ] , { stdio : 'inherit' , cwd : process . cwd ( ) } ) ;
428+ fg . on ( 'exit' , ( code ) => process . exit ( code || 0 ) ) ;
429+ } catch ( e ) {
430+ console . error ( '[!!] Failed to start dashboard:' , e . message ) ;
431+ process . exit ( 1 ) ;
432+ }
433+ }
434+ } ) ;
435+
436+ web
437+ . command ( 'stop' )
438+ . description ( 'Stop a dashboard started with `web start --daemon`' )
439+ . action ( ( ) => {
440+ const pidFile = path . join ( process . cwd ( ) , '.dashboard.pid' ) ;
441+ if ( ! fs . existsSync ( pidFile ) ) {
442+ console . error ( '[!] No .dashboard.pid file found in current directory — is the dashboard running?' ) ;
443+ process . exit ( 1 ) ;
444+ }
445+ try {
446+ const text = fs . readFileSync ( pidFile , 'utf8' ) . trim ( ) ;
447+ const pid = parseInt ( text , 10 ) ;
448+ if ( isNaN ( pid ) ) throw new Error ( 'Invalid PID in pidfile' ) ;
449+ try {
450+ process . kill ( pid ) ;
451+ console . log ( `[+] Sent termination signal to dashboard pid ${ pid } .` ) ;
452+ } catch ( e ) {
453+ // if process doesn't exist, report it but remove pidfile
454+ if ( e . code === 'ESRCH' ) console . warn ( '[!] No process found with that PID — removing stale pidfile.' ) ;
455+ else throw e ;
456+ }
457+ try { fs . unlinkSync ( pidFile ) ; } catch ( e ) { }
458+ process . exit ( 0 ) ;
459+ } catch ( e ) {
460+ console . error ( '[!!] Failed to stop dashboard:' , e . message ) ;
461+ process . exit ( 1 ) ;
462+ }
463+ } ) ;
464+
395465printBanner ( ) ;
396- program . parse ( process . argv ) ;
466+ program . parse ( process . argv ) ;
467+
0 commit comments