@supaku/agentfactory-cli 0.2.0 → 0.4.0
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/src/analyze-logs.d.ts +2 -2
- package/dist/src/analyze-logs.js +23 -194
- package/dist/src/cleanup.d.ts +2 -6
- package/dist/src/cleanup.d.ts.map +1 -1
- package/dist/src/cleanup.js +24 -225
- package/dist/src/lib/analyze-logs-runner.d.ts +47 -0
- package/dist/src/lib/analyze-logs-runner.d.ts.map +1 -0
- package/dist/src/lib/analyze-logs-runner.js +216 -0
- package/dist/src/lib/cleanup-runner.d.ts +28 -0
- package/dist/src/lib/cleanup-runner.d.ts.map +1 -0
- package/dist/src/lib/cleanup-runner.js +224 -0
- package/dist/src/lib/orchestrator-runner.d.ts +45 -0
- package/dist/src/lib/orchestrator-runner.d.ts.map +1 -0
- package/dist/src/lib/orchestrator-runner.js +144 -0
- package/dist/src/lib/queue-admin-runner.d.ts +30 -0
- package/dist/src/lib/queue-admin-runner.d.ts.map +1 -0
- package/dist/src/lib/queue-admin-runner.js +378 -0
- package/dist/src/lib/worker-fleet-runner.d.ts +28 -0
- package/dist/src/lib/worker-fleet-runner.d.ts.map +1 -0
- package/dist/src/lib/worker-fleet-runner.js +224 -0
- package/dist/src/lib/worker-runner.d.ts +31 -0
- package/dist/src/lib/worker-runner.d.ts.map +1 -0
- package/dist/src/lib/worker-runner.js +735 -0
- package/dist/src/orchestrator.d.ts +1 -1
- package/dist/src/orchestrator.js +42 -106
- package/dist/src/queue-admin.d.ts +3 -2
- package/dist/src/queue-admin.d.ts.map +1 -1
- package/dist/src/queue-admin.js +38 -360
- package/dist/src/worker-fleet.d.ts +1 -1
- package/dist/src/worker-fleet.js +23 -162
- package/dist/src/worker.d.ts +1 -0
- package/dist/src/worker.d.ts.map +1 -1
- package/dist/src/worker.js +33 -702
- package/package.json +28 -4
package/dist/src/worker-fleet.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* AgentFactory Worker Fleet Manager
|
|
4
4
|
*
|
|
5
5
|
* Spawns and manages multiple worker processes for parallel agent execution.
|
|
6
|
-
*
|
|
6
|
+
* Thin wrapper around the programmatic runner in ./lib/worker-fleet-runner.js.
|
|
7
7
|
*
|
|
8
8
|
* Usage:
|
|
9
9
|
* af-worker-fleet [options]
|
|
@@ -19,38 +19,24 @@
|
|
|
19
19
|
* WORKER_API_URL Coordinator API URL (required)
|
|
20
20
|
* WORKER_API_KEY API key for authentication (required)
|
|
21
21
|
*/
|
|
22
|
-
import { spawn } from 'child_process';
|
|
23
|
-
import os from 'os';
|
|
24
22
|
import path from 'path';
|
|
25
|
-
import
|
|
23
|
+
import os from 'os';
|
|
26
24
|
import { config as loadEnv } from 'dotenv';
|
|
27
25
|
// Load environment variables from .env.local in CWD
|
|
28
26
|
loadEnv({ path: path.resolve(process.cwd(), '.env.local') });
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const __dirname = path.dirname(__filename);
|
|
32
|
-
// ANSI colors
|
|
27
|
+
import { runWorkerFleet } from './lib/worker-fleet-runner.js';
|
|
28
|
+
// ANSI colors (kept for help output)
|
|
33
29
|
const colors = {
|
|
34
30
|
reset: '\x1b[0m',
|
|
35
31
|
red: '\x1b[31m',
|
|
36
32
|
green: '\x1b[32m',
|
|
37
33
|
yellow: '\x1b[33m',
|
|
38
|
-
blue: '\x1b[34m',
|
|
39
|
-
magenta: '\x1b[35m',
|
|
40
34
|
cyan: '\x1b[36m',
|
|
41
|
-
gray: '\x1b[90m',
|
|
42
35
|
};
|
|
43
|
-
// Worker color cycling
|
|
44
|
-
const workerColors = [
|
|
45
|
-
colors.cyan,
|
|
46
|
-
colors.magenta,
|
|
47
|
-
colors.yellow,
|
|
48
|
-
colors.green,
|
|
49
|
-
colors.blue,
|
|
50
|
-
];
|
|
51
36
|
function parseArgs() {
|
|
52
37
|
const args = process.argv.slice(2);
|
|
53
|
-
let workers = parseInt(process.env.WORKER_FLEET_SIZE ?? '0', 10) ||
|
|
38
|
+
let workers = parseInt(process.env.WORKER_FLEET_SIZE ?? '0', 10) ||
|
|
39
|
+
Math.max(1, Math.floor(os.cpus().length / 2));
|
|
54
40
|
let capacity = parseInt(process.env.WORKER_CAPACITY ?? '3', 10);
|
|
55
41
|
let dryRun = false;
|
|
56
42
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -101,146 +87,8 @@ ${colors.yellow}System Info:${colors.reset}
|
|
|
101
87
|
Free RAM: ${Math.round(os.freemem() / 1024 / 1024 / 1024)} GB
|
|
102
88
|
`);
|
|
103
89
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
function fleetLog(workerId, color, level, message) {
|
|
108
|
-
const prefix = workerId !== null ? `[W${workerId.toString().padStart(2, '0')}]` : '[FLEET]';
|
|
109
|
-
const levelColor = level === 'ERR' ? colors.red : level === 'WRN' ? colors.yellow : colors.gray;
|
|
110
|
-
console.log(`${colors.gray}${timestamp()}${colors.reset} ${color}${prefix}${colors.reset} ${levelColor}${level}${colors.reset} ${message}`);
|
|
111
|
-
}
|
|
112
|
-
class WorkerFleet {
|
|
113
|
-
workers = new Map();
|
|
114
|
-
fleetConfig;
|
|
115
|
-
shuttingDown = false;
|
|
116
|
-
workerScript;
|
|
117
|
-
constructor(fleetConfig) {
|
|
118
|
-
this.fleetConfig = fleetConfig;
|
|
119
|
-
// Use the compiled worker.js in the same directory
|
|
120
|
-
this.workerScript = path.resolve(__dirname, 'worker.js');
|
|
121
|
-
}
|
|
122
|
-
async start() {
|
|
123
|
-
const { workers, capacity, dryRun } = this.fleetConfig;
|
|
124
|
-
const totalCapacity = workers * capacity;
|
|
125
|
-
console.log(`
|
|
126
|
-
${colors.cyan}================================================================${colors.reset}
|
|
127
|
-
${colors.cyan} AgentFactory Worker Fleet Manager${colors.reset}
|
|
128
|
-
${colors.cyan}================================================================${colors.reset}
|
|
129
|
-
Workers: ${colors.green}${workers}${colors.reset}
|
|
130
|
-
Capacity/Worker: ${colors.green}${capacity}${colors.reset}
|
|
131
|
-
Total Capacity: ${colors.green}${totalCapacity}${colors.reset} concurrent agents
|
|
132
|
-
|
|
133
|
-
System:
|
|
134
|
-
CPU Cores: ${os.cpus().length}
|
|
135
|
-
Total RAM: ${Math.round(os.totalmem() / 1024 / 1024 / 1024)} GB
|
|
136
|
-
Free RAM: ${Math.round(os.freemem() / 1024 / 1024 / 1024)} GB
|
|
137
|
-
${colors.cyan}================================================================${colors.reset}
|
|
138
|
-
`);
|
|
139
|
-
if (dryRun) {
|
|
140
|
-
console.log(`${colors.yellow}Dry run mode - not starting workers${colors.reset}`);
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
// Set up shutdown handlers
|
|
144
|
-
process.on('SIGINT', () => this.shutdown('SIGINT'));
|
|
145
|
-
process.on('SIGTERM', () => this.shutdown('SIGTERM'));
|
|
146
|
-
// Spawn workers with staggered start to avoid thundering herd
|
|
147
|
-
for (let i = 0; i < workers; i++) {
|
|
148
|
-
await this.spawnWorker(i);
|
|
149
|
-
if (i < workers - 1) {
|
|
150
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
fleetLog(null, colors.green, 'INF', `All ${workers} workers started`);
|
|
154
|
-
// Keep the fleet manager running
|
|
155
|
-
await new Promise(() => { });
|
|
156
|
-
}
|
|
157
|
-
async spawnWorker(id) {
|
|
158
|
-
const color = workerColors[id % workerColors.length];
|
|
159
|
-
const existingWorker = this.workers.get(id);
|
|
160
|
-
const restartCount = existingWorker?.restartCount ?? 0;
|
|
161
|
-
fleetLog(id, color, 'INF', `Starting worker (capacity: ${this.fleetConfig.capacity})${restartCount > 0 ? ` [restart #${restartCount}]` : ''}`);
|
|
162
|
-
const workerProcess = spawn('node', [this.workerScript, '--capacity', String(this.fleetConfig.capacity)], {
|
|
163
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
164
|
-
env: {
|
|
165
|
-
...process.env,
|
|
166
|
-
WORKER_FLEET_ID: String(id),
|
|
167
|
-
},
|
|
168
|
-
cwd: process.cwd(),
|
|
169
|
-
});
|
|
170
|
-
const workerInfo = {
|
|
171
|
-
id,
|
|
172
|
-
process: workerProcess,
|
|
173
|
-
color,
|
|
174
|
-
startedAt: new Date(),
|
|
175
|
-
restartCount,
|
|
176
|
-
};
|
|
177
|
-
this.workers.set(id, workerInfo);
|
|
178
|
-
// Handle stdout - prefix with worker ID
|
|
179
|
-
workerProcess.stdout?.on('data', (data) => {
|
|
180
|
-
const lines = data.toString().trim().split('\n');
|
|
181
|
-
for (const line of lines) {
|
|
182
|
-
if (line.trim()) {
|
|
183
|
-
console.log(`${color}[W${id.toString().padStart(2, '0')}]${colors.reset} ${line}`);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
|
-
// Handle stderr
|
|
188
|
-
workerProcess.stderr?.on('data', (data) => {
|
|
189
|
-
const lines = data.toString().trim().split('\n');
|
|
190
|
-
for (const line of lines) {
|
|
191
|
-
if (line.trim()) {
|
|
192
|
-
console.log(`${color}[W${id.toString().padStart(2, '0')}]${colors.reset} ${colors.red}${line}${colors.reset}`);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
// Handle worker exit
|
|
197
|
-
workerProcess.on('exit', (code, signal) => {
|
|
198
|
-
if (this.shuttingDown) {
|
|
199
|
-
fleetLog(id, color, 'INF', `Worker stopped (code: ${code}, signal: ${signal})`);
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
fleetLog(id, color, 'WRN', `Worker exited unexpectedly (code: ${code}, signal: ${signal}) - restarting in 5s`);
|
|
203
|
-
const worker = this.workers.get(id);
|
|
204
|
-
if (worker) {
|
|
205
|
-
worker.restartCount++;
|
|
206
|
-
}
|
|
207
|
-
setTimeout(() => {
|
|
208
|
-
if (!this.shuttingDown) {
|
|
209
|
-
this.spawnWorker(id);
|
|
210
|
-
}
|
|
211
|
-
}, 5000);
|
|
212
|
-
});
|
|
213
|
-
workerProcess.on('error', (err) => {
|
|
214
|
-
fleetLog(id, color, 'ERR', `Worker error: ${err.message}`);
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
async shutdown(signal) {
|
|
218
|
-
if (this.shuttingDown)
|
|
219
|
-
return;
|
|
220
|
-
this.shuttingDown = true;
|
|
221
|
-
console.log(`\n${colors.yellow}Received ${signal} - shutting down fleet...${colors.reset}`);
|
|
222
|
-
for (const [id, worker] of this.workers) {
|
|
223
|
-
fleetLog(id, worker.color, 'INF', 'Stopping worker...');
|
|
224
|
-
worker.process.kill('SIGTERM');
|
|
225
|
-
}
|
|
226
|
-
// Wait for workers to exit (max 30 seconds)
|
|
227
|
-
const timeout = setTimeout(() => {
|
|
228
|
-
console.log(`${colors.red}Timeout waiting for workers - force killing${colors.reset}`);
|
|
229
|
-
for (const worker of this.workers.values()) {
|
|
230
|
-
worker.process.kill('SIGKILL');
|
|
231
|
-
}
|
|
232
|
-
process.exit(1);
|
|
233
|
-
}, 30000);
|
|
234
|
-
await Promise.all(Array.from(this.workers.values()).map((worker) => new Promise((resolve) => {
|
|
235
|
-
worker.process.on('exit', () => resolve());
|
|
236
|
-
})));
|
|
237
|
-
clearTimeout(timeout);
|
|
238
|
-
console.log(`${colors.green}All workers stopped${colors.reset}`);
|
|
239
|
-
process.exit(0);
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
// Main
|
|
243
|
-
const fleetConfig = parseArgs();
|
|
90
|
+
// --- Main ---
|
|
91
|
+
const fleetArgs = parseArgs();
|
|
244
92
|
if (!process.env.WORKER_API_URL) {
|
|
245
93
|
console.error(`${colors.red}Error: WORKER_API_URL environment variable is required${colors.reset}`);
|
|
246
94
|
process.exit(1);
|
|
@@ -249,8 +97,21 @@ if (!process.env.WORKER_API_KEY) {
|
|
|
249
97
|
console.error(`${colors.red}Error: WORKER_API_KEY environment variable is required${colors.reset}`);
|
|
250
98
|
process.exit(1);
|
|
251
99
|
}
|
|
252
|
-
|
|
253
|
-
|
|
100
|
+
// Create AbortController for graceful shutdown
|
|
101
|
+
const controller = new AbortController();
|
|
102
|
+
process.on('SIGINT', () => controller.abort());
|
|
103
|
+
process.on('SIGTERM', () => controller.abort());
|
|
104
|
+
runWorkerFleet({
|
|
105
|
+
workers: fleetArgs.workers,
|
|
106
|
+
capacity: fleetArgs.capacity,
|
|
107
|
+
dryRun: fleetArgs.dryRun,
|
|
108
|
+
apiUrl: process.env.WORKER_API_URL,
|
|
109
|
+
apiKey: process.env.WORKER_API_KEY,
|
|
110
|
+
}, controller.signal)
|
|
111
|
+
.then(() => {
|
|
112
|
+
process.exit(0);
|
|
113
|
+
})
|
|
114
|
+
.catch((err) => {
|
|
254
115
|
console.error(`${colors.red}Fleet error: ${err instanceof Error ? err.message : String(err)}${colors.reset}`);
|
|
255
116
|
process.exit(1);
|
|
256
117
|
});
|
package/dist/src/worker.d.ts
CHANGED
package/dist/src/worker.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/worker.ts"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/worker.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;GAoBG"}
|