@itz4blitz/agentful 1.2.0 → 1.3.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/README.md +28 -1
- package/bin/cli.js +11 -1055
- package/bin/hooks/block-file-creation.js +271 -0
- package/bin/hooks/product-spec-watcher.js +151 -0
- package/lib/index.js +0 -11
- package/lib/init.js +2 -21
- package/lib/parallel-execution.js +235 -0
- package/lib/presets.js +26 -4
- package/package.json +4 -7
- package/template/.claude/agents/architect.md +2 -2
- package/template/.claude/agents/backend.md +17 -30
- package/template/.claude/agents/frontend.md +17 -39
- package/template/.claude/agents/orchestrator.md +63 -4
- package/template/.claude/agents/product-analyzer.md +1 -1
- package/template/.claude/agents/tester.md +16 -29
- package/template/.claude/commands/agentful-generate.md +221 -14
- package/template/.claude/commands/agentful-init.md +621 -0
- package/template/.claude/commands/agentful-product.md +1 -1
- package/template/.claude/commands/agentful-start.md +99 -1
- package/template/.claude/product/EXAMPLES.md +2 -2
- package/template/.claude/product/index.md +1 -1
- package/template/.claude/settings.json +22 -0
- package/template/.claude/skills/research/SKILL.md +432 -0
- package/template/CLAUDE.md +5 -6
- package/template/bin/hooks/architect-drift-detector.js +242 -0
- package/template/bin/hooks/product-spec-watcher.js +151 -0
- package/version.json +1 -1
- package/bin/hooks/post-agent.js +0 -101
- package/bin/hooks/post-feature.js +0 -227
- package/bin/hooks/pre-agent.js +0 -118
- package/bin/hooks/pre-feature.js +0 -138
- package/lib/VALIDATION_README.md +0 -455
- package/lib/ci/claude-action-integration.js +0 -641
- package/lib/ci/index.js +0 -10
- package/lib/core/analyzer.js +0 -497
- package/lib/core/cli.js +0 -141
- package/lib/core/detectors/conventions.js +0 -342
- package/lib/core/detectors/framework.js +0 -276
- package/lib/core/detectors/index.js +0 -15
- package/lib/core/detectors/language.js +0 -199
- package/lib/core/detectors/patterns.js +0 -356
- package/lib/core/generator.js +0 -626
- package/lib/core/index.js +0 -9
- package/lib/core/output-parser.js +0 -458
- package/lib/core/storage.js +0 -515
- package/lib/core/templates.js +0 -556
- package/lib/pipeline/cli.js +0 -423
- package/lib/pipeline/engine.js +0 -928
- package/lib/pipeline/executor.js +0 -440
- package/lib/pipeline/index.js +0 -33
- package/lib/pipeline/integrations.js +0 -559
- package/lib/pipeline/schemas.js +0 -288
- package/lib/remote/client.js +0 -361
- package/lib/server/auth.js +0 -270
- package/lib/server/client-example.js +0 -190
- package/lib/server/executor.js +0 -477
- package/lib/server/index.js +0 -494
- package/lib/update-helpers.js +0 -505
- package/lib/validation.js +0 -460
package/lib/pipeline/cli.js
DELETED
|
@@ -1,423 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import fs from 'fs/promises';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import { PipelineEngine } from './engine.js';
|
|
6
|
-
import { AgentExecutor } from './executor.js';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Pipeline CLI
|
|
10
|
-
*
|
|
11
|
-
* Command-line interface for managing pipeline execution
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
const commands = {
|
|
15
|
-
/**
|
|
16
|
-
* Run a pipeline
|
|
17
|
-
*/
|
|
18
|
-
async run(args) {
|
|
19
|
-
const pipelineFile = args.pipeline || args.p;
|
|
20
|
-
if (!pipelineFile) {
|
|
21
|
-
console.error('Error: --pipeline (-p) is required');
|
|
22
|
-
process.exit(1);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const contextFile = args.context || args.c;
|
|
26
|
-
const context = contextFile
|
|
27
|
-
? JSON.parse(await fs.readFile(contextFile, 'utf-8'))
|
|
28
|
-
: {};
|
|
29
|
-
|
|
30
|
-
// Create agent executor
|
|
31
|
-
const agentExecutor = new AgentExecutor({
|
|
32
|
-
agentsDir: args.agentsDir || '.claude/agents',
|
|
33
|
-
streamLogs: !args.quiet
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
// Create pipeline engine
|
|
37
|
-
const engine = new PipelineEngine({
|
|
38
|
-
maxConcurrentJobs: args.concurrency || 3,
|
|
39
|
-
stateDir: args.stateDir || '.agentful/pipelines',
|
|
40
|
-
agentExecutor: async (jobDef, jobContext, options) => {
|
|
41
|
-
return await agentExecutor.execute(jobDef, jobContext, options);
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
// Setup event handlers
|
|
46
|
-
engine.on('pipeline:started', (event) => {
|
|
47
|
-
console.log(`\n🚀 Pipeline started: ${event.pipeline}`);
|
|
48
|
-
console.log(` Run ID: ${event.runId}\n`);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
engine.on('job:started', (event) => {
|
|
52
|
-
console.log(`⏳ Job started: ${event.jobName} (attempt ${event.attempt})`);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
engine.on('job:completed', (event) => {
|
|
56
|
-
const duration = (event.duration / 1000).toFixed(1);
|
|
57
|
-
console.log(`✅ Job completed: ${event.jobName} (${duration}s)\n`);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
engine.on('job:failed', (event) => {
|
|
61
|
-
console.error(`❌ Job failed: ${event.jobName}`);
|
|
62
|
-
console.error(` Error: ${event.error}\n`);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
engine.on('job:progress', (event) => {
|
|
66
|
-
if (args.verbose) {
|
|
67
|
-
console.log(` Progress: ${event.progress}%`);
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
engine.on('job:log', (event) => {
|
|
72
|
-
if (args.verbose) {
|
|
73
|
-
console.log(` ${event.message}`);
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
engine.on('pipeline:completed', (event) => {
|
|
78
|
-
const duration = (event.duration / 1000).toFixed(1);
|
|
79
|
-
console.log(`\n✨ Pipeline completed successfully (${duration}s)`);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
engine.on('pipeline:failed', (event) => {
|
|
83
|
-
console.error(`\n💥 Pipeline failed: ${event.error}`);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
// Start pipeline
|
|
87
|
-
try {
|
|
88
|
-
const runId = await engine.startPipeline(pipelineFile, context);
|
|
89
|
-
|
|
90
|
-
// Wait for completion
|
|
91
|
-
await waitForPipeline(engine, runId);
|
|
92
|
-
|
|
93
|
-
const status = engine.getPipelineStatus(runId);
|
|
94
|
-
if (status.status === 'completed') {
|
|
95
|
-
process.exit(0);
|
|
96
|
-
} else {
|
|
97
|
-
process.exit(1);
|
|
98
|
-
}
|
|
99
|
-
} catch (error) {
|
|
100
|
-
console.error(`\n❌ Error: ${error.message}`);
|
|
101
|
-
process.exit(1);
|
|
102
|
-
}
|
|
103
|
-
},
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Get pipeline status
|
|
107
|
-
*/
|
|
108
|
-
async status(args) {
|
|
109
|
-
const runId = args.runId || args.r;
|
|
110
|
-
if (!runId) {
|
|
111
|
-
console.error('Error: --run-id (-r) is required');
|
|
112
|
-
process.exit(1);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const engine = new PipelineEngine({
|
|
116
|
-
stateDir: args.stateDir || '.agentful/pipelines'
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
const status = engine.getPipelineStatus(runId);
|
|
120
|
-
if (!status) {
|
|
121
|
-
console.error(`Pipeline not found: ${runId}`);
|
|
122
|
-
process.exit(1);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
console.log('\n📊 Pipeline Status\n');
|
|
126
|
-
console.log(`Pipeline: ${status.pipeline}`);
|
|
127
|
-
console.log(`Status: ${status.status}`);
|
|
128
|
-
console.log(`Progress: ${status.progress}%`);
|
|
129
|
-
console.log(`Started: ${status.startedAt}`);
|
|
130
|
-
if (status.completedAt) {
|
|
131
|
-
console.log(`Completed: ${status.completedAt}`);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
console.log('\n📋 Jobs:\n');
|
|
135
|
-
for (const job of status.jobs) {
|
|
136
|
-
const icon = {
|
|
137
|
-
pending: '⏸️ ',
|
|
138
|
-
queued: '⏳',
|
|
139
|
-
running: '⏳',
|
|
140
|
-
completed: '✅',
|
|
141
|
-
failed: '❌',
|
|
142
|
-
skipped: '⏭️ '
|
|
143
|
-
}[job.status];
|
|
144
|
-
|
|
145
|
-
console.log(`${icon} ${job.name}`);
|
|
146
|
-
console.log(` Status: ${job.status}`);
|
|
147
|
-
if (job.progress > 0) {
|
|
148
|
-
console.log(` Progress: ${job.progress}%`);
|
|
149
|
-
}
|
|
150
|
-
if (job.error) {
|
|
151
|
-
console.log(` Error: ${job.error}`);
|
|
152
|
-
}
|
|
153
|
-
console.log();
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
if (status.errors.length > 0) {
|
|
157
|
-
console.log('\n⚠️ Errors:\n');
|
|
158
|
-
for (const error of status.errors) {
|
|
159
|
-
console.log(`- ${error.message}`);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
},
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* List pipeline runs
|
|
166
|
-
*/
|
|
167
|
-
async list(args) {
|
|
168
|
-
const stateDir = args.stateDir || '.agentful/pipelines';
|
|
169
|
-
const runsDir = path.join(stateDir, 'runs');
|
|
170
|
-
|
|
171
|
-
try {
|
|
172
|
-
const files = await fs.readdir(runsDir);
|
|
173
|
-
const runs = [];
|
|
174
|
-
|
|
175
|
-
for (const file of files) {
|
|
176
|
-
if (!file.endsWith('.json')) continue;
|
|
177
|
-
|
|
178
|
-
const content = await fs.readFile(path.join(runsDir, file), 'utf-8');
|
|
179
|
-
const state = JSON.parse(content);
|
|
180
|
-
|
|
181
|
-
runs.push({
|
|
182
|
-
runId: state.runId,
|
|
183
|
-
pipeline: state.pipeline.name,
|
|
184
|
-
status: state.status,
|
|
185
|
-
startedAt: state.startedAt,
|
|
186
|
-
completedAt: state.completedAt
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Sort by start time (newest first)
|
|
191
|
-
runs.sort((a, b) => new Date(b.startedAt) - new Date(a.startedAt));
|
|
192
|
-
|
|
193
|
-
console.log('\n📋 Pipeline Runs\n');
|
|
194
|
-
for (const run of runs) {
|
|
195
|
-
const icon = {
|
|
196
|
-
idle: '⏸️ ',
|
|
197
|
-
running: '⏳',
|
|
198
|
-
completed: '✅',
|
|
199
|
-
failed: '❌',
|
|
200
|
-
cancelled: '⏹️ '
|
|
201
|
-
}[run.status];
|
|
202
|
-
|
|
203
|
-
console.log(`${icon} ${run.pipeline}`);
|
|
204
|
-
console.log(` Run ID: ${run.runId}`);
|
|
205
|
-
console.log(` Status: ${run.status}`);
|
|
206
|
-
console.log(` Started: ${run.startedAt}`);
|
|
207
|
-
if (run.completedAt) {
|
|
208
|
-
console.log(` Completed: ${run.completedAt}`);
|
|
209
|
-
}
|
|
210
|
-
console.log();
|
|
211
|
-
}
|
|
212
|
-
} catch (error) {
|
|
213
|
-
console.error(`Error listing runs: ${error.message}`);
|
|
214
|
-
process.exit(1);
|
|
215
|
-
}
|
|
216
|
-
},
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Cancel a pipeline run
|
|
220
|
-
*/
|
|
221
|
-
async cancel(args) {
|
|
222
|
-
const runId = args.runId || args.r;
|
|
223
|
-
if (!runId) {
|
|
224
|
-
console.error('Error: --run-id (-r) is required');
|
|
225
|
-
process.exit(1);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const engine = new PipelineEngine({
|
|
229
|
-
stateDir: args.stateDir || '.agentful/pipelines'
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
const cancelled = await engine.cancelPipeline(runId);
|
|
233
|
-
if (cancelled) {
|
|
234
|
-
console.log(`✅ Pipeline cancelled: ${runId}`);
|
|
235
|
-
} else {
|
|
236
|
-
console.error(`❌ Pipeline not found: ${runId}`);
|
|
237
|
-
process.exit(1);
|
|
238
|
-
}
|
|
239
|
-
},
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* Resume a pipeline run
|
|
243
|
-
*/
|
|
244
|
-
async resume(args) {
|
|
245
|
-
const runId = args.runId || args.r;
|
|
246
|
-
if (!runId) {
|
|
247
|
-
console.error('Error: --run-id (-r) is required');
|
|
248
|
-
process.exit(1);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const engine = new PipelineEngine({
|
|
252
|
-
stateDir: args.stateDir || '.agentful/pipelines'
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
const resumed = await engine.resumePipeline(runId);
|
|
256
|
-
if (resumed) {
|
|
257
|
-
console.log(`✅ Pipeline resumed: ${runId}`);
|
|
258
|
-
} else {
|
|
259
|
-
console.error(`❌ Cannot resume pipeline: ${runId}`);
|
|
260
|
-
process.exit(1);
|
|
261
|
-
}
|
|
262
|
-
},
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Validate pipeline definition
|
|
266
|
-
*/
|
|
267
|
-
async validate(args) {
|
|
268
|
-
const pipelineFile = args.pipeline || args.p;
|
|
269
|
-
if (!pipelineFile) {
|
|
270
|
-
console.error('Error: --pipeline (-p) is required');
|
|
271
|
-
process.exit(1);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
try {
|
|
275
|
-
const engine = new PipelineEngine();
|
|
276
|
-
const pipeline = await engine.loadPipeline(pipelineFile);
|
|
277
|
-
|
|
278
|
-
console.log('✅ Pipeline definition is valid');
|
|
279
|
-
console.log(` Name: ${pipeline.name}`);
|
|
280
|
-
console.log(` Jobs: ${pipeline.jobs.length}`);
|
|
281
|
-
} catch (error) {
|
|
282
|
-
console.error(`❌ Pipeline validation failed: ${error.message}`);
|
|
283
|
-
process.exit(1);
|
|
284
|
-
}
|
|
285
|
-
},
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
* Show help
|
|
289
|
-
*/
|
|
290
|
-
help() {
|
|
291
|
-
console.log(`
|
|
292
|
-
agentful pipeline - Pipeline orchestration for AI agents
|
|
293
|
-
|
|
294
|
-
Usage:
|
|
295
|
-
agentful pipeline <command> [options]
|
|
296
|
-
|
|
297
|
-
Commands:
|
|
298
|
-
run Run a pipeline
|
|
299
|
-
status Get pipeline status
|
|
300
|
-
list List pipeline runs
|
|
301
|
-
cancel Cancel a running pipeline
|
|
302
|
-
resume Resume an interrupted pipeline
|
|
303
|
-
validate Validate pipeline definition
|
|
304
|
-
|
|
305
|
-
Options:
|
|
306
|
-
--pipeline, -p Pipeline YAML file
|
|
307
|
-
--context, -c Context JSON file
|
|
308
|
-
--run-id, -r Pipeline run ID
|
|
309
|
-
--concurrency Max concurrent jobs (default: 3)
|
|
310
|
-
--state-dir State directory (default: .agentful/pipelines)
|
|
311
|
-
--agents-dir Agents directory (default: .claude/agents)
|
|
312
|
-
--verbose, -v Verbose output
|
|
313
|
-
--quiet, -q Quiet mode (no logs)
|
|
314
|
-
|
|
315
|
-
Examples:
|
|
316
|
-
# Run a pipeline
|
|
317
|
-
agentful pipeline run --pipeline examples/pipelines/feature-development.yml
|
|
318
|
-
|
|
319
|
-
# Run with context
|
|
320
|
-
agentful pipeline run -p pipeline.yml -c context.json
|
|
321
|
-
|
|
322
|
-
# Check status
|
|
323
|
-
agentful pipeline status --run-id feature-development-1234567890-abc
|
|
324
|
-
|
|
325
|
-
# List all runs
|
|
326
|
-
agentful pipeline list
|
|
327
|
-
|
|
328
|
-
# Cancel a run
|
|
329
|
-
agentful pipeline cancel --run-id feature-development-1234567890-abc
|
|
330
|
-
|
|
331
|
-
# Validate pipeline
|
|
332
|
-
agentful pipeline validate --pipeline pipeline.yml
|
|
333
|
-
`);
|
|
334
|
-
}
|
|
335
|
-
};
|
|
336
|
-
|
|
337
|
-
/**
|
|
338
|
-
* Helper: Wait for pipeline to complete
|
|
339
|
-
*/
|
|
340
|
-
async function waitForPipeline(engine, runId) {
|
|
341
|
-
return new Promise((resolve) => {
|
|
342
|
-
const check = () => {
|
|
343
|
-
const status = engine.getPipelineStatus(runId);
|
|
344
|
-
if (!status) {
|
|
345
|
-
resolve();
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
if (
|
|
350
|
-
status.status === 'completed' ||
|
|
351
|
-
status.status === 'failed' ||
|
|
352
|
-
status.status === 'cancelled'
|
|
353
|
-
) {
|
|
354
|
-
resolve();
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
setTimeout(check, 1000);
|
|
359
|
-
};
|
|
360
|
-
|
|
361
|
-
check();
|
|
362
|
-
});
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
/**
|
|
366
|
-
* Parse command-line arguments
|
|
367
|
-
*/
|
|
368
|
-
function parseArgs(argv) {
|
|
369
|
-
const args = {};
|
|
370
|
-
let current = null;
|
|
371
|
-
|
|
372
|
-
for (let i = 0; i < argv.length; i++) {
|
|
373
|
-
const arg = argv[i];
|
|
374
|
-
|
|
375
|
-
if (arg.startsWith('--')) {
|
|
376
|
-
current = arg.substring(2);
|
|
377
|
-
args[current] = true;
|
|
378
|
-
} else if (arg.startsWith('-')) {
|
|
379
|
-
current = arg.substring(1);
|
|
380
|
-
args[current] = true;
|
|
381
|
-
} else if (current) {
|
|
382
|
-
args[current] = arg;
|
|
383
|
-
current = null;
|
|
384
|
-
} else {
|
|
385
|
-
if (!args._command) {
|
|
386
|
-
args._command = arg;
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
return args;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
/**
|
|
395
|
-
* Main entry point
|
|
396
|
-
*/
|
|
397
|
-
async function main() {
|
|
398
|
-
const args = parseArgs(process.argv.slice(2));
|
|
399
|
-
const command = args._command || 'help';
|
|
400
|
-
|
|
401
|
-
if (!commands[command]) {
|
|
402
|
-
console.error(`Unknown command: ${command}`);
|
|
403
|
-
commands.help();
|
|
404
|
-
process.exit(1);
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
try {
|
|
408
|
-
await commands[command](args);
|
|
409
|
-
} catch (error) {
|
|
410
|
-
console.error(`Error: ${error.message}`);
|
|
411
|
-
if (args.verbose) {
|
|
412
|
-
console.error(error.stack);
|
|
413
|
-
}
|
|
414
|
-
process.exit(1);
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
// Run CLI if executed directly
|
|
419
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
420
|
-
main();
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
export default { commands, parseArgs };
|