@@ -41,9 +41,9 @@ export async function runDev({ docker=false } = {}) {
41
41
const cfg = JSON . parse ( fs . readFileSync ( configPath , 'utf-8' ) ) ;
42
42
const servicesDir = path . join ( cwd , 'services' ) ;
43
43
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
+ }
47
47
if ( docker ) {
48
48
console . log ( chalk . cyan ( '🛳 Starting via docker compose...' ) ) ;
49
49
const compose = spawn ( 'docker' , [ 'compose' , 'up' , '--build' ] , { stdio : 'inherit' } ) ;
@@ -53,20 +53,44 @@ export async function runDev({ docker=false } = {}) {
53
53
console . log ( chalk . cyan ( '🚀 Starting services locally (best effort)...' ) ) ;
54
54
const procs = [ ] ;
55
55
const healthPromises = [ ] ;
56
+
57
+ if ( fs . existsSync ( servicesDir ) ) {
56
58
for ( const svc of cfg . services ) {
57
59
const svcPath = path . join ( cwd , svc . path ) ;
60
+
58
61
if ( ! fs . existsSync ( svcPath ) ) continue ;
59
62
// Only auto-run node & frontend services (others require language runtime dev tasks)
60
63
if ( ! [ 'node' , 'frontend' ] . includes ( svc . type ) ) continue ;
64
+
61
65
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
+
70
94
const child = spawn ( cmd , args , { cwd : svcPath , env : { ...process . env , PORT : String ( svc . port ) } , shell : true } ) ;
71
95
procs . push ( child ) ;
72
96
child . stdout . on ( 'data' , d => process . stdout . write ( color ( `[${ svc . name } ] ` ) + d . toString ( ) ) ) ;
@@ -76,18 +100,27 @@ export async function runDev({ docker=false } = {}) {
76
100
} ) ;
77
101
// health check
78
102
const healthUrl = `http://localhost:${ svc . port } /health` ;
79
- const hp = waitForHealth ( healthUrl ) . then ( ok => {
103
+ const hp = waitForHealth ( healthUrl , 30000 ) . then ( ok => {
80
104
const msg = ok ? chalk . green ( `✔ health OK ${ svc . name } ${ healthUrl } ` ) : chalk . yellow ( `⚠ health timeout ${ svc . name } ${ healthUrl } ` ) ;
81
105
console . log ( msg ) ;
82
106
} ) ;
83
107
healthPromises . push ( hp ) ;
84
108
}
109
+ }
110
+
85
111
if ( ! procs . length ) {
86
112
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
+ }
87
117
}
88
118
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
+ }
91
124
}
92
125
93
126
function detectPM ( root ) {
0 commit comments