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.
- package/bin/musubi-change.js +623 -10
- package/bin/musubi-orchestrate.js +456 -0
- package/bin/musubi-trace.js +393 -0
- package/package.json +3 -2
- package/src/analyzers/impact-analyzer.js +682 -0
- package/src/integrations/cicd.js +782 -0
- package/src/integrations/documentation.js +740 -0
- package/src/integrations/examples.js +789 -0
- package/src/integrations/index.js +23 -0
- package/src/integrations/platforms.js +929 -0
- package/src/managers/delta-spec.js +484 -0
- package/src/monitoring/incident-manager.js +890 -0
- package/src/monitoring/index.js +633 -0
- package/src/monitoring/observability.js +938 -0
- package/src/monitoring/release-manager.js +622 -0
- package/src/orchestration/index.js +168 -0
- package/src/orchestration/orchestration-engine.js +409 -0
- package/src/orchestration/pattern-registry.js +319 -0
- package/src/orchestration/patterns/auto.js +386 -0
- package/src/orchestration/patterns/group-chat.js +395 -0
- package/src/orchestration/patterns/human-in-loop.js +506 -0
- package/src/orchestration/patterns/nested.js +322 -0
- package/src/orchestration/patterns/sequential.js +278 -0
- package/src/orchestration/patterns/swarm.js +395 -0
- package/src/orchestration/workflow-orchestrator.js +738 -0
- package/src/reporters/coverage-report.js +452 -0
- package/src/reporters/traceability-matrix-report.js +684 -0
- package/src/steering/advanced-validation.js +812 -0
- package/src/steering/auto-updater.js +670 -0
- package/src/steering/index.js +119 -0
- package/src/steering/quality-metrics.js +650 -0
- package/src/steering/template-constraints.js +789 -0
- package/src/templates/agents/claude-code/skills/agent-assistant/SKILL.md +22 -0
- package/src/templates/agents/claude-code/skills/issue-resolver/SKILL.md +21 -0
- package/src/templates/agents/claude-code/skills/orchestrator/SKILL.md +90 -28
- package/src/templates/agents/claude-code/skills/project-manager/SKILL.md +32 -0
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/SKILL.md +27 -0
- package/src/templates/agents/claude-code/skills/steering/SKILL.md +30 -0
- package/src/templates/agents/claude-code/skills/test-engineer/SKILL.md +21 -0
- package/src/templates/agents/claude-code/skills/ui-ux-designer/SKILL.md +27 -0
- package/src/templates/agents/codex/AGENTS.md +36 -1
- package/src/templates/agents/cursor/AGENTS.md +36 -1
- package/src/templates/agents/gemini-cli/GEMINI.md +36 -1
- package/src/templates/agents/github-copilot/AGENTS.md +65 -1
- package/src/templates/agents/qwen-code/QWEN.md +36 -1
- package/src/templates/agents/windsurf/AGENTS.md +36 -1
- package/src/templates/shared/delta-spec-template.md +246 -0
- package/src/validators/delta-format.js +474 -0
- package/src/validators/traceability-validator.js +561 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NestedPattern - Hierarchical skill delegation pattern
|
|
3
|
+
*
|
|
4
|
+
* Executes tasks by delegating to sub-skills in a hierarchical manner.
|
|
5
|
+
* Each skill can spawn child tasks creating a tree-like execution structure.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { BasePattern } = require('../pattern-registry');
|
|
9
|
+
const { PatternType, ExecutionContext, ExecutionStatus } = require('../orchestration-engine');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Nested execution mode
|
|
13
|
+
*/
|
|
14
|
+
const NestedMode = {
|
|
15
|
+
DEPTH_FIRST: 'depth-first',
|
|
16
|
+
BREADTH_FIRST: 'breadth-first'
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* NestedPattern - Hierarchical task delegation
|
|
21
|
+
*/
|
|
22
|
+
class NestedPattern extends BasePattern {
|
|
23
|
+
constructor(options = {}) {
|
|
24
|
+
super({
|
|
25
|
+
name: PatternType.NESTED,
|
|
26
|
+
type: PatternType.NESTED,
|
|
27
|
+
description: 'Execute tasks hierarchically, delegating to sub-skills',
|
|
28
|
+
version: '1.0.0',
|
|
29
|
+
tags: ['hierarchical', 'delegation', 'decomposition'],
|
|
30
|
+
useCases: [
|
|
31
|
+
'Complex task breakdown',
|
|
32
|
+
'Hierarchical processing',
|
|
33
|
+
'Multi-level delegation'
|
|
34
|
+
],
|
|
35
|
+
complexity: 'high',
|
|
36
|
+
supportsParallel: false,
|
|
37
|
+
requiresHuman: false
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
this.options = {
|
|
41
|
+
maxDepth: options.maxDepth || 5,
|
|
42
|
+
mode: options.mode || NestedMode.DEPTH_FIRST,
|
|
43
|
+
allowSelfDelegation: options.allowSelfDelegation || false,
|
|
44
|
+
aggregateResults: options.aggregateResults || true,
|
|
45
|
+
...options
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Validate the execution context
|
|
51
|
+
* @param {ExecutionContext} context - Execution context
|
|
52
|
+
* @param {OrchestrationEngine} engine - Orchestration engine
|
|
53
|
+
* @returns {object} Validation result
|
|
54
|
+
*/
|
|
55
|
+
validate(context, engine) {
|
|
56
|
+
const errors = [];
|
|
57
|
+
const input = context.input;
|
|
58
|
+
|
|
59
|
+
// Check for root skill or task
|
|
60
|
+
if (!input.rootSkill && !input.task) {
|
|
61
|
+
errors.push('Nested pattern requires input.rootSkill or input.task');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Check root skill exists
|
|
65
|
+
if (input.rootSkill && !engine.getSkill(input.rootSkill)) {
|
|
66
|
+
errors.push(`Unknown root skill: ${input.rootSkill}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Check delegation map if provided
|
|
70
|
+
if (input.delegationMap) {
|
|
71
|
+
for (const [parent, children] of Object.entries(input.delegationMap)) {
|
|
72
|
+
if (!engine.getSkill(parent)) {
|
|
73
|
+
errors.push(`Unknown skill in delegation map: ${parent}`);
|
|
74
|
+
}
|
|
75
|
+
for (const child of children) {
|
|
76
|
+
if (!engine.getSkill(child)) {
|
|
77
|
+
errors.push(`Unknown child skill: ${child}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
valid: errors.length === 0,
|
|
85
|
+
errors
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Execute nested pattern
|
|
91
|
+
* @param {ExecutionContext} context - Execution context
|
|
92
|
+
* @param {OrchestrationEngine} engine - Orchestration engine
|
|
93
|
+
* @returns {Promise<object>} Execution result
|
|
94
|
+
*/
|
|
95
|
+
async execute(context, engine) {
|
|
96
|
+
const validation = this.validate(context, engine);
|
|
97
|
+
if (!validation.valid) {
|
|
98
|
+
throw new Error(`Validation failed: ${validation.errors.join(', ')}`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const { rootSkill, task, delegationMap = {}, initialInput = {} } = context.input;
|
|
102
|
+
|
|
103
|
+
engine.emit('nestedStarted', {
|
|
104
|
+
context,
|
|
105
|
+
rootSkill,
|
|
106
|
+
delegationMap
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Determine root skill from task if not provided
|
|
110
|
+
let actualRootSkill = rootSkill;
|
|
111
|
+
if (!actualRootSkill && task) {
|
|
112
|
+
actualRootSkill = await engine.resolveSkill(task);
|
|
113
|
+
if (!actualRootSkill) {
|
|
114
|
+
throw new Error(`Cannot resolve skill for task: ${task}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const executionTree = {
|
|
119
|
+
skill: actualRootSkill,
|
|
120
|
+
children: [],
|
|
121
|
+
output: null,
|
|
122
|
+
status: ExecutionStatus.PENDING,
|
|
123
|
+
depth: 0
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
await this._executeNode(
|
|
128
|
+
executionTree,
|
|
129
|
+
initialInput,
|
|
130
|
+
delegationMap,
|
|
131
|
+
context,
|
|
132
|
+
engine,
|
|
133
|
+
0
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
const aggregatedResult = this.options.aggregateResults
|
|
137
|
+
? this._aggregateResults(executionTree)
|
|
138
|
+
: executionTree;
|
|
139
|
+
|
|
140
|
+
engine.emit('nestedCompleted', {
|
|
141
|
+
context,
|
|
142
|
+
tree: executionTree,
|
|
143
|
+
aggregatedResult
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
tree: executionTree,
|
|
148
|
+
aggregatedResult,
|
|
149
|
+
summary: this._createSummary(executionTree)
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
} catch (error) {
|
|
153
|
+
engine.emit('nestedFailed', {
|
|
154
|
+
context,
|
|
155
|
+
tree: executionTree,
|
|
156
|
+
error
|
|
157
|
+
});
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Execute a single node in the tree
|
|
164
|
+
* @private
|
|
165
|
+
*/
|
|
166
|
+
async _executeNode(node, input, delegationMap, parentContext, engine, depth) {
|
|
167
|
+
if (depth >= this.options.maxDepth) {
|
|
168
|
+
node.status = ExecutionStatus.FAILED;
|
|
169
|
+
node.error = `Max depth (${this.options.maxDepth}) exceeded`;
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const stepContext = new ExecutionContext({
|
|
174
|
+
task: `Nested: ${node.skill} (depth: ${depth})`,
|
|
175
|
+
skill: node.skill,
|
|
176
|
+
input,
|
|
177
|
+
parentId: parentContext.id,
|
|
178
|
+
metadata: {
|
|
179
|
+
pattern: PatternType.NESTED,
|
|
180
|
+
depth,
|
|
181
|
+
hasChildren: delegationMap[node.skill]?.length > 0
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
parentContext.children.push(stepContext);
|
|
186
|
+
|
|
187
|
+
engine.emit('nestedNodeStarted', {
|
|
188
|
+
node,
|
|
189
|
+
depth,
|
|
190
|
+
stepContext
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
try {
|
|
194
|
+
stepContext.start();
|
|
195
|
+
node.status = ExecutionStatus.RUNNING;
|
|
196
|
+
|
|
197
|
+
// Execute the skill
|
|
198
|
+
const output = await engine.executeSkill(node.skill, input, parentContext);
|
|
199
|
+
node.output = output;
|
|
200
|
+
stepContext.complete(output);
|
|
201
|
+
|
|
202
|
+
// Check for child skills to delegate to
|
|
203
|
+
const childSkills = delegationMap[node.skill] || [];
|
|
204
|
+
|
|
205
|
+
if (childSkills.length > 0) {
|
|
206
|
+
for (const childSkill of childSkills) {
|
|
207
|
+
// Skip self-delegation unless allowed
|
|
208
|
+
if (!this.options.allowSelfDelegation && childSkill === node.skill) {
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const childNode = {
|
|
213
|
+
skill: childSkill,
|
|
214
|
+
children: [],
|
|
215
|
+
output: null,
|
|
216
|
+
status: ExecutionStatus.PENDING,
|
|
217
|
+
depth: depth + 1
|
|
218
|
+
};
|
|
219
|
+
node.children.push(childNode);
|
|
220
|
+
|
|
221
|
+
// Use parent output as child input
|
|
222
|
+
await this._executeNode(
|
|
223
|
+
childNode,
|
|
224
|
+
output,
|
|
225
|
+
delegationMap,
|
|
226
|
+
parentContext,
|
|
227
|
+
engine,
|
|
228
|
+
depth + 1
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
node.status = ExecutionStatus.COMPLETED;
|
|
234
|
+
|
|
235
|
+
engine.emit('nestedNodeCompleted', {
|
|
236
|
+
node,
|
|
237
|
+
depth,
|
|
238
|
+
output
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
} catch (error) {
|
|
242
|
+
node.status = ExecutionStatus.FAILED;
|
|
243
|
+
node.error = error.message;
|
|
244
|
+
stepContext.fail(error);
|
|
245
|
+
|
|
246
|
+
engine.emit('nestedNodeFailed', {
|
|
247
|
+
node,
|
|
248
|
+
depth,
|
|
249
|
+
error
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
throw error;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Aggregate results from tree
|
|
258
|
+
* @private
|
|
259
|
+
*/
|
|
260
|
+
_aggregateResults(node) {
|
|
261
|
+
const result = {
|
|
262
|
+
skill: node.skill,
|
|
263
|
+
output: node.output,
|
|
264
|
+
childOutputs: []
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
for (const child of node.children) {
|
|
268
|
+
result.childOutputs.push(this._aggregateResults(child));
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return result;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Create execution summary
|
|
276
|
+
* @private
|
|
277
|
+
*/
|
|
278
|
+
_createSummary(tree) {
|
|
279
|
+
let totalNodes = 0;
|
|
280
|
+
let completed = 0;
|
|
281
|
+
let failed = 0;
|
|
282
|
+
let maxDepth = 0;
|
|
283
|
+
|
|
284
|
+
const traverse = (node) => {
|
|
285
|
+
totalNodes++;
|
|
286
|
+
if (node.status === ExecutionStatus.COMPLETED) completed++;
|
|
287
|
+
if (node.status === ExecutionStatus.FAILED) failed++;
|
|
288
|
+
if (node.depth > maxDepth) maxDepth = node.depth;
|
|
289
|
+
|
|
290
|
+
for (const child of node.children) {
|
|
291
|
+
traverse(child);
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
traverse(tree);
|
|
296
|
+
|
|
297
|
+
return {
|
|
298
|
+
totalNodes,
|
|
299
|
+
completed,
|
|
300
|
+
failed,
|
|
301
|
+
maxDepth,
|
|
302
|
+
successRate: totalNodes > 0
|
|
303
|
+
? (completed / totalNodes * 100).toFixed(1) + '%'
|
|
304
|
+
: '0%'
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Create a nested pattern with custom options
|
|
311
|
+
* @param {object} options - Pattern options
|
|
312
|
+
* @returns {NestedPattern} Nested pattern instance
|
|
313
|
+
*/
|
|
314
|
+
function createNestedPattern(options = {}) {
|
|
315
|
+
return new NestedPattern(options);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
module.exports = {
|
|
319
|
+
NestedPattern,
|
|
320
|
+
NestedMode,
|
|
321
|
+
createNestedPattern
|
|
322
|
+
};
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SequentialPattern - Linear skill execution pattern
|
|
3
|
+
*
|
|
4
|
+
* Executes skills in sequence, passing output from one skill
|
|
5
|
+
* as input to the next. Supports error handling and recovery.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { BasePattern } = require('../pattern-registry');
|
|
9
|
+
const { PatternType, ExecutionContext, ExecutionStatus } = require('../orchestration-engine');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Sequential execution options
|
|
13
|
+
*/
|
|
14
|
+
const SequentialOptions = {
|
|
15
|
+
STOP_ON_ERROR: 'stop-on-error',
|
|
16
|
+
CONTINUE_ON_ERROR: 'continue-on-error',
|
|
17
|
+
RETRY_ON_ERROR: 'retry-on-error'
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* SequentialPattern - Execute skills one after another
|
|
22
|
+
*/
|
|
23
|
+
class SequentialPattern extends BasePattern {
|
|
24
|
+
constructor(options = {}) {
|
|
25
|
+
super({
|
|
26
|
+
name: PatternType.SEQUENTIAL,
|
|
27
|
+
type: PatternType.SEQUENTIAL,
|
|
28
|
+
description: 'Execute skills in sequence, passing output as input to next skill',
|
|
29
|
+
version: '1.0.0',
|
|
30
|
+
tags: ['linear', 'pipeline', 'workflow'],
|
|
31
|
+
useCases: [
|
|
32
|
+
'Step-by-step workflows',
|
|
33
|
+
'Data transformation pipelines',
|
|
34
|
+
'Dependent task chains'
|
|
35
|
+
],
|
|
36
|
+
complexity: 'low',
|
|
37
|
+
supportsParallel: false,
|
|
38
|
+
requiresHuman: false
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
this.options = {
|
|
42
|
+
errorHandling: options.errorHandling || SequentialOptions.STOP_ON_ERROR,
|
|
43
|
+
maxRetries: options.maxRetries || 3,
|
|
44
|
+
retryDelay: options.retryDelay || 1000,
|
|
45
|
+
transformOutput: options.transformOutput || ((output, context) => output),
|
|
46
|
+
...options
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Validate the execution context
|
|
52
|
+
* @param {ExecutionContext} context - Execution context
|
|
53
|
+
* @param {OrchestrationEngine} engine - Orchestration engine
|
|
54
|
+
* @returns {object} Validation result
|
|
55
|
+
*/
|
|
56
|
+
validate(context, engine) {
|
|
57
|
+
const errors = [];
|
|
58
|
+
const input = context.input;
|
|
59
|
+
|
|
60
|
+
// Check for skills array
|
|
61
|
+
if (!input.skills || !Array.isArray(input.skills)) {
|
|
62
|
+
errors.push('Sequential pattern requires input.skills array');
|
|
63
|
+
} else if (input.skills.length === 0) {
|
|
64
|
+
errors.push('Sequential pattern requires at least one skill');
|
|
65
|
+
} else {
|
|
66
|
+
// Validate each skill exists
|
|
67
|
+
for (const skillName of input.skills) {
|
|
68
|
+
if (!engine.getSkill(skillName)) {
|
|
69
|
+
errors.push(`Unknown skill: ${skillName}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
valid: errors.length === 0,
|
|
76
|
+
errors
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Execute skills sequentially
|
|
82
|
+
* @param {ExecutionContext} context - Execution context
|
|
83
|
+
* @param {OrchestrationEngine} engine - Orchestration engine
|
|
84
|
+
* @returns {Promise<object>} Execution result
|
|
85
|
+
*/
|
|
86
|
+
async execute(context, engine) {
|
|
87
|
+
const validation = this.validate(context, engine);
|
|
88
|
+
if (!validation.valid) {
|
|
89
|
+
throw new Error(`Validation failed: ${validation.errors.join(', ')}`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const { skills, initialInput = {} } = context.input;
|
|
93
|
+
const results = [];
|
|
94
|
+
let currentInput = { ...initialInput };
|
|
95
|
+
let lastOutput = null;
|
|
96
|
+
|
|
97
|
+
engine.emit('sequentialStarted', {
|
|
98
|
+
context,
|
|
99
|
+
skills,
|
|
100
|
+
totalSteps: skills.length
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
for (let i = 0; i < skills.length; i++) {
|
|
104
|
+
const skillName = skills[i];
|
|
105
|
+
const stepContext = new ExecutionContext({
|
|
106
|
+
task: `Step ${i + 1}: ${skillName}`,
|
|
107
|
+
skill: skillName,
|
|
108
|
+
input: currentInput,
|
|
109
|
+
parentId: context.id,
|
|
110
|
+
metadata: {
|
|
111
|
+
stepIndex: i,
|
|
112
|
+
totalSteps: skills.length,
|
|
113
|
+
pattern: PatternType.SEQUENTIAL
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
context.children.push(stepContext);
|
|
118
|
+
|
|
119
|
+
engine.emit('sequentialStepStarted', {
|
|
120
|
+
context,
|
|
121
|
+
stepContext,
|
|
122
|
+
stepIndex: i,
|
|
123
|
+
skillName
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
stepContext.start();
|
|
128
|
+
|
|
129
|
+
const output = await this._executeWithRetry(
|
|
130
|
+
() => engine.executeSkill(skillName, currentInput, context),
|
|
131
|
+
skillName,
|
|
132
|
+
engine
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
stepContext.complete(output);
|
|
136
|
+
lastOutput = output;
|
|
137
|
+
|
|
138
|
+
// Transform output for next step
|
|
139
|
+
currentInput = this.options.transformOutput(output, stepContext);
|
|
140
|
+
|
|
141
|
+
results.push({
|
|
142
|
+
step: i + 1,
|
|
143
|
+
skill: skillName,
|
|
144
|
+
status: ExecutionStatus.COMPLETED,
|
|
145
|
+
output
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
engine.emit('sequentialStepCompleted', {
|
|
149
|
+
context,
|
|
150
|
+
stepContext,
|
|
151
|
+
stepIndex: i,
|
|
152
|
+
skillName,
|
|
153
|
+
output
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
} catch (error) {
|
|
157
|
+
stepContext.fail(error);
|
|
158
|
+
|
|
159
|
+
results.push({
|
|
160
|
+
step: i + 1,
|
|
161
|
+
skill: skillName,
|
|
162
|
+
status: ExecutionStatus.FAILED,
|
|
163
|
+
error: error.message
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
engine.emit('sequentialStepFailed', {
|
|
167
|
+
context,
|
|
168
|
+
stepContext,
|
|
169
|
+
stepIndex: i,
|
|
170
|
+
skillName,
|
|
171
|
+
error
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Handle error based on configuration
|
|
175
|
+
if (this.options.errorHandling === SequentialOptions.STOP_ON_ERROR) {
|
|
176
|
+
throw new Error(
|
|
177
|
+
`Sequential execution failed at step ${i + 1} (${skillName}): ${error.message}`
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Continue on error - use previous output as input
|
|
182
|
+
engine.emit('sequentialContinuingAfterError', {
|
|
183
|
+
context,
|
|
184
|
+
stepIndex: i,
|
|
185
|
+
skillName,
|
|
186
|
+
error
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const summary = this._createSummary(results, skills);
|
|
192
|
+
|
|
193
|
+
engine.emit('sequentialCompleted', {
|
|
194
|
+
context,
|
|
195
|
+
results,
|
|
196
|
+
summary
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
results,
|
|
201
|
+
summary,
|
|
202
|
+
finalOutput: lastOutput
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Execute with retry
|
|
208
|
+
* @private
|
|
209
|
+
*/
|
|
210
|
+
async _executeWithRetry(fn, skillName, engine) {
|
|
211
|
+
let lastError;
|
|
212
|
+
|
|
213
|
+
for (let attempt = 1; attempt <= this.options.maxRetries; attempt++) {
|
|
214
|
+
try {
|
|
215
|
+
return await fn();
|
|
216
|
+
} catch (error) {
|
|
217
|
+
lastError = error;
|
|
218
|
+
|
|
219
|
+
if (attempt < this.options.maxRetries &&
|
|
220
|
+
this.options.errorHandling === SequentialOptions.RETRY_ON_ERROR) {
|
|
221
|
+
engine.emit('sequentialRetrying', {
|
|
222
|
+
skillName,
|
|
223
|
+
attempt,
|
|
224
|
+
maxRetries: this.options.maxRetries,
|
|
225
|
+
error
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
await this._delay(this.options.retryDelay * attempt);
|
|
229
|
+
} else {
|
|
230
|
+
throw error;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
throw lastError;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Delay helper
|
|
240
|
+
* @private
|
|
241
|
+
*/
|
|
242
|
+
_delay(ms) {
|
|
243
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Create execution summary
|
|
248
|
+
* @private
|
|
249
|
+
*/
|
|
250
|
+
_createSummary(results, skills) {
|
|
251
|
+
const completed = results.filter(r => r.status === ExecutionStatus.COMPLETED).length;
|
|
252
|
+
const failed = results.filter(r => r.status === ExecutionStatus.FAILED).length;
|
|
253
|
+
|
|
254
|
+
return {
|
|
255
|
+
totalSteps: skills.length,
|
|
256
|
+
completed,
|
|
257
|
+
failed,
|
|
258
|
+
successRate: skills.length > 0 ? (completed / skills.length * 100).toFixed(1) + '%' : '0%',
|
|
259
|
+
allCompleted: completed === skills.length,
|
|
260
|
+
hasFailed: failed > 0
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Create a sequential pattern with custom options
|
|
267
|
+
* @param {object} options - Pattern options
|
|
268
|
+
* @returns {SequentialPattern} Sequential pattern instance
|
|
269
|
+
*/
|
|
270
|
+
function createSequentialPattern(options = {}) {
|
|
271
|
+
return new SequentialPattern(options);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
module.exports = {
|
|
275
|
+
SequentialPattern,
|
|
276
|
+
SequentialOptions,
|
|
277
|
+
createSequentialPattern
|
|
278
|
+
};
|