@@ -41,9 +41,9 @@ export async function runDev({ docker=false } = {}) {
4141 const cfg = JSON . parse ( fs . readFileSync ( configPath , 'utf-8' ) ) ;
4242 const servicesDir = path . join ( cwd , 'services' ) ;
4343 if ( ! fs . existsSync ( servicesDir ) ) {
44- console . error ( chalk . red ( ' services/ directory not found.') ) ;
45- process . exit ( 1 ) ;
46- }
44+ console . log ( chalk . yellow ( '⚠️ services/ directory not found. No local services will be started .') ) ;
45+ //no return - continue to check cfg.services
46+ }
4747 if ( docker ) {
4848 console . log ( chalk . cyan ( '🛳 Starting via docker compose...' ) ) ;
4949 const compose = spawn ( 'docker' , [ 'compose' , 'up' , '--build' ] , { stdio : 'inherit' } ) ;
@@ -53,20 +53,44 @@ export async function runDev({ docker=false } = {}) {
5353 console . log ( chalk . cyan ( '🚀 Starting services locally (best effort)...' ) ) ;
5454 const procs = [ ] ;
5555 const healthPromises = [ ] ;
56+
57+ if ( fs . existsSync ( servicesDir ) ) {
5658 for ( const svc of cfg . services ) {
5759 const svcPath = path . join ( cwd , svc . path ) ;
60+
5861 if ( ! fs . existsSync ( svcPath ) ) continue ;
5962 // Only auto-run node & frontend services (others require language runtime dev tasks)
6063 if ( ! [ 'node' , 'frontend' ] . includes ( svc . type ) ) continue ;
64+
6165 const pkgPath = path . join ( svcPath , 'package.json' ) ;
62- if ( ! fs . existsSync ( pkgPath ) ) continue ;
63- let pkg ;
64- try { pkg = JSON . parse ( fs . readFileSync ( pkgPath , 'utf-8' ) ) ; } catch { continue ; }
65- if ( ! pkg . scripts || ! pkg . scripts . dev ) continue ;
66- const color = colorFor ( svc . name ) ;
67- const pm = detectPM ( cwd ) ;
68- const cmd = pm === 'yarn' ? 'yarn' : pm === 'pnpm' ? 'pnpm' : pm === 'bun' ? 'bun' : 'npm' ;
69- const args = pm === 'yarn' ? [ 'run' , 'dev' ] : [ 'run' , 'dev' ] ;
66+ if ( ! fs . existsSync ( pkgPath ) ) {
67+ console . log ( `Skipping ${ svc . name } (no package.json)` ) ;
68+ continue ;
69+ }
70+
71+ let pkg ;
72+ try {
73+ pkg = JSON . parse ( fs . readFileSync ( pkgPath , 'utf-8' ) ) ;
74+ } catch {
75+ console . log ( chalk . yellow ( `Skipping ${ svc . name } (invalid package.json)` ) ) ;
76+ continue ;
77+ }
78+
79+ // Determine which script to run
80+ const useScript = pkg . scripts ?. dev ? 'dev' : pkg . scripts ?. start ? 'start' : null ;
81+ if ( ! useScript ) {
82+ console . log ( chalk . yellow ( `Skipping ${ svc . name } (no "dev" or "start" script)` ) ) ;
83+ continue ;
84+ }
85+ if ( useScript === 'start' ) {
86+ console . log ( `running start instead of dev for ${ svc . name } ` ) ;
87+ }
88+
89+ const color = colorFor ( svc . name ) ;
90+ const pm = detectPM ( svcPath ) ;
91+ const cmd = pm === 'yarn' ? 'yarn' : pm === 'pnpm' ? 'pnpm' : pm === 'bun' ? 'bun' : 'npm' ;
92+ const args = [ 'run' , useScript ] ;
93+
7094 const child = spawn ( cmd , args , { cwd : svcPath , env : { ...process . env , PORT : String ( svc . port ) } , shell : true } ) ;
7195 procs . push ( child ) ;
7296 child . stdout . on ( 'data' , d => process . stdout . write ( color ( `[${ svc . name } ] ` ) + d . toString ( ) ) ) ;
@@ -76,18 +100,27 @@ export async function runDev({ docker=false } = {}) {
76100 } ) ;
77101 // health check
78102 const healthUrl = `http://localhost:${ svc . port } /health` ;
79- const hp = waitForHealth ( healthUrl ) . then ( ok => {
103+ const hp = waitForHealth ( healthUrl , 30000 ) . then ( ok => {
80104 const msg = ok ? chalk . green ( `✔ health OK ${ svc . name } ${ healthUrl } ` ) : chalk . yellow ( `⚠ health timeout ${ svc . name } ${ healthUrl } ` ) ;
81105 console . log ( msg ) ;
82106 } ) ;
83107 healthPromises . push ( hp ) ;
84108 }
109+ }
110+
85111 if ( ! procs . length ) {
86112 console . log ( chalk . yellow ( 'No auto-runnable Node/Frontend services found. Use --docker to start all via compose.' ) ) ;
113+ // ✅ FIXED: Exit cleanly when running in CI/test mode
114+ if ( process . env . CI === 'true' ) {
115+ process . exit ( 0 ) ;
116+ }
87117 }
88118 await Promise . all ( healthPromises ) ;
89- console . log ( chalk . blue ( 'Watching services. Press Ctrl+C to exit.' ) ) ;
90- process . on ( 'SIGINT' , ( ) => { procs . forEach ( p => p . kill ( 'SIGINT' ) ) ; process . exit ( 0 ) ; } ) ;
119+
120+ if ( procs . length > 0 ) {
121+ console . log ( chalk . blue ( 'Watching services. Press Ctrl+C to exit.' ) ) ;
122+ process . on ( 'SIGINT' , ( ) => { procs . forEach ( p => p . kill ( 'SIGINT' ) ) ; process . exit ( 0 ) ; } ) ;
123+ }
91124}
92125
93126function detectPM ( root ) {
0 commit comments