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.
- package/dist/cli/commands.d.ts +1 -0
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +47 -0
- package/dist/cli/commands.js.map +1 -1
- package/dist/core/agent-executor.d.ts +13 -0
- package/dist/core/agent-executor.d.ts.map +1 -0
- package/dist/core/agent-executor.js +153 -0
- package/dist/core/agent-executor.js.map +1 -0
- package/dist/core/orchestrator.d.ts +63 -0
- package/dist/core/orchestrator.d.ts.map +1 -0
- package/dist/core/orchestrator.js +320 -0
- package/dist/core/orchestrator.js.map +1 -0
- package/dist/index.js +28 -3
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +72 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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
|