musubi-sdd 3.0.1 → 3.5.1

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 (49) hide show
  1. package/bin/musubi-change.js +623 -10
  2. package/bin/musubi-orchestrate.js +456 -0
  3. package/bin/musubi-trace.js +393 -0
  4. package/package.json +3 -2
  5. package/src/analyzers/impact-analyzer.js +682 -0
  6. package/src/integrations/cicd.js +782 -0
  7. package/src/integrations/documentation.js +740 -0
  8. package/src/integrations/examples.js +789 -0
  9. package/src/integrations/index.js +23 -0
  10. package/src/integrations/platforms.js +929 -0
  11. package/src/managers/delta-spec.js +484 -0
  12. package/src/monitoring/incident-manager.js +890 -0
  13. package/src/monitoring/index.js +633 -0
  14. package/src/monitoring/observability.js +938 -0
  15. package/src/monitoring/release-manager.js +622 -0
  16. package/src/orchestration/index.js +168 -0
  17. package/src/orchestration/orchestration-engine.js +409 -0
  18. package/src/orchestration/pattern-registry.js +319 -0
  19. package/src/orchestration/patterns/auto.js +386 -0
  20. package/src/orchestration/patterns/group-chat.js +395 -0
  21. package/src/orchestration/patterns/human-in-loop.js +506 -0
  22. package/src/orchestration/patterns/nested.js +322 -0
  23. package/src/orchestration/patterns/sequential.js +278 -0
  24. package/src/orchestration/patterns/swarm.js +395 -0
  25. package/src/orchestration/workflow-orchestrator.js +738 -0
  26. package/src/reporters/coverage-report.js +452 -0
  27. package/src/reporters/traceability-matrix-report.js +684 -0
  28. package/src/steering/advanced-validation.js +812 -0
  29. package/src/steering/auto-updater.js +670 -0
  30. package/src/steering/index.js +119 -0
  31. package/src/steering/quality-metrics.js +650 -0
  32. package/src/steering/template-constraints.js +789 -0
  33. package/src/templates/agents/claude-code/skills/agent-assistant/SKILL.md +22 -0
  34. package/src/templates/agents/claude-code/skills/issue-resolver/SKILL.md +21 -0
  35. package/src/templates/agents/claude-code/skills/orchestrator/SKILL.md +90 -28
  36. package/src/templates/agents/claude-code/skills/project-manager/SKILL.md +32 -0
  37. package/src/templates/agents/claude-code/skills/site-reliability-engineer/SKILL.md +27 -0
  38. package/src/templates/agents/claude-code/skills/steering/SKILL.md +30 -0
  39. package/src/templates/agents/claude-code/skills/test-engineer/SKILL.md +21 -0
  40. package/src/templates/agents/claude-code/skills/ui-ux-designer/SKILL.md +27 -0
  41. package/src/templates/agents/codex/AGENTS.md +36 -1
  42. package/src/templates/agents/cursor/AGENTS.md +36 -1
  43. package/src/templates/agents/gemini-cli/GEMINI.md +36 -1
  44. package/src/templates/agents/github-copilot/AGENTS.md +65 -1
  45. package/src/templates/agents/qwen-code/QWEN.md +36 -1
  46. package/src/templates/agents/windsurf/AGENTS.md +36 -1
  47. package/src/templates/shared/delta-spec-template.md +246 -0
  48. package/src/validators/delta-format.js +474 -0
  49. package/src/validators/traceability-validator.js +561 -0
@@ -0,0 +1,738 @@
1
+ /**
2
+ * WorkflowOrchestrator - Complex multi-pattern workflow execution
3
+ *
4
+ * Enables end-to-end workflows combining multiple orchestration patterns
5
+ * for complete SDD lifecycle (Research → Monitoring)
6
+ */
7
+
8
+ const { PatternType, ExecutionContext, ExecutionStatus } = require('./orchestration-engine');
9
+
10
+ /**
11
+ * Workflow step types
12
+ */
13
+ const StepType = {
14
+ SKILL: 'skill', // Single skill execution
15
+ PATTERN: 'pattern', // Execute an orchestration pattern
16
+ CONDITIONAL: 'conditional', // Branch based on condition
17
+ PARALLEL: 'parallel', // Parallel steps
18
+ CHECKPOINT: 'checkpoint', // Save state checkpoint
19
+ HUMAN_GATE: 'human-gate' // Require human approval
20
+ };
21
+
22
+ /**
23
+ * Workflow state
24
+ */
25
+ const WorkflowState = {
26
+ PENDING: 'pending',
27
+ RUNNING: 'running',
28
+ PAUSED: 'paused',
29
+ COMPLETED: 'completed',
30
+ FAILED: 'failed',
31
+ CANCELLED: 'cancelled'
32
+ };
33
+
34
+ /**
35
+ * WorkflowOrchestrator - Complex workflow coordination
36
+ */
37
+ class WorkflowOrchestrator {
38
+ constructor(engine, options = {}) {
39
+ this.engine = engine;
40
+ this.options = {
41
+ saveCheckpoints: options.saveCheckpoints || false,
42
+ checkpointStorage: options.checkpointStorage || new Map(),
43
+ maxRetries: options.maxRetries || 3,
44
+ retryDelay: options.retryDelay || 1000,
45
+ timeout: options.timeout || 300000, // 5 minutes default
46
+ ...options
47
+ };
48
+
49
+ this.workflows = new Map();
50
+ this.activeExecutions = new Map();
51
+ }
52
+
53
+ /**
54
+ * Register a workflow definition
55
+ * @param {string} name - Workflow name
56
+ * @param {object} definition - Workflow definition
57
+ */
58
+ registerWorkflow(name, definition) {
59
+ if (!definition.steps || !Array.isArray(definition.steps)) {
60
+ throw new Error('Workflow must have steps array');
61
+ }
62
+
63
+ this.workflows.set(name, {
64
+ name,
65
+ description: definition.description || '',
66
+ version: definition.version || '1.0.0',
67
+ steps: definition.steps,
68
+ inputs: definition.inputs || [],
69
+ outputs: definition.outputs || [],
70
+ onError: definition.onError || 'stop',
71
+ metadata: definition.metadata || {}
72
+ });
73
+
74
+ return this;
75
+ }
76
+
77
+ /**
78
+ * Get workflow definition
79
+ * @param {string} name - Workflow name
80
+ * @returns {object|null} Workflow definition
81
+ */
82
+ getWorkflow(name) {
83
+ return this.workflows.get(name) || null;
84
+ }
85
+
86
+ /**
87
+ * List all registered workflows
88
+ * @returns {string[]} Workflow names
89
+ */
90
+ listWorkflows() {
91
+ return [...this.workflows.keys()];
92
+ }
93
+
94
+ /**
95
+ * Execute a workflow
96
+ * @param {string} workflowName - Name of workflow to execute
97
+ * @param {object} input - Initial input data
98
+ * @param {object} options - Execution options
99
+ * @returns {Promise<object>} Execution result
100
+ */
101
+ async execute(workflowName, input = {}, options = {}) {
102
+ const workflow = this.workflows.get(workflowName);
103
+ if (!workflow) {
104
+ throw new Error(`Unknown workflow: ${workflowName}`);
105
+ }
106
+
107
+ const executionId = this._generateId();
108
+ const startTime = Date.now();
109
+
110
+ const execution = {
111
+ id: executionId,
112
+ workflow: workflowName,
113
+ state: WorkflowState.RUNNING,
114
+ currentStep: 0,
115
+ input,
116
+ output: {},
117
+ context: { ...input },
118
+ stepResults: [],
119
+ checkpoints: [],
120
+ startTime,
121
+ endTime: null,
122
+ error: null
123
+ };
124
+
125
+ this.activeExecutions.set(executionId, execution);
126
+
127
+ this.engine.emit('workflowStarted', {
128
+ executionId,
129
+ workflow: workflowName,
130
+ input
131
+ });
132
+
133
+ try {
134
+ // Execute each step
135
+ for (let i = 0; i < workflow.steps.length; i++) {
136
+ execution.currentStep = i;
137
+ const step = workflow.steps[i];
138
+
139
+ this.engine.emit('workflowStepStarted', {
140
+ executionId,
141
+ stepIndex: i,
142
+ step: step.name || step.type,
143
+ totalSteps: workflow.steps.length
144
+ });
145
+
146
+ const stepResult = await this._executeStep(step, execution, options);
147
+
148
+ execution.stepResults.push({
149
+ step: step.name || `step-${i}`,
150
+ type: step.type,
151
+ status: stepResult.status,
152
+ output: stepResult.output,
153
+ duration: stepResult.duration
154
+ });
155
+
156
+ // Merge step output into context
157
+ if (stepResult.output) {
158
+ execution.context = {
159
+ ...execution.context,
160
+ ...stepResult.output,
161
+ [`step_${i}_result`]: stepResult.output
162
+ };
163
+ }
164
+
165
+ this.engine.emit('workflowStepCompleted', {
166
+ executionId,
167
+ stepIndex: i,
168
+ step: step.name || step.type,
169
+ result: stepResult
170
+ });
171
+
172
+ // Handle step failure
173
+ if (stepResult.status === ExecutionStatus.FAILED) {
174
+ if (workflow.onError === 'stop') {
175
+ throw new Error(`Step ${step.name || i} failed: ${stepResult.error}`);
176
+ }
177
+ // Continue on error
178
+ }
179
+
180
+ // Check if execution was cancelled or paused
181
+ if (execution.state === WorkflowState.CANCELLED) {
182
+ break;
183
+ }
184
+ if (execution.state === WorkflowState.PAUSED) {
185
+ // Save checkpoint and wait
186
+ await this._saveCheckpoint(execution);
187
+ return {
188
+ executionId,
189
+ state: WorkflowState.PAUSED,
190
+ resumeFrom: i + 1,
191
+ context: execution.context
192
+ };
193
+ }
194
+ }
195
+
196
+ // Workflow completed
197
+ execution.state = WorkflowState.COMPLETED;
198
+ execution.endTime = Date.now();
199
+ execution.output = this._extractOutputs(execution.context, workflow.outputs);
200
+
201
+ const result = {
202
+ executionId,
203
+ workflow: workflowName,
204
+ state: WorkflowState.COMPLETED,
205
+ output: execution.output,
206
+ stepResults: execution.stepResults,
207
+ duration: execution.endTime - startTime,
208
+ summary: this._createSummary(execution)
209
+ };
210
+
211
+ this.engine.emit('workflowCompleted', {
212
+ executionId,
213
+ result
214
+ });
215
+
216
+ return result;
217
+
218
+ } catch (error) {
219
+ execution.state = WorkflowState.FAILED;
220
+ execution.endTime = Date.now();
221
+ execution.error = error.message;
222
+
223
+ this.engine.emit('workflowFailed', {
224
+ executionId,
225
+ error,
226
+ stepResults: execution.stepResults
227
+ });
228
+
229
+ throw error;
230
+ } finally {
231
+ this.activeExecutions.delete(executionId);
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Execute a single workflow step
237
+ * @private
238
+ */
239
+ async _executeStep(step, execution, options) {
240
+ const startTime = Date.now();
241
+
242
+ try {
243
+ let output;
244
+
245
+ switch (step.type) {
246
+ case StepType.SKILL:
247
+ output = await this._executeSkillStep(step, execution);
248
+ break;
249
+
250
+ case StepType.PATTERN:
251
+ output = await this._executePatternStep(step, execution);
252
+ break;
253
+
254
+ case StepType.CONDITIONAL:
255
+ output = await this._executeConditionalStep(step, execution);
256
+ break;
257
+
258
+ case StepType.PARALLEL:
259
+ output = await this._executeParallelStep(step, execution);
260
+ break;
261
+
262
+ case StepType.CHECKPOINT:
263
+ output = await this._executeCheckpointStep(step, execution);
264
+ break;
265
+
266
+ case StepType.HUMAN_GATE:
267
+ output = await this._executeHumanGateStep(step, execution, options);
268
+ break;
269
+
270
+ default:
271
+ throw new Error(`Unknown step type: ${step.type}`);
272
+ }
273
+
274
+ return {
275
+ status: ExecutionStatus.COMPLETED,
276
+ output,
277
+ duration: Date.now() - startTime
278
+ };
279
+
280
+ } catch (error) {
281
+ return {
282
+ status: ExecutionStatus.FAILED,
283
+ error: error.message,
284
+ duration: Date.now() - startTime
285
+ };
286
+ }
287
+ }
288
+
289
+ /**
290
+ * Execute skill step
291
+ * @private
292
+ */
293
+ async _executeSkillStep(step, execution) {
294
+ const input = this._resolveInput(step.input, execution.context);
295
+ const skill = this.engine.getSkill(step.skill);
296
+
297
+ if (!skill) {
298
+ throw new Error(`Unknown skill: ${step.skill}`);
299
+ }
300
+
301
+ const parentContext = new ExecutionContext({
302
+ task: `Workflow skill: ${step.skill}`,
303
+ skill: step.skill,
304
+ input
305
+ });
306
+
307
+ return await this.engine.executeSkill(step.skill, input, parentContext);
308
+ }
309
+
310
+ /**
311
+ * Execute pattern step
312
+ * @private
313
+ */
314
+ async _executePatternStep(step, execution) {
315
+ const input = this._resolveInput(step.input, execution.context);
316
+
317
+ const context = await this.engine.execute(step.pattern, {
318
+ input: { ...input, ...step.config }
319
+ });
320
+
321
+ return context.output;
322
+ }
323
+
324
+ /**
325
+ * Execute conditional step
326
+ * @private
327
+ */
328
+ async _executeConditionalStep(step, execution) {
329
+ const condition = this._evaluateCondition(step.condition, execution.context);
330
+
331
+ const branchSteps = condition ? step.then : step.else;
332
+
333
+ if (branchSteps && branchSteps.length > 0) {
334
+ for (const branchStep of branchSteps) {
335
+ const result = await this._executeStep(branchStep, execution, {});
336
+ if (result.status === ExecutionStatus.FAILED) {
337
+ throw new Error(`Conditional branch failed: ${result.error}`);
338
+ }
339
+ }
340
+ }
341
+
342
+ return { branch: condition ? 'then' : 'else' };
343
+ }
344
+
345
+ /**
346
+ * Execute parallel step
347
+ * @private
348
+ */
349
+ async _executeParallelStep(step, execution) {
350
+ const results = await Promise.allSettled(
351
+ step.steps.map(subStep =>
352
+ this._executeStep(subStep, execution, {})
353
+ )
354
+ );
355
+
356
+ const outputs = results.map((r, i) => ({
357
+ step: step.steps[i].name || `parallel-${i}`,
358
+ status: r.status === 'fulfilled' ? r.value.status : ExecutionStatus.FAILED,
359
+ output: r.status === 'fulfilled' ? r.value.output : null,
360
+ error: r.status === 'rejected' ? r.reason.message : null
361
+ }));
362
+
363
+ return { parallelResults: outputs };
364
+ }
365
+
366
+ /**
367
+ * Execute checkpoint step
368
+ * @private
369
+ */
370
+ async _executeCheckpointStep(step, execution) {
371
+ const checkpoint = {
372
+ id: this._generateId(),
373
+ name: step.name || 'checkpoint',
374
+ timestamp: Date.now(),
375
+ context: { ...execution.context }
376
+ };
377
+
378
+ execution.checkpoints.push(checkpoint);
379
+
380
+ if (this.options.saveCheckpoints) {
381
+ this.options.checkpointStorage.set(checkpoint.id, checkpoint);
382
+ }
383
+
384
+ return { checkpointId: checkpoint.id };
385
+ }
386
+
387
+ /**
388
+ * Execute human gate step
389
+ * @private
390
+ */
391
+ async _executeHumanGateStep(step, execution, options) {
392
+ if (!options.humanGate) {
393
+ // Auto-approve if no human gate configured
394
+ return { approved: true, autoApproved: true };
395
+ }
396
+
397
+ const question = this._resolveTemplate(step.question, execution.context);
398
+ const response = await options.humanGate.request(question, execution.context);
399
+
400
+ if (!response.approved) {
401
+ throw new Error(`Human gate rejected: ${response.feedback || 'No reason provided'}`);
402
+ }
403
+
404
+ return response;
405
+ }
406
+
407
+ /**
408
+ * Resolve input with context values
409
+ * @private
410
+ */
411
+ _resolveInput(input, context) {
412
+ if (!input) return context;
413
+ if (typeof input === 'function') return input(context);
414
+
415
+ const resolved = {};
416
+ for (const [key, value] of Object.entries(input)) {
417
+ if (typeof value === 'string' && value.startsWith('$')) {
418
+ // Reference to context value
419
+ const path = value.slice(1);
420
+ resolved[key] = this._getValueByPath(context, path);
421
+ } else {
422
+ resolved[key] = value;
423
+ }
424
+ }
425
+ return { ...context, ...resolved };
426
+ }
427
+
428
+ /**
429
+ * Get value from object by dot path
430
+ * @private
431
+ */
432
+ _getValueByPath(obj, path) {
433
+ return path.split('.').reduce((o, k) => (o || {})[k], obj);
434
+ }
435
+
436
+ /**
437
+ * Evaluate condition expression
438
+ * @private
439
+ */
440
+ _evaluateCondition(condition, context) {
441
+ if (typeof condition === 'function') {
442
+ return condition(context);
443
+ }
444
+ if (typeof condition === 'string') {
445
+ // Simple path check
446
+ return !!this._getValueByPath(context, condition);
447
+ }
448
+ return !!condition;
449
+ }
450
+
451
+ /**
452
+ * Resolve template string with context values
453
+ * @private
454
+ */
455
+ _resolveTemplate(template, context) {
456
+ if (typeof template !== 'string') return template;
457
+ return template.replace(/\$\{([^}]+)\}/g, (_, path) =>
458
+ this._getValueByPath(context, path) || ''
459
+ );
460
+ }
461
+
462
+ /**
463
+ * Extract specified outputs from context
464
+ * @private
465
+ */
466
+ _extractOutputs(context, outputs) {
467
+ if (!outputs || outputs.length === 0) return context;
468
+
469
+ const result = {};
470
+ for (const output of outputs) {
471
+ result[output] = context[output];
472
+ }
473
+ return result;
474
+ }
475
+
476
+ /**
477
+ * Create execution summary
478
+ * @private
479
+ */
480
+ _createSummary(execution) {
481
+ const completed = execution.stepResults.filter(s => s.status === ExecutionStatus.COMPLETED).length;
482
+ const failed = execution.stepResults.filter(s => s.status === ExecutionStatus.FAILED).length;
483
+ const total = execution.stepResults.length;
484
+
485
+ return {
486
+ totalSteps: total,
487
+ completedSteps: completed,
488
+ failedSteps: failed,
489
+ successRate: total > 0 ? (completed / total * 100).toFixed(1) + '%' : '0%',
490
+ duration: execution.endTime - execution.startTime,
491
+ checkpoints: execution.checkpoints.length
492
+ };
493
+ }
494
+
495
+ /**
496
+ * Save checkpoint
497
+ * @private
498
+ */
499
+ async _saveCheckpoint(execution) {
500
+ if (this.options.saveCheckpoints) {
501
+ const checkpoint = {
502
+ id: this._generateId(),
503
+ executionId: execution.id,
504
+ workflow: execution.workflow,
505
+ currentStep: execution.currentStep,
506
+ context: execution.context,
507
+ timestamp: Date.now()
508
+ };
509
+ this.options.checkpointStorage.set(checkpoint.id, checkpoint);
510
+ return checkpoint;
511
+ }
512
+ return null;
513
+ }
514
+
515
+ /**
516
+ * Resume workflow from checkpoint
517
+ * @param {string} checkpointId - Checkpoint ID to resume from
518
+ * @param {object} options - Execution options
519
+ */
520
+ async resumeFromCheckpoint(checkpointId, options = {}) {
521
+ const checkpoint = this.options.checkpointStorage.get(checkpointId);
522
+ if (!checkpoint) {
523
+ throw new Error(`Checkpoint not found: ${checkpointId}`);
524
+ }
525
+
526
+ const workflow = this.workflows.get(checkpoint.workflow);
527
+ if (!workflow) {
528
+ throw new Error(`Workflow not found: ${checkpoint.workflow}`);
529
+ }
530
+
531
+ // Resume execution from checkpoint
532
+ const remainingSteps = workflow.steps.slice(checkpoint.currentStep);
533
+ const resumedWorkflow = {
534
+ ...workflow,
535
+ steps: remainingSteps
536
+ };
537
+
538
+ // Temporarily register resumed workflow
539
+ const tempName = `${checkpoint.workflow}_resumed_${checkpointId}`;
540
+ this.registerWorkflow(tempName, resumedWorkflow);
541
+
542
+ try {
543
+ return await this.execute(tempName, checkpoint.context, options);
544
+ } finally {
545
+ this.workflows.delete(tempName);
546
+ }
547
+ }
548
+
549
+ /**
550
+ * Pause an active execution
551
+ * @param {string} executionId - Execution ID to pause
552
+ */
553
+ pause(executionId) {
554
+ const execution = this.activeExecutions.get(executionId);
555
+ if (execution && execution.state === WorkflowState.RUNNING) {
556
+ execution.state = WorkflowState.PAUSED;
557
+ return true;
558
+ }
559
+ return false;
560
+ }
561
+
562
+ /**
563
+ * Cancel an active execution
564
+ * @param {string} executionId - Execution ID to cancel
565
+ */
566
+ cancel(executionId) {
567
+ const execution = this.activeExecutions.get(executionId);
568
+ if (execution && execution.state === WorkflowState.RUNNING) {
569
+ execution.state = WorkflowState.CANCELLED;
570
+ return true;
571
+ }
572
+ return false;
573
+ }
574
+
575
+ /**
576
+ * Generate unique ID
577
+ * @private
578
+ */
579
+ _generateId() {
580
+ return `wf-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
581
+ }
582
+ }
583
+
584
+ /**
585
+ * Pre-defined SDD workflow templates
586
+ */
587
+ const SDDWorkflowTemplates = {
588
+ /**
589
+ * Simple feature workflow: Requirements → Design → Tasks
590
+ */
591
+ SIMPLE_FEATURE: {
592
+ name: 'simple-feature',
593
+ description: 'Simple feature development workflow',
594
+ steps: [
595
+ {
596
+ name: 'requirements',
597
+ type: StepType.SKILL,
598
+ skill: 'requirements-analyst',
599
+ input: { feature: '$featureName' }
600
+ },
601
+ {
602
+ name: 'design',
603
+ type: StepType.SKILL,
604
+ skill: 'software-architect',
605
+ input: { requirements: '$step_0_result' }
606
+ },
607
+ {
608
+ name: 'tasks',
609
+ type: StepType.SKILL,
610
+ skill: 'task-planner',
611
+ input: { design: '$step_1_result' }
612
+ }
613
+ ],
614
+ outputs: ['requirements', 'design', 'tasks']
615
+ },
616
+
617
+ /**
618
+ * Full SDD lifecycle workflow
619
+ */
620
+ FULL_SDD: {
621
+ name: 'full-sdd',
622
+ description: 'Complete SDD lifecycle from research to deployment',
623
+ steps: [
624
+ {
625
+ name: 'research',
626
+ type: StepType.PATTERN,
627
+ pattern: PatternType.AUTO,
628
+ input: { task: 'Research: $featureName' }
629
+ },
630
+ {
631
+ name: 'requirements',
632
+ type: StepType.SKILL,
633
+ skill: 'requirements-analyst'
634
+ },
635
+ {
636
+ name: 'review-requirements',
637
+ type: StepType.HUMAN_GATE,
638
+ question: 'Please review the requirements for ${featureName}'
639
+ },
640
+ {
641
+ name: 'design',
642
+ type: StepType.PATTERN,
643
+ pattern: PatternType.GROUP_CHAT,
644
+ config: {
645
+ participants: ['software-architect', 'security-reviewer', 'ux-designer'],
646
+ topic: 'Design review'
647
+ }
648
+ },
649
+ {
650
+ name: 'implementation',
651
+ type: StepType.PATTERN,
652
+ pattern: PatternType.SEQUENTIAL,
653
+ config: {
654
+ skills: ['code-generator', 'test-engineer']
655
+ }
656
+ },
657
+ {
658
+ name: 'validation',
659
+ type: StepType.PATTERN,
660
+ pattern: PatternType.SWARM,
661
+ config: {
662
+ tasks: [
663
+ { skill: 'code-reviewer' },
664
+ { skill: 'security-reviewer' },
665
+ { skill: 'accessibility-specialist' }
666
+ ]
667
+ }
668
+ },
669
+ {
670
+ name: 'checkpoint',
671
+ type: StepType.CHECKPOINT,
672
+ name: 'pre-deployment'
673
+ },
674
+ {
675
+ name: 'deploy-approval',
676
+ type: StepType.HUMAN_GATE,
677
+ question: 'Approve deployment for ${featureName}?'
678
+ }
679
+ ],
680
+ outputs: ['requirements', 'design', 'code', 'tests', 'reviews']
681
+ },
682
+
683
+ /**
684
+ * Code review workflow
685
+ */
686
+ CODE_REVIEW: {
687
+ name: 'code-review',
688
+ description: 'Multi-perspective code review',
689
+ steps: [
690
+ {
691
+ name: 'parallel-review',
692
+ type: StepType.PARALLEL,
693
+ steps: [
694
+ {
695
+ type: StepType.SKILL,
696
+ skill: 'code-reviewer',
697
+ input: { focus: 'quality' }
698
+ },
699
+ {
700
+ type: StepType.SKILL,
701
+ skill: 'security-reviewer',
702
+ input: { focus: 'security' }
703
+ },
704
+ {
705
+ type: StepType.SKILL,
706
+ skill: 'performance-engineer',
707
+ input: { focus: 'performance' }
708
+ }
709
+ ]
710
+ },
711
+ {
712
+ name: 'consolidate',
713
+ type: StepType.SKILL,
714
+ skill: 'documentation-writer',
715
+ input: { reviews: '$parallelResults' }
716
+ }
717
+ ],
718
+ outputs: ['reviews', 'summary']
719
+ }
720
+ };
721
+
722
+ /**
723
+ * Create a workflow orchestrator
724
+ * @param {OrchestrationEngine} engine - Orchestration engine
725
+ * @param {object} options - Options
726
+ * @returns {WorkflowOrchestrator} Workflow orchestrator instance
727
+ */
728
+ function createWorkflowOrchestrator(engine, options = {}) {
729
+ return new WorkflowOrchestrator(engine, options);
730
+ }
731
+
732
+ module.exports = {
733
+ WorkflowOrchestrator,
734
+ StepType,
735
+ WorkflowState,
736
+ SDDWorkflowTemplates,
737
+ createWorkflowOrchestrator
738
+ };