ai-sdlc 0.3.0-alpha.18 → 0.3.0-alpha.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Agent Executor - Child process entry point for concurrent story execution
4
+ *
5
+ * This script is spawned as a child process by the orchestrator to execute
6
+ * a single story in isolation. It runs in its own worktree and communicates
7
+ * with the parent process via IPC.
8
+ *
9
+ * Usage: node agent-executor.js <storyId>
10
+ * Environment: AI_SDLC_STORY_ID must be set
11
+ */
12
+ export {};
13
+ //# sourceMappingURL=agent-executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-executor.d.ts","sourceRoot":"","sources":["../../src/core/agent-executor.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG"}
@@ -0,0 +1,153 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Agent Executor - Child process entry point for concurrent story execution
4
+ *
5
+ * This script is spawned as a child process by the orchestrator to execute
6
+ * a single story in isolation. It runs in its own worktree and communicates
7
+ * with the parent process via IPC.
8
+ *
9
+ * Usage: node agent-executor.js <storyId>
10
+ * Environment: AI_SDLC_STORY_ID must be set
11
+ */
12
+ /**
13
+ * Send IPC message to parent process
14
+ */
15
+ function sendToParent(message) {
16
+ if (process.send) {
17
+ process.send(message);
18
+ }
19
+ }
20
+ /**
21
+ * Send status update to parent
22
+ */
23
+ function sendStatus(storyId, status, progress) {
24
+ sendToParent({
25
+ type: 'status_update',
26
+ storyId,
27
+ timestamp: Date.now(),
28
+ payload: { progress },
29
+ });
30
+ }
31
+ /**
32
+ * Send error report to parent
33
+ */
34
+ function sendError(storyId, error) {
35
+ sendToParent({
36
+ type: 'error',
37
+ storyId,
38
+ timestamp: Date.now(),
39
+ payload: { error },
40
+ });
41
+ }
42
+ /**
43
+ * Send completion message to parent
44
+ */
45
+ function sendComplete(storyId, success, exitCode) {
46
+ sendToParent({
47
+ type: 'complete',
48
+ storyId,
49
+ timestamp: Date.now(),
50
+ payload: {
51
+ result: {
52
+ storyId,
53
+ success,
54
+ exitCode,
55
+ signal: null,
56
+ duration: Date.now() - startTime,
57
+ },
58
+ },
59
+ });
60
+ }
61
+ /**
62
+ * Handle IPC messages from parent
63
+ */
64
+ function setupIPCHandlers(storyId) {
65
+ process.on('message', (msg) => {
66
+ if (!msg || typeof msg !== 'object')
67
+ return;
68
+ const message = msg;
69
+ switch (message.type) {
70
+ case 'health_check':
71
+ // Respond to health check
72
+ sendToParent({
73
+ type: 'health_response',
74
+ storyId,
75
+ timestamp: Date.now(),
76
+ });
77
+ break;
78
+ case 'shutdown':
79
+ // Graceful shutdown requested
80
+ console.log(`[${storyId}] Received shutdown signal, exiting...`);
81
+ process.exit(0);
82
+ break;
83
+ }
84
+ });
85
+ }
86
+ /**
87
+ * Handle graceful shutdown on SIGTERM
88
+ */
89
+ function setupShutdownHandlers(storyId) {
90
+ const shutdown = (signal) => {
91
+ console.log(`[${storyId}] Received ${signal}, shutting down gracefully...`);
92
+ sendToParent({
93
+ type: 'shutdown',
94
+ storyId,
95
+ timestamp: Date.now(),
96
+ });
97
+ process.exit(0);
98
+ };
99
+ process.on('SIGTERM', () => shutdown('SIGTERM'));
100
+ process.on('SIGINT', () => shutdown('SIGINT'));
101
+ }
102
+ // Track execution start time
103
+ const startTime = Date.now();
104
+ /**
105
+ * Main entry point
106
+ */
107
+ async function main() {
108
+ // Get story ID from arguments or environment
109
+ const storyId = process.argv[2] || process.env.AI_SDLC_STORY_ID;
110
+ if (!storyId) {
111
+ console.error('Error: Story ID not provided');
112
+ console.error('Usage: node agent-executor.js <storyId>');
113
+ console.error('Or set AI_SDLC_STORY_ID environment variable');
114
+ process.exit(1);
115
+ }
116
+ // Setup IPC and shutdown handlers
117
+ setupIPCHandlers(storyId);
118
+ setupShutdownHandlers(storyId);
119
+ console.log(`[${storyId}] Agent executor started in worktree: ${process.cwd()}`);
120
+ sendStatus(storyId, 'starting');
121
+ try {
122
+ // Import and execute the run command
123
+ // This reuses the existing single-story execution logic
124
+ const { run } = await import('../cli/commands.js');
125
+ sendStatus(storyId, 'running');
126
+ // Execute the story with auto mode and no-worktree flag
127
+ // (since we're already in an isolated worktree)
128
+ await run({
129
+ story: storyId,
130
+ auto: true,
131
+ worktree: false, // --no-worktree: already in a worktree
132
+ });
133
+ // Execution succeeded
134
+ console.log(`[${storyId}] Story execution completed successfully`);
135
+ sendComplete(storyId, true, 0);
136
+ process.exit(0);
137
+ }
138
+ catch (error) {
139
+ // Execution failed
140
+ const errorMsg = error instanceof Error ? error.message : String(error);
141
+ console.error(`[${storyId}] Story execution failed:`, errorMsg);
142
+ sendError(storyId, errorMsg);
143
+ sendComplete(storyId, false, 1);
144
+ process.exit(1);
145
+ }
146
+ }
147
+ // Run main with error handling
148
+ main().catch((error) => {
149
+ console.error('Fatal error in agent executor:', error);
150
+ process.exit(1);
151
+ });
152
+ export {};
153
+ //# sourceMappingURL=agent-executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-executor.js","sourceRoot":"","sources":["../../src/core/agent-executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Multi-Process Orchestrator
3
+ *
4
+ * Manages concurrent execution of multiple stories via isolated child processes.
5
+ * Each story runs in its own git worktree with its own Node.js process.
6
+ *
7
+ * Key Features:
8
+ * - Spawns child processes with concurrency limiting
9
+ * - IPC communication for status updates and health checks
10
+ * - Graceful shutdown with SIGTERM → SIGKILL fallback
11
+ * - Error isolation (child crash doesn't affect parent or siblings)
12
+ * - Worktree lifecycle management
13
+ */
14
+ import type { ProcessOrchestratorOptions, ProcessExecutionResult, Story } from '../types/index.js';
15
+ /**
16
+ * Multi-Process Orchestrator
17
+ *
18
+ * Coordinates concurrent story execution across isolated child processes.
19
+ * Uses a manual queue pattern (similar to epic-processor) for concurrency control.
20
+ */
21
+ export declare class Orchestrator {
22
+ private options;
23
+ private children;
24
+ private results;
25
+ private shuttingDown;
26
+ private worktreeService;
27
+ private processManager;
28
+ constructor(options: ProcessOrchestratorOptions);
29
+ /**
30
+ * Execute multiple stories concurrently with concurrency limiting
31
+ */
32
+ execute(stories: Story[]): Promise<ProcessExecutionResult[]>;
33
+ /**
34
+ * Execute a single story in an isolated child process
35
+ */
36
+ private executeStory;
37
+ /**
38
+ * Spawn child process for story execution
39
+ */
40
+ private spawnChild;
41
+ /**
42
+ * Graceful shutdown: SIGTERM → wait → SIGKILL
43
+ * Note: Signal handlers are managed by ProcessManager globally
44
+ */
45
+ shutdown(): Promise<void>;
46
+ /**
47
+ * Cleanup resources
48
+ */
49
+ private cleanup;
50
+ /**
51
+ * Generate URL-safe slug from title
52
+ */
53
+ private generateSlug;
54
+ /**
55
+ * Get current execution results
56
+ */
57
+ getResults(): ProcessExecutionResult[];
58
+ /**
59
+ * Get count of active child processes
60
+ */
61
+ getActiveCount(): number;
62
+ }
63
+ //# sourceMappingURL=orchestrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/core/orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EACV,0BAA0B,EAC1B,sBAAsB,EAEtB,KAAK,EACN,MAAM,mBAAmB,CAAC;AAK3B;;;;;GAKG;AACH,qBAAa,YAAY;IAOX,OAAO,CAAC,OAAO;IAN3B,OAAO,CAAC,QAAQ,CAA4C;IAC5D,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,cAAc,CAAiB;gBAEnB,OAAO,EAAE,0BAA0B;IAOvD;;OAEG;IACG,OAAO,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,sBAAsB,EAAE,CAAC;IAyDlE;;OAEG;YACW,YAAY;IA0D1B;;OAEG;YACW,UAAU;IA2HxB;;;OAGG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IA0C/B;;OAEG;YACW,OAAO;IAOrB;;OAEG;IACH,OAAO,CAAC,YAAY;IAQpB;;OAEG;IACH,UAAU,IAAI,sBAAsB,EAAE;IAItC;;OAEG;IACH,cAAc,IAAI,MAAM;CAGzB"}
@@ -0,0 +1,320 @@
1
+ /**
2
+ * Multi-Process Orchestrator
3
+ *
4
+ * Manages concurrent execution of multiple stories via isolated child processes.
5
+ * Each story runs in its own git worktree with its own Node.js process.
6
+ *
7
+ * Key Features:
8
+ * - Spawns child processes with concurrency limiting
9
+ * - IPC communication for status updates and health checks
10
+ * - Graceful shutdown with SIGTERM → SIGKILL fallback
11
+ * - Error isolation (child crash doesn't affect parent or siblings)
12
+ * - Worktree lifecycle management
13
+ */
14
+ import { spawn } from 'child_process';
15
+ import path from 'path';
16
+ import { fileURLToPath } from 'url';
17
+ import { GitWorktreeService } from './worktree.js';
18
+ import { ProcessManager } from './process-manager.js';
19
+ import { getSdlcRoot } from './config.js';
20
+ /**
21
+ * Multi-Process Orchestrator
22
+ *
23
+ * Coordinates concurrent story execution across isolated child processes.
24
+ * Uses a manual queue pattern (similar to epic-processor) for concurrency control.
25
+ */
26
+ export class Orchestrator {
27
+ options;
28
+ children = new Map();
29
+ results = [];
30
+ shuttingDown = false;
31
+ worktreeService;
32
+ processManager;
33
+ constructor(options) {
34
+ this.options = options;
35
+ const sdlcRoot = getSdlcRoot();
36
+ const worktreeBasePath = options.worktreeBasePath || path.join(sdlcRoot, '.ai-sdlc', 'worktrees');
37
+ this.worktreeService = new GitWorktreeService(sdlcRoot, worktreeBasePath);
38
+ this.processManager = ProcessManager.getInstance();
39
+ }
40
+ /**
41
+ * Execute multiple stories concurrently with concurrency limiting
42
+ */
43
+ async execute(stories) {
44
+ if (stories.length === 0) {
45
+ return [];
46
+ }
47
+ console.log(`🚀 Starting orchestrator with ${stories.length} stories (concurrency: ${this.options.concurrency})`);
48
+ try {
49
+ // Use manual queue pattern (same as epic-processor)
50
+ const queue = [...stories];
51
+ const active = new Set();
52
+ while (queue.length > 0 || active.size > 0) {
53
+ // Fill up to maxConcurrent
54
+ while (active.size < this.options.concurrency && queue.length > 0 && !this.shuttingDown) {
55
+ const story = queue.shift();
56
+ const promise = this.executeStory(story);
57
+ active.add(promise);
58
+ // Remove from active and collect result when done
59
+ promise.then((result) => {
60
+ active.delete(promise);
61
+ this.results.push(result);
62
+ }, (error) => {
63
+ active.delete(promise);
64
+ // Error should not happen as executeStory catches all errors
65
+ console.error('Unexpected error in executeStory:', error);
66
+ });
67
+ }
68
+ if (active.size > 0) {
69
+ // Wait for at least one to complete
70
+ await Promise.race(active);
71
+ // If shutdown requested, cancel queued stories
72
+ if (this.shuttingDown) {
73
+ console.log(`⚠️ Shutdown in progress, canceling ${queue.length} queued stories`);
74
+ break;
75
+ }
76
+ }
77
+ }
78
+ // Wait for all active processes to complete
79
+ if (active.size > 0) {
80
+ await Promise.all(active);
81
+ }
82
+ return this.results;
83
+ }
84
+ finally {
85
+ await this.cleanup();
86
+ }
87
+ }
88
+ /**
89
+ * Execute a single story in an isolated child process
90
+ */
91
+ async executeStory(story) {
92
+ const storyId = story.frontmatter.id;
93
+ const startTime = Date.now();
94
+ try {
95
+ // Create worktree for story
96
+ const slug = this.generateSlug(story.frontmatter.title || storyId);
97
+ const worktreePath = this.worktreeService.getWorktreePath(storyId, slug);
98
+ console.log(`📝 [${storyId}] Creating worktree: ${worktreePath}`);
99
+ try {
100
+ this.worktreeService.create({
101
+ storyId,
102
+ slug,
103
+ baseBranch: 'main',
104
+ });
105
+ }
106
+ catch (error) {
107
+ // Worktree creation failure - skip story
108
+ const errorMsg = error instanceof Error ? error.message : String(error);
109
+ console.error(`❌ [${storyId}] Worktree creation failed: ${errorMsg}`);
110
+ return {
111
+ storyId,
112
+ success: false,
113
+ exitCode: null,
114
+ signal: null,
115
+ duration: Date.now() - startTime,
116
+ error: `Worktree creation failed: ${errorMsg}`,
117
+ };
118
+ }
119
+ // Spawn child process
120
+ const result = await this.spawnChild(storyId, worktreePath, startTime);
121
+ // Cleanup worktree if not keeping
122
+ if (!this.options.keepWorktrees) {
123
+ try {
124
+ this.worktreeService.remove(worktreePath, false);
125
+ }
126
+ catch (cleanupError) {
127
+ console.warn(`⚠️ [${storyId}] Failed to cleanup worktree: ${cleanupError}`);
128
+ }
129
+ }
130
+ return result;
131
+ }
132
+ catch (error) {
133
+ const errorMsg = error instanceof Error ? error.message : String(error);
134
+ console.error(`❌ [${storyId}] Execution failed: ${errorMsg}`);
135
+ return {
136
+ storyId,
137
+ success: false,
138
+ exitCode: null,
139
+ signal: null,
140
+ duration: Date.now() - startTime,
141
+ error: errorMsg,
142
+ };
143
+ }
144
+ }
145
+ /**
146
+ * Spawn child process for story execution
147
+ */
148
+ async spawnChild(storyId, worktreePath, startTime) {
149
+ return new Promise((resolve) => {
150
+ // Spawn agent-executor as child process entry point
151
+ // Determine the path to agent-executor (could be in dist/ or src/ depending on build state)
152
+ const currentFilePath = fileURLToPath(import.meta.url);
153
+ const agentExecutorPath = path.join(path.dirname(currentFilePath), 'agent-executor.js');
154
+ const proc = spawn(process.execPath, [agentExecutorPath, storyId], {
155
+ cwd: worktreePath,
156
+ stdio: ['ignore', 'pipe', 'pipe', 'ipc'], // Enable IPC channel
157
+ shell: false,
158
+ env: {
159
+ ...process.env,
160
+ AI_SDLC_STORY_ID: storyId,
161
+ },
162
+ });
163
+ // Track child process
164
+ if (proc.pid) {
165
+ this.children.set(storyId, {
166
+ storyId,
167
+ pid: proc.pid,
168
+ worktreePath,
169
+ startTime,
170
+ });
171
+ this.processManager.registerChild(proc);
172
+ }
173
+ // Capture stdout/stderr
174
+ let stdout = '';
175
+ let stderr = '';
176
+ proc.stdout?.on('data', (data) => {
177
+ stdout += data.toString();
178
+ // Echo to parent console with prefix
179
+ const lines = data.toString().split('\n').filter((l) => l.trim());
180
+ lines.forEach((line) => console.log(` [${storyId}] ${line}`));
181
+ });
182
+ proc.stderr?.on('data', (data) => {
183
+ stderr += data.toString();
184
+ // Echo to parent console with prefix
185
+ const lines = data.toString().split('\n').filter((l) => l.trim());
186
+ lines.forEach((line) => console.error(` [${storyId}] ${line}`));
187
+ });
188
+ // Handle IPC messages from child
189
+ proc.on('message', (msg) => {
190
+ if (!msg || typeof msg !== 'object')
191
+ return;
192
+ const message = msg;
193
+ switch (message.type) {
194
+ case 'status_update':
195
+ // Log status updates from child
196
+ console.log(` [${storyId}] Status update:`, message.payload);
197
+ break;
198
+ case 'health_response':
199
+ // Child responded to health check
200
+ console.log(` [${storyId}] Health check OK`);
201
+ break;
202
+ case 'error':
203
+ // Child reported an error
204
+ console.error(` [${storyId}] Error:`, message.payload);
205
+ break;
206
+ case 'complete':
207
+ // Child reported completion
208
+ console.log(` [${storyId}] Complete:`, message.payload);
209
+ break;
210
+ }
211
+ });
212
+ // Handle process exit
213
+ proc.on('close', (code, signal) => {
214
+ this.children.delete(storyId);
215
+ const duration = Date.now() - startTime;
216
+ const success = code === 0;
217
+ if (success) {
218
+ console.log(`✅ [${storyId}] Completed successfully (${duration}ms)`);
219
+ }
220
+ else {
221
+ console.error(`❌ [${storyId}] Failed with code ${code} (${duration}ms)`);
222
+ }
223
+ resolve({
224
+ storyId,
225
+ success,
226
+ exitCode: code,
227
+ signal,
228
+ duration,
229
+ error: success ? undefined : stderr || `Process exited with code ${code}`,
230
+ });
231
+ });
232
+ // Handle spawn errors
233
+ proc.on('error', (err) => {
234
+ this.children.delete(storyId);
235
+ console.error(`❌ [${storyId}] Process error: ${err.message}`);
236
+ resolve({
237
+ storyId,
238
+ success: false,
239
+ exitCode: null,
240
+ signal: null,
241
+ duration: Date.now() - startTime,
242
+ error: err.message,
243
+ });
244
+ });
245
+ });
246
+ }
247
+ /**
248
+ * Graceful shutdown: SIGTERM → wait → SIGKILL
249
+ * Note: Signal handlers are managed by ProcessManager globally
250
+ */
251
+ async shutdown() {
252
+ if (this.children.size === 0)
253
+ return;
254
+ console.log(`⏳ Shutting down ${this.children.size} child processes...`);
255
+ const shutdownTimeout = this.options.shutdownTimeout || 10000;
256
+ // Send SIGTERM to all children
257
+ for (const [storyId, info] of this.children.entries()) {
258
+ try {
259
+ process.kill(info.pid, 'SIGTERM');
260
+ console.log(` [${storyId}] Sent SIGTERM`);
261
+ }
262
+ catch (error) {
263
+ // Process may already be dead
264
+ }
265
+ }
266
+ // Wait for graceful shutdown
267
+ const waitStart = Date.now();
268
+ const checkInterval = 100;
269
+ while (this.children.size > 0 && Date.now() - waitStart < shutdownTimeout) {
270
+ await new Promise((resolve) => setTimeout(resolve, checkInterval));
271
+ }
272
+ // Force kill remaining processes
273
+ if (this.children.size > 0) {
274
+ console.warn(`⚠️ Force killing ${this.children.size} unresponsive processes`);
275
+ for (const [storyId, info] of this.children.entries()) {
276
+ try {
277
+ process.kill(info.pid, 'SIGKILL');
278
+ console.log(` [${storyId}] Sent SIGKILL`);
279
+ }
280
+ catch (error) {
281
+ // Process may already be dead
282
+ }
283
+ }
284
+ this.children.clear();
285
+ }
286
+ console.log('✅ All child processes terminated');
287
+ }
288
+ /**
289
+ * Cleanup resources
290
+ */
291
+ async cleanup() {
292
+ // Ensure all children are terminated
293
+ if (this.children.size > 0) {
294
+ await this.shutdown();
295
+ }
296
+ }
297
+ /**
298
+ * Generate URL-safe slug from title
299
+ */
300
+ generateSlug(title) {
301
+ return title
302
+ .toLowerCase()
303
+ .replace(/[^a-z0-9]+/g, '-')
304
+ .replace(/^-|-$/g, '')
305
+ .substring(0, 50);
306
+ }
307
+ /**
308
+ * Get current execution results
309
+ */
310
+ getResults() {
311
+ return [...this.results];
312
+ }
313
+ /**
314
+ * Get count of active child processes
315
+ */
316
+ getActiveCount() {
317
+ return this.children.size;
318
+ }
319
+ }
320
+ //# sourceMappingURL=orchestrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/core/orchestrator.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -75,6 +75,7 @@ program
75
75
  .option('--batch <story-ids>', 'Process multiple stories sequentially (comma-separated list, e.g., S-001,S-002,S-003)')
76
76
  .option('--epic <epic-id>', 'Process all stories labeled epic-{epic-id} with parallel execution (e.g., --epic ticketing matches epic-ticketing)')
77
77
  .option('--max-concurrent <n>', 'Maximum parallel stories for --epic (default: 3)', '3')
78
+ .option('--concurrent <n>', 'Run N ready stories concurrently in isolated worktrees (default: 1)', '1')
78
79
  .option('--step <phase>', 'Run a specific phase (refine, research, plan, implement, review) - cannot be combined with --auto --story')
79
80
  .option('--max-iterations <number>', 'Maximum retry iterations (default: infinite)')
80
81
  .option('--watch', 'Run in daemon mode, continuously processing backlog')
@@ -154,12 +155,36 @@ program
154
155
  console.log(c.error('Error: --clean requires --story flag'));
155
156
  process.exit(1);
156
157
  }
157
- // Validate --keep-worktrees with --epic
158
- if (options.keepWorktrees && !options.epic) {
158
+ // Validate --keep-worktrees with --epic or --concurrent
159
+ const concurrentValue = options.concurrent ? parseInt(options.concurrent, 10) : 1;
160
+ if (options.keepWorktrees && !options.epic && concurrentValue <= 1) {
159
161
  const c = getThemedChalk(config);
160
- console.log(c.error('Error: --keep-worktrees requires --epic flag'));
162
+ console.log(c.error('Error: --keep-worktrees requires --epic or --concurrent > 1 flag'));
161
163
  process.exit(1);
162
164
  }
165
+ // Validate --concurrent mutual exclusivity
166
+ if (options.concurrent && parseInt(options.concurrent, 10) > 1) {
167
+ if (options.story) {
168
+ const c = getThemedChalk(config);
169
+ console.log(c.error('Error: --concurrent cannot be used with --story'));
170
+ process.exit(1);
171
+ }
172
+ if (options.epic) {
173
+ const c = getThemedChalk(config);
174
+ console.log(c.error('Error: --concurrent cannot be used with --epic'));
175
+ process.exit(1);
176
+ }
177
+ if (options.batch) {
178
+ const c = getThemedChalk(config);
179
+ console.log(c.error('Error: --concurrent cannot be used with --batch'));
180
+ process.exit(1);
181
+ }
182
+ if (options.watch) {
183
+ const c = getThemedChalk(config);
184
+ console.log(c.error('Error: --concurrent cannot be used with --watch'));
185
+ process.exit(1);
186
+ }
187
+ }
163
188
  return run(options);
164
189
  });
165
190
  program