@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.
Files changed (59) hide show
  1. package/README.md +28 -1
  2. package/bin/cli.js +11 -1055
  3. package/bin/hooks/block-file-creation.js +271 -0
  4. package/bin/hooks/product-spec-watcher.js +151 -0
  5. package/lib/index.js +0 -11
  6. package/lib/init.js +2 -21
  7. package/lib/parallel-execution.js +235 -0
  8. package/lib/presets.js +26 -4
  9. package/package.json +4 -7
  10. package/template/.claude/agents/architect.md +2 -2
  11. package/template/.claude/agents/backend.md +17 -30
  12. package/template/.claude/agents/frontend.md +17 -39
  13. package/template/.claude/agents/orchestrator.md +63 -4
  14. package/template/.claude/agents/product-analyzer.md +1 -1
  15. package/template/.claude/agents/tester.md +16 -29
  16. package/template/.claude/commands/agentful-generate.md +221 -14
  17. package/template/.claude/commands/agentful-init.md +621 -0
  18. package/template/.claude/commands/agentful-product.md +1 -1
  19. package/template/.claude/commands/agentful-start.md +99 -1
  20. package/template/.claude/product/EXAMPLES.md +2 -2
  21. package/template/.claude/product/index.md +1 -1
  22. package/template/.claude/settings.json +22 -0
  23. package/template/.claude/skills/research/SKILL.md +432 -0
  24. package/template/CLAUDE.md +5 -6
  25. package/template/bin/hooks/architect-drift-detector.js +242 -0
  26. package/template/bin/hooks/product-spec-watcher.js +151 -0
  27. package/version.json +1 -1
  28. package/bin/hooks/post-agent.js +0 -101
  29. package/bin/hooks/post-feature.js +0 -227
  30. package/bin/hooks/pre-agent.js +0 -118
  31. package/bin/hooks/pre-feature.js +0 -138
  32. package/lib/VALIDATION_README.md +0 -455
  33. package/lib/ci/claude-action-integration.js +0 -641
  34. package/lib/ci/index.js +0 -10
  35. package/lib/core/analyzer.js +0 -497
  36. package/lib/core/cli.js +0 -141
  37. package/lib/core/detectors/conventions.js +0 -342
  38. package/lib/core/detectors/framework.js +0 -276
  39. package/lib/core/detectors/index.js +0 -15
  40. package/lib/core/detectors/language.js +0 -199
  41. package/lib/core/detectors/patterns.js +0 -356
  42. package/lib/core/generator.js +0 -626
  43. package/lib/core/index.js +0 -9
  44. package/lib/core/output-parser.js +0 -458
  45. package/lib/core/storage.js +0 -515
  46. package/lib/core/templates.js +0 -556
  47. package/lib/pipeline/cli.js +0 -423
  48. package/lib/pipeline/engine.js +0 -928
  49. package/lib/pipeline/executor.js +0 -440
  50. package/lib/pipeline/index.js +0 -33
  51. package/lib/pipeline/integrations.js +0 -559
  52. package/lib/pipeline/schemas.js +0 -288
  53. package/lib/remote/client.js +0 -361
  54. package/lib/server/auth.js +0 -270
  55. package/lib/server/client-example.js +0 -190
  56. package/lib/server/executor.js +0 -477
  57. package/lib/server/index.js +0 -494
  58. package/lib/update-helpers.js +0 -505
  59. package/lib/validation.js +0 -460
@@ -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 };