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,395 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SwarmPattern - Parallel skill execution pattern
|
|
3
|
+
*
|
|
4
|
+
* Enables concurrent execution of multiple skills with
|
|
5
|
+
* P-label task decomposition and dependency tracking.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { BasePattern } = require('../pattern-registry');
|
|
9
|
+
const { PatternType, ExecutionContext, ExecutionStatus, Priority } = require('../orchestration-engine');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* P-label priority levels for parallel execution
|
|
13
|
+
*/
|
|
14
|
+
const PLabel = {
|
|
15
|
+
P0: 'P0', // Critical - must complete first (blocking)
|
|
16
|
+
P1: 'P1', // High priority - primary path
|
|
17
|
+
P2: 'P2', // Medium priority - secondary path
|
|
18
|
+
P3: 'P3' // Low priority - can be deferred
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Execution strategy for swarm
|
|
23
|
+
*/
|
|
24
|
+
const SwarmStrategy = {
|
|
25
|
+
ALL: 'all', // Wait for all to complete
|
|
26
|
+
FIRST: 'first', // Return after first success
|
|
27
|
+
MAJORITY: 'majority', // Return after majority complete
|
|
28
|
+
QUORUM: 'quorum' // Return after quorum achieved
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* SwarmPattern - Parallel skill execution
|
|
33
|
+
*/
|
|
34
|
+
class SwarmPattern extends BasePattern {
|
|
35
|
+
constructor(options = {}) {
|
|
36
|
+
super({
|
|
37
|
+
name: PatternType.SWARM,
|
|
38
|
+
type: PatternType.SWARM,
|
|
39
|
+
description: 'Execute multiple skills concurrently with dependency tracking',
|
|
40
|
+
version: '1.0.0',
|
|
41
|
+
tags: ['parallel', 'concurrent', 'swarm', 'distributed'],
|
|
42
|
+
useCases: [
|
|
43
|
+
'Parallel task execution',
|
|
44
|
+
'Independent subtask processing',
|
|
45
|
+
'Load distribution',
|
|
46
|
+
'Multi-perspective analysis'
|
|
47
|
+
],
|
|
48
|
+
complexity: 'high',
|
|
49
|
+
supportsParallel: true,
|
|
50
|
+
requiresHuman: false
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
this.options = {
|
|
54
|
+
strategy: options.strategy || SwarmStrategy.ALL,
|
|
55
|
+
maxConcurrent: options.maxConcurrent || 10,
|
|
56
|
+
timeout: options.timeout || 60000, // 60 seconds per task
|
|
57
|
+
retryFailed: options.retryFailed || false,
|
|
58
|
+
retryAttempts: options.retryAttempts || 3,
|
|
59
|
+
quorumThreshold: options.quorumThreshold || 0.5,
|
|
60
|
+
priorityOrder: options.priorityOrder || [PLabel.P0, PLabel.P1, PLabel.P2, PLabel.P3],
|
|
61
|
+
...options
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Validate the execution context
|
|
67
|
+
* @param {ExecutionContext} context - Execution context
|
|
68
|
+
* @param {OrchestrationEngine} engine - Orchestration engine
|
|
69
|
+
* @returns {object} Validation result
|
|
70
|
+
*/
|
|
71
|
+
validate(context, engine) {
|
|
72
|
+
const errors = [];
|
|
73
|
+
const input = context.input;
|
|
74
|
+
|
|
75
|
+
// Check for tasks
|
|
76
|
+
if (!input.tasks || !Array.isArray(input.tasks)) {
|
|
77
|
+
errors.push('Swarm pattern requires input.tasks array');
|
|
78
|
+
} else if (input.tasks.length === 0) {
|
|
79
|
+
errors.push('Swarm pattern requires at least one task');
|
|
80
|
+
} else {
|
|
81
|
+
// Validate each task
|
|
82
|
+
for (let i = 0; i < input.tasks.length; i++) {
|
|
83
|
+
const task = input.tasks[i];
|
|
84
|
+
if (!task.skill) {
|
|
85
|
+
errors.push(`Task ${i} requires a skill name`);
|
|
86
|
+
} else if (!engine.getSkill(task.skill)) {
|
|
87
|
+
errors.push(`Unknown skill: ${task.skill}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Validate dependencies
|
|
93
|
+
if (input.dependencies) {
|
|
94
|
+
const taskIds = new Set(input.tasks.map(t => t.id || t.skill));
|
|
95
|
+
for (const [taskId, deps] of Object.entries(input.dependencies)) {
|
|
96
|
+
if (!taskIds.has(taskId)) {
|
|
97
|
+
errors.push(`Dependency references unknown task: ${taskId}`);
|
|
98
|
+
}
|
|
99
|
+
for (const dep of deps) {
|
|
100
|
+
if (!taskIds.has(dep)) {
|
|
101
|
+
errors.push(`Dependency references unknown task: ${dep}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
valid: errors.length === 0,
|
|
109
|
+
errors
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Execute swarm pattern
|
|
115
|
+
* @param {ExecutionContext} context - Execution context
|
|
116
|
+
* @param {OrchestrationEngine} engine - Orchestration engine
|
|
117
|
+
* @returns {Promise<object>} Execution result
|
|
118
|
+
*/
|
|
119
|
+
async execute(context, engine) {
|
|
120
|
+
const validation = this.validate(context, engine);
|
|
121
|
+
if (!validation.valid) {
|
|
122
|
+
throw new Error(`Validation failed: ${validation.errors.join(', ')}`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const { tasks, dependencies = {}, sharedContext = {} } = context.input;
|
|
126
|
+
const results = new Map();
|
|
127
|
+
const completed = new Set();
|
|
128
|
+
const failed = new Set();
|
|
129
|
+
const pending = new Set(tasks.map(t => t.id || t.skill));
|
|
130
|
+
|
|
131
|
+
engine.emit('swarmStarted', {
|
|
132
|
+
context,
|
|
133
|
+
totalTasks: tasks.length,
|
|
134
|
+
strategy: this.options.strategy
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const startTime = Date.now();
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
// Sort tasks by priority
|
|
141
|
+
const sortedTasks = this._sortByPriority(tasks);
|
|
142
|
+
|
|
143
|
+
// Execute tasks respecting dependencies
|
|
144
|
+
while (pending.size > 0) {
|
|
145
|
+
// Find ready tasks (dependencies satisfied)
|
|
146
|
+
const readyTasks = sortedTasks.filter(task => {
|
|
147
|
+
const taskId = task.id || task.skill;
|
|
148
|
+
if (!pending.has(taskId)) return false;
|
|
149
|
+
|
|
150
|
+
const deps = dependencies[taskId] || [];
|
|
151
|
+
return deps.every(dep => completed.has(dep));
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
if (readyTasks.length === 0 && pending.size > 0) {
|
|
155
|
+
// Circular dependency or missing dependency
|
|
156
|
+
throw new Error(`Cannot resolve dependencies for tasks: ${[...pending].join(', ')}`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Execute ready tasks in parallel (limited by maxConcurrent)
|
|
160
|
+
const batch = readyTasks.slice(0, this.options.maxConcurrent);
|
|
161
|
+
|
|
162
|
+
engine.emit('swarmBatchStarted', {
|
|
163
|
+
context,
|
|
164
|
+
batch: batch.map(t => t.id || t.skill),
|
|
165
|
+
pending: pending.size
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
const batchResults = await Promise.allSettled(
|
|
169
|
+
batch.map(task => this._executeTask(task, engine, context, sharedContext, results))
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
// Process results
|
|
173
|
+
for (let i = 0; i < batch.length; i++) {
|
|
174
|
+
const task = batch[i];
|
|
175
|
+
const taskId = task.id || task.skill;
|
|
176
|
+
const result = batchResults[i];
|
|
177
|
+
|
|
178
|
+
pending.delete(taskId);
|
|
179
|
+
|
|
180
|
+
if (result.status === 'fulfilled') {
|
|
181
|
+
results.set(taskId, result.value);
|
|
182
|
+
completed.add(taskId);
|
|
183
|
+
|
|
184
|
+
engine.emit('swarmTaskCompleted', {
|
|
185
|
+
context,
|
|
186
|
+
taskId,
|
|
187
|
+
result: result.value
|
|
188
|
+
});
|
|
189
|
+
} else {
|
|
190
|
+
failed.add(taskId);
|
|
191
|
+
results.set(taskId, { error: result.reason.message });
|
|
192
|
+
|
|
193
|
+
engine.emit('swarmTaskFailed', {
|
|
194
|
+
context,
|
|
195
|
+
taskId,
|
|
196
|
+
error: result.reason
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// Retry logic
|
|
200
|
+
if (this.options.retryFailed && task.retryCount < this.options.retryAttempts) {
|
|
201
|
+
task.retryCount = (task.retryCount || 0) + 1;
|
|
202
|
+
pending.add(taskId);
|
|
203
|
+
failed.delete(taskId);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Check early exit conditions
|
|
209
|
+
if (this._shouldExit(completed, failed, tasks.length)) {
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const duration = Date.now() - startTime;
|
|
215
|
+
const summary = this._createSummary(results, completed, failed, duration, tasks);
|
|
216
|
+
|
|
217
|
+
engine.emit('swarmCompleted', {
|
|
218
|
+
context,
|
|
219
|
+
results: Object.fromEntries(results),
|
|
220
|
+
summary
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
results: Object.fromEntries(results),
|
|
225
|
+
completed: [...completed],
|
|
226
|
+
failed: [...failed],
|
|
227
|
+
summary
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
} catch (error) {
|
|
231
|
+
engine.emit('swarmFailed', {
|
|
232
|
+
context,
|
|
233
|
+
results: Object.fromEntries(results),
|
|
234
|
+
error
|
|
235
|
+
});
|
|
236
|
+
throw error;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Sort tasks by priority (P0 first)
|
|
242
|
+
* @private
|
|
243
|
+
*/
|
|
244
|
+
_sortByPriority(tasks) {
|
|
245
|
+
const priorityOrder = this.options.priorityOrder;
|
|
246
|
+
|
|
247
|
+
return [...tasks].sort((a, b) => {
|
|
248
|
+
const aPriority = a.priority || PLabel.P2;
|
|
249
|
+
const bPriority = b.priority || PLabel.P2;
|
|
250
|
+
return priorityOrder.indexOf(aPriority) - priorityOrder.indexOf(bPriority);
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Execute a single task
|
|
256
|
+
* @private
|
|
257
|
+
*/
|
|
258
|
+
async _executeTask(task, engine, parentContext, sharedContext, previousResults) {
|
|
259
|
+
const taskId = task.id || task.skill;
|
|
260
|
+
|
|
261
|
+
const stepContext = new ExecutionContext({
|
|
262
|
+
task: `Swarm task: ${taskId}`,
|
|
263
|
+
skill: task.skill,
|
|
264
|
+
input: {
|
|
265
|
+
...sharedContext,
|
|
266
|
+
...task.input,
|
|
267
|
+
previousResults: Object.fromEntries(previousResults)
|
|
268
|
+
},
|
|
269
|
+
parentId: parentContext.id,
|
|
270
|
+
priority: this._mapPriority(task.priority),
|
|
271
|
+
metadata: {
|
|
272
|
+
pattern: PatternType.SWARM,
|
|
273
|
+
taskId,
|
|
274
|
+
priority: task.priority || PLabel.P2
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
parentContext.children.push(stepContext);
|
|
279
|
+
|
|
280
|
+
stepContext.start();
|
|
281
|
+
|
|
282
|
+
try {
|
|
283
|
+
const result = await Promise.race([
|
|
284
|
+
engine.executeSkill(task.skill, stepContext.input, parentContext),
|
|
285
|
+
this._timeout(this.options.timeout, taskId)
|
|
286
|
+
]);
|
|
287
|
+
|
|
288
|
+
stepContext.complete(result);
|
|
289
|
+
return result;
|
|
290
|
+
|
|
291
|
+
} catch (error) {
|
|
292
|
+
stepContext.fail(error);
|
|
293
|
+
throw error;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Map P-label to internal priority
|
|
299
|
+
* @private
|
|
300
|
+
*/
|
|
301
|
+
_mapPriority(pLabel) {
|
|
302
|
+
const mapping = {
|
|
303
|
+
[PLabel.P0]: Priority.CRITICAL,
|
|
304
|
+
[PLabel.P1]: Priority.HIGH,
|
|
305
|
+
[PLabel.P2]: Priority.MEDIUM,
|
|
306
|
+
[PLabel.P3]: Priority.LOW
|
|
307
|
+
};
|
|
308
|
+
return mapping[pLabel] || Priority.MEDIUM;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Create timeout promise
|
|
313
|
+
* @private
|
|
314
|
+
*/
|
|
315
|
+
_timeout(ms, taskId) {
|
|
316
|
+
return new Promise((_, reject) => {
|
|
317
|
+
setTimeout(() => reject(new Error(`Task ${taskId} timed out after ${ms}ms`)), ms);
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Check if swarm should exit early based on strategy
|
|
323
|
+
* @private
|
|
324
|
+
*/
|
|
325
|
+
_shouldExit(completed, failed, total) {
|
|
326
|
+
switch (this.options.strategy) {
|
|
327
|
+
case SwarmStrategy.FIRST:
|
|
328
|
+
return completed.size >= 1;
|
|
329
|
+
|
|
330
|
+
case SwarmStrategy.MAJORITY:
|
|
331
|
+
return completed.size > total / 2;
|
|
332
|
+
|
|
333
|
+
case SwarmStrategy.QUORUM:
|
|
334
|
+
return completed.size >= total * this.options.quorumThreshold;
|
|
335
|
+
|
|
336
|
+
case SwarmStrategy.ALL:
|
|
337
|
+
default:
|
|
338
|
+
return false; // Continue until all complete
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Create execution summary
|
|
344
|
+
* @private
|
|
345
|
+
*/
|
|
346
|
+
_createSummary(results, completed, failed, duration, tasks) {
|
|
347
|
+
const total = tasks.length;
|
|
348
|
+
const successCount = completed.size;
|
|
349
|
+
const failCount = failed.size;
|
|
350
|
+
const pendingCount = total - successCount - failCount;
|
|
351
|
+
|
|
352
|
+
// Count by priority
|
|
353
|
+
const byPriority = {
|
|
354
|
+
[PLabel.P0]: { total: 0, completed: 0, failed: 0 },
|
|
355
|
+
[PLabel.P1]: { total: 0, completed: 0, failed: 0 },
|
|
356
|
+
[PLabel.P2]: { total: 0, completed: 0, failed: 0 },
|
|
357
|
+
[PLabel.P3]: { total: 0, completed: 0, failed: 0 }
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
for (const task of tasks) {
|
|
361
|
+
const priority = task.priority || PLabel.P2;
|
|
362
|
+
const taskId = task.id || task.skill;
|
|
363
|
+
byPriority[priority].total++;
|
|
364
|
+
if (completed.has(taskId)) byPriority[priority].completed++;
|
|
365
|
+
if (failed.has(taskId)) byPriority[priority].failed++;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return {
|
|
369
|
+
total,
|
|
370
|
+
completed: successCount,
|
|
371
|
+
failed: failCount,
|
|
372
|
+
pending: pendingCount,
|
|
373
|
+
duration,
|
|
374
|
+
successRate: total > 0 ? (successCount / total * 100).toFixed(1) + '%' : '0%',
|
|
375
|
+
strategy: this.options.strategy,
|
|
376
|
+
byPriority
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Create a swarm pattern with custom options
|
|
383
|
+
* @param {object} options - Pattern options
|
|
384
|
+
* @returns {SwarmPattern} Swarm pattern instance
|
|
385
|
+
*/
|
|
386
|
+
function createSwarmPattern(options = {}) {
|
|
387
|
+
return new SwarmPattern(options);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
module.exports = {
|
|
391
|
+
SwarmPattern,
|
|
392
|
+
PLabel,
|
|
393
|
+
SwarmStrategy,
|
|
394
|
+
createSwarmPattern
|
|
395
|
+
};
|