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,319 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PatternRegistry - Registry for orchestration patterns
|
|
3
|
+
*
|
|
4
|
+
* Manages pattern lifecycle and provides pattern discovery
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { PatternType } = require('./orchestration-engine');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Pattern metadata
|
|
11
|
+
*/
|
|
12
|
+
class PatternMetadata {
|
|
13
|
+
constructor(options = {}) {
|
|
14
|
+
this.name = options.name || '';
|
|
15
|
+
this.type = options.type || PatternType.SEQUENTIAL;
|
|
16
|
+
this.description = options.description || '';
|
|
17
|
+
this.version = options.version || '1.0.0';
|
|
18
|
+
this.author = options.author || 'MUSUBI';
|
|
19
|
+
this.tags = options.tags || [];
|
|
20
|
+
this.useCases = options.useCases || [];
|
|
21
|
+
this.complexity = options.complexity || 'medium'; // low, medium, high
|
|
22
|
+
this.supportsParallel = options.supportsParallel || false;
|
|
23
|
+
this.requiresHuman = options.requiresHuman || false;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
matches(criteria = {}) {
|
|
27
|
+
if (criteria.type && this.type !== criteria.type) return false;
|
|
28
|
+
if (criteria.complexity && this.complexity !== criteria.complexity) return false;
|
|
29
|
+
if (criteria.supportsParallel !== undefined &&
|
|
30
|
+
this.supportsParallel !== criteria.supportsParallel) return false;
|
|
31
|
+
if (criteria.requiresHuman !== undefined &&
|
|
32
|
+
this.requiresHuman !== criteria.requiresHuman) return false;
|
|
33
|
+
if (criteria.tags && criteria.tags.length > 0) {
|
|
34
|
+
if (!criteria.tags.some(t => this.tags.includes(t))) return false;
|
|
35
|
+
}
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
toJSON() {
|
|
40
|
+
return {
|
|
41
|
+
name: this.name,
|
|
42
|
+
type: this.type,
|
|
43
|
+
description: this.description,
|
|
44
|
+
version: this.version,
|
|
45
|
+
author: this.author,
|
|
46
|
+
tags: this.tags,
|
|
47
|
+
useCases: this.useCases,
|
|
48
|
+
complexity: this.complexity,
|
|
49
|
+
supportsParallel: this.supportsParallel,
|
|
50
|
+
requiresHuman: this.requiresHuman
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Base pattern class
|
|
57
|
+
*/
|
|
58
|
+
class BasePattern {
|
|
59
|
+
constructor(metadata = {}) {
|
|
60
|
+
this.metadata = new PatternMetadata(metadata);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Execute the pattern
|
|
65
|
+
* @param {ExecutionContext} context - Execution context
|
|
66
|
+
* @param {OrchestrationEngine} engine - Orchestration engine
|
|
67
|
+
* @returns {Promise<any>} Execution result
|
|
68
|
+
*/
|
|
69
|
+
async execute(context, engine) {
|
|
70
|
+
throw new Error('Pattern must implement execute method');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Validate pattern can execute with given context
|
|
75
|
+
* @param {ExecutionContext} context - Execution context
|
|
76
|
+
* @param {OrchestrationEngine} engine - Orchestration engine
|
|
77
|
+
* @returns {object} Validation result
|
|
78
|
+
*/
|
|
79
|
+
validate(context, engine) {
|
|
80
|
+
return { valid: true, errors: [] };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Get pattern name
|
|
85
|
+
* @returns {string} Pattern name
|
|
86
|
+
*/
|
|
87
|
+
getName() {
|
|
88
|
+
return this.metadata.name;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Get pattern metadata
|
|
93
|
+
* @returns {PatternMetadata} Pattern metadata
|
|
94
|
+
*/
|
|
95
|
+
getMetadata() {
|
|
96
|
+
return this.metadata;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* PatternRegistry - Central registry for patterns
|
|
102
|
+
*/
|
|
103
|
+
class PatternRegistry {
|
|
104
|
+
constructor() {
|
|
105
|
+
this.patterns = new Map();
|
|
106
|
+
this.metadata = new Map();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Register a pattern
|
|
111
|
+
* @param {string} name - Pattern name
|
|
112
|
+
* @param {BasePattern|object} pattern - Pattern implementation
|
|
113
|
+
* @param {object} metadata - Optional metadata override
|
|
114
|
+
* @returns {PatternRegistry} This registry for chaining
|
|
115
|
+
*/
|
|
116
|
+
register(name, pattern, metadata = {}) {
|
|
117
|
+
if (!pattern) {
|
|
118
|
+
throw new Error(`Pattern '${name}' cannot be null`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Validate pattern has execute method
|
|
122
|
+
if (typeof pattern.execute !== 'function') {
|
|
123
|
+
throw new Error(`Pattern '${name}' must have an execute method`);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
this.patterns.set(name, pattern);
|
|
127
|
+
|
|
128
|
+
// Extract or create metadata
|
|
129
|
+
const patternMeta = pattern.metadata || pattern.getMetadata?.() || {};
|
|
130
|
+
this.metadata.set(name, new PatternMetadata({
|
|
131
|
+
name,
|
|
132
|
+
...patternMeta,
|
|
133
|
+
...metadata
|
|
134
|
+
}));
|
|
135
|
+
|
|
136
|
+
return this;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Unregister a pattern
|
|
141
|
+
* @param {string} name - Pattern name
|
|
142
|
+
* @returns {boolean} True if pattern was removed
|
|
143
|
+
*/
|
|
144
|
+
unregister(name) {
|
|
145
|
+
this.metadata.delete(name);
|
|
146
|
+
return this.patterns.delete(name);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Get a pattern by name
|
|
151
|
+
* @param {string} name - Pattern name
|
|
152
|
+
* @returns {object|null} Pattern or null
|
|
153
|
+
*/
|
|
154
|
+
get(name) {
|
|
155
|
+
return this.patterns.get(name) || null;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Check if a pattern exists
|
|
160
|
+
* @param {string} name - Pattern name
|
|
161
|
+
* @returns {boolean} True if pattern exists
|
|
162
|
+
*/
|
|
163
|
+
has(name) {
|
|
164
|
+
return this.patterns.has(name);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Get pattern metadata
|
|
169
|
+
* @param {string} name - Pattern name
|
|
170
|
+
* @returns {PatternMetadata|null} Metadata or null
|
|
171
|
+
*/
|
|
172
|
+
getMetadata(name) {
|
|
173
|
+
return this.metadata.get(name) || null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* List all pattern names
|
|
178
|
+
* @returns {string[]} Pattern names
|
|
179
|
+
*/
|
|
180
|
+
list() {
|
|
181
|
+
return Array.from(this.patterns.keys());
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Find patterns matching criteria
|
|
186
|
+
* @param {object} criteria - Search criteria
|
|
187
|
+
* @returns {object[]} Matching patterns with metadata
|
|
188
|
+
*/
|
|
189
|
+
find(criteria = {}) {
|
|
190
|
+
const results = [];
|
|
191
|
+
|
|
192
|
+
for (const [name, pattern] of this.patterns) {
|
|
193
|
+
const meta = this.metadata.get(name);
|
|
194
|
+
if (meta && meta.matches(criteria)) {
|
|
195
|
+
results.push({
|
|
196
|
+
name,
|
|
197
|
+
pattern,
|
|
198
|
+
metadata: meta
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return results;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Find the best pattern for a task
|
|
208
|
+
* @param {string} task - Task description
|
|
209
|
+
* @returns {string|null} Best pattern name
|
|
210
|
+
*/
|
|
211
|
+
findBestPattern(task) {
|
|
212
|
+
const taskLower = task.toLowerCase();
|
|
213
|
+
|
|
214
|
+
// Check for parallel keywords
|
|
215
|
+
if (taskLower.includes('parallel') ||
|
|
216
|
+
taskLower.includes('concurrent') ||
|
|
217
|
+
taskLower.includes('simultaneous')) {
|
|
218
|
+
const swarm = this.find({ supportsParallel: true });
|
|
219
|
+
if (swarm.length > 0) return swarm[0].name;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Check for sequential keywords
|
|
223
|
+
if (taskLower.includes('sequential') ||
|
|
224
|
+
taskLower.includes('step by step') ||
|
|
225
|
+
taskLower.includes('one by one')) {
|
|
226
|
+
if (this.has(PatternType.SEQUENTIAL)) return PatternType.SEQUENTIAL;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Check for collaboration keywords
|
|
230
|
+
if (taskLower.includes('discuss') ||
|
|
231
|
+
taskLower.includes('review') ||
|
|
232
|
+
taskLower.includes('collaborate')) {
|
|
233
|
+
if (this.has(PatternType.GROUP_CHAT)) return PatternType.GROUP_CHAT;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Check for nested/hierarchical keywords
|
|
237
|
+
if (taskLower.includes('break down') ||
|
|
238
|
+
taskLower.includes('decompose') ||
|
|
239
|
+
taskLower.includes('hierarchical')) {
|
|
240
|
+
if (this.has(PatternType.NESTED)) return PatternType.NESTED;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Check for human validation keywords
|
|
244
|
+
if (taskLower.includes('validate') ||
|
|
245
|
+
taskLower.includes('approve') ||
|
|
246
|
+
taskLower.includes('review')) {
|
|
247
|
+
if (this.has(PatternType.HUMAN_IN_LOOP)) return PatternType.HUMAN_IN_LOOP;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Default to auto pattern
|
|
251
|
+
if (this.has(PatternType.AUTO)) return PatternType.AUTO;
|
|
252
|
+
|
|
253
|
+
// Fall back to sequential
|
|
254
|
+
if (this.has(PatternType.SEQUENTIAL)) return PatternType.SEQUENTIAL;
|
|
255
|
+
|
|
256
|
+
// Return first available pattern
|
|
257
|
+
const patterns = this.list();
|
|
258
|
+
return patterns.length > 0 ? patterns[0] : null;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Register all patterns with an orchestration engine
|
|
263
|
+
* @param {OrchestrationEngine} engine - Engine to register with
|
|
264
|
+
*/
|
|
265
|
+
registerWithEngine(engine) {
|
|
266
|
+
for (const [name, pattern] of this.patterns) {
|
|
267
|
+
engine.registerPattern(name, pattern);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Get registry summary
|
|
273
|
+
* @returns {object} Summary of registered patterns
|
|
274
|
+
*/
|
|
275
|
+
getSummary() {
|
|
276
|
+
const summary = {
|
|
277
|
+
total: this.patterns.size,
|
|
278
|
+
patterns: [],
|
|
279
|
+
byType: {},
|
|
280
|
+
byComplexity: {}
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
for (const [name, meta] of this.metadata) {
|
|
284
|
+
summary.patterns.push(meta.toJSON());
|
|
285
|
+
|
|
286
|
+
// Count by type
|
|
287
|
+
summary.byType[meta.type] = (summary.byType[meta.type] || 0) + 1;
|
|
288
|
+
|
|
289
|
+
// Count by complexity
|
|
290
|
+
summary.byComplexity[meta.complexity] =
|
|
291
|
+
(summary.byComplexity[meta.complexity] || 0) + 1;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return summary;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Clear all patterns
|
|
299
|
+
*/
|
|
300
|
+
clear() {
|
|
301
|
+
this.patterns.clear();
|
|
302
|
+
this.metadata.clear();
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Create a default registry with built-in patterns
|
|
308
|
+
* @returns {PatternRegistry} Registry with default patterns
|
|
309
|
+
*/
|
|
310
|
+
function createDefaultRegistry() {
|
|
311
|
+
return new PatternRegistry();
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
module.exports = {
|
|
315
|
+
PatternRegistry,
|
|
316
|
+
PatternMetadata,
|
|
317
|
+
BasePattern,
|
|
318
|
+
createDefaultRegistry
|
|
319
|
+
};
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AutoPattern - Automatic skill selection pattern
|
|
3
|
+
*
|
|
4
|
+
* Analyzes the task and automatically selects the most appropriate
|
|
5
|
+
* skill to execute. Uses skill metadata and keywords for matching.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { BasePattern } = require('../pattern-registry');
|
|
9
|
+
const { PatternType, ExecutionContext, ExecutionStatus } = require('../orchestration-engine');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Skill match confidence levels
|
|
13
|
+
*/
|
|
14
|
+
const ConfidenceLevel = {
|
|
15
|
+
HIGH: 'high', // >= 0.8
|
|
16
|
+
MEDIUM: 'medium', // >= 0.5
|
|
17
|
+
LOW: 'low', // >= 0.3
|
|
18
|
+
NONE: 'none' // < 0.3
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* AutoPattern - Automatic skill selection and execution
|
|
23
|
+
*/
|
|
24
|
+
class AutoPattern extends BasePattern {
|
|
25
|
+
constructor(options = {}) {
|
|
26
|
+
super({
|
|
27
|
+
name: PatternType.AUTO,
|
|
28
|
+
type: PatternType.AUTO,
|
|
29
|
+
description: 'Automatically select and execute the best skill for a task',
|
|
30
|
+
version: '1.0.0',
|
|
31
|
+
tags: ['intelligent', 'automatic', 'routing'],
|
|
32
|
+
useCases: [
|
|
33
|
+
'Dynamic task routing',
|
|
34
|
+
'Intelligent skill selection',
|
|
35
|
+
'Natural language task processing'
|
|
36
|
+
],
|
|
37
|
+
complexity: 'medium',
|
|
38
|
+
supportsParallel: false,
|
|
39
|
+
requiresHuman: false
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
this.options = {
|
|
43
|
+
minConfidence: options.minConfidence || 0.3,
|
|
44
|
+
fallbackSkill: options.fallbackSkill || null,
|
|
45
|
+
multiMatch: options.multiMatch || false, // Execute multiple matching skills
|
|
46
|
+
maxMatches: options.maxMatches || 3,
|
|
47
|
+
...options
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Skill category keywords for classification
|
|
51
|
+
this.categoryKeywords = {
|
|
52
|
+
requirements: ['requirement', 'need', 'user story', 'feature', 'specification', 'ears'],
|
|
53
|
+
design: ['design', 'architecture', 'component', 'diagram', 'c4', 'uml'],
|
|
54
|
+
implementation: ['implement', 'code', 'develop', 'build', 'create', 'programming'],
|
|
55
|
+
testing: ['test', 'qa', 'quality', 'verify', 'validate', 'bug'],
|
|
56
|
+
documentation: ['document', 'doc', 'readme', 'guide', 'tutorial'],
|
|
57
|
+
devops: ['deploy', 'ci', 'cd', 'pipeline', 'infrastructure', 'kubernetes'],
|
|
58
|
+
security: ['security', 'vulnerability', 'authentication', 'authorization'],
|
|
59
|
+
performance: ['performance', 'optimize', 'benchmark', 'profiling'],
|
|
60
|
+
analysis: ['analyze', 'review', 'assess', 'evaluate', 'audit'],
|
|
61
|
+
research: ['research', 'investigate', 'explore', 'study']
|
|
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
|
+
|
|
74
|
+
if (!context.task && !context.input?.task) {
|
|
75
|
+
errors.push('Auto pattern requires a task description');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (engine.listSkills().length === 0) {
|
|
79
|
+
errors.push('No skills registered with engine');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
valid: errors.length === 0,
|
|
84
|
+
errors
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Execute auto pattern - select and run best skill
|
|
90
|
+
* @param {ExecutionContext} context - Execution context
|
|
91
|
+
* @param {OrchestrationEngine} engine - Orchestration engine
|
|
92
|
+
* @returns {Promise<object>} Execution result
|
|
93
|
+
*/
|
|
94
|
+
async execute(context, engine) {
|
|
95
|
+
const validation = this.validate(context, engine);
|
|
96
|
+
if (!validation.valid) {
|
|
97
|
+
throw new Error(`Validation failed: ${validation.errors.join(', ')}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const task = context.task || context.input?.task || '';
|
|
101
|
+
const input = context.input?.skillInput || context.input || {};
|
|
102
|
+
|
|
103
|
+
engine.emit('autoPatternStarted', {
|
|
104
|
+
context,
|
|
105
|
+
task
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Find matching skills
|
|
109
|
+
const matches = this._findMatchingSkills(task, engine);
|
|
110
|
+
|
|
111
|
+
engine.emit('autoPatternMatched', {
|
|
112
|
+
context,
|
|
113
|
+
task,
|
|
114
|
+
matches: matches.map(m => ({ skill: m.skill, confidence: m.confidence }))
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (matches.length === 0) {
|
|
118
|
+
// No matches found
|
|
119
|
+
if (this.options.fallbackSkill && engine.getSkill(this.options.fallbackSkill)) {
|
|
120
|
+
engine.emit('autoPatternFallback', {
|
|
121
|
+
context,
|
|
122
|
+
fallbackSkill: this.options.fallbackSkill
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
return this._executeSingleSkill(
|
|
126
|
+
this.options.fallbackSkill,
|
|
127
|
+
input,
|
|
128
|
+
context,
|
|
129
|
+
engine,
|
|
130
|
+
{ confidence: 0, reason: 'fallback' }
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
throw new Error(`No matching skill found for task: ${task}`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Execute based on configuration
|
|
138
|
+
if (this.options.multiMatch && matches.length > 1) {
|
|
139
|
+
return this._executeMultipleSkills(matches, input, context, engine);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Execute best match
|
|
143
|
+
const bestMatch = matches[0];
|
|
144
|
+
return this._executeSingleSkill(
|
|
145
|
+
bestMatch.skill,
|
|
146
|
+
input,
|
|
147
|
+
context,
|
|
148
|
+
engine,
|
|
149
|
+
bestMatch
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Find matching skills for a task
|
|
155
|
+
* @private
|
|
156
|
+
*/
|
|
157
|
+
_findMatchingSkills(task, engine) {
|
|
158
|
+
const taskLower = task.toLowerCase();
|
|
159
|
+
const words = this._tokenize(taskLower);
|
|
160
|
+
const matches = [];
|
|
161
|
+
|
|
162
|
+
for (const skillName of engine.listSkills()) {
|
|
163
|
+
const skill = engine.getSkill(skillName);
|
|
164
|
+
const score = this._calculateMatchScore(taskLower, words, skillName, skill);
|
|
165
|
+
|
|
166
|
+
if (score >= this.options.minConfidence) {
|
|
167
|
+
matches.push({
|
|
168
|
+
skill: skillName,
|
|
169
|
+
confidence: score,
|
|
170
|
+
confidenceLevel: this._getConfidenceLevel(score),
|
|
171
|
+
matchedKeywords: this._getMatchedKeywords(taskLower, skill)
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Sort by confidence descending
|
|
177
|
+
matches.sort((a, b) => b.confidence - a.confidence);
|
|
178
|
+
|
|
179
|
+
// Limit matches
|
|
180
|
+
return matches.slice(0, this.options.maxMatches);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Calculate match score for a skill
|
|
185
|
+
* @private
|
|
186
|
+
*/
|
|
187
|
+
_calculateMatchScore(taskLower, words, skillName, skill) {
|
|
188
|
+
let score = 0;
|
|
189
|
+
let maxScore = 0;
|
|
190
|
+
|
|
191
|
+
// Skill name match
|
|
192
|
+
maxScore += 0.3;
|
|
193
|
+
const skillNameLower = skillName.toLowerCase().replace(/-/g, ' ');
|
|
194
|
+
if (taskLower.includes(skillNameLower)) {
|
|
195
|
+
score += 0.3;
|
|
196
|
+
} else {
|
|
197
|
+
// Partial name match
|
|
198
|
+
const nameWords = skillNameLower.split(' ');
|
|
199
|
+
const matchedNameWords = nameWords.filter(w => taskLower.includes(w));
|
|
200
|
+
score += 0.3 * (matchedNameWords.length / nameWords.length);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Keywords match
|
|
204
|
+
const keywords = skill?.keywords || [];
|
|
205
|
+
if (keywords.length > 0) {
|
|
206
|
+
maxScore += 0.4;
|
|
207
|
+
const matchedKeywords = keywords.filter(k =>
|
|
208
|
+
taskLower.includes(k.toLowerCase())
|
|
209
|
+
);
|
|
210
|
+
score += 0.4 * (matchedKeywords.length / keywords.length);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Category match
|
|
214
|
+
maxScore += 0.2;
|
|
215
|
+
const categories = skill?.categories || [];
|
|
216
|
+
for (const category of categories) {
|
|
217
|
+
const categoryKw = this.categoryKeywords[category] || [];
|
|
218
|
+
if (categoryKw.some(kw => taskLower.includes(kw))) {
|
|
219
|
+
score += 0.2;
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Description match
|
|
225
|
+
const description = skill?.description || '';
|
|
226
|
+
if (description) {
|
|
227
|
+
maxScore += 0.1;
|
|
228
|
+
const descWords = this._tokenize(description.toLowerCase());
|
|
229
|
+
const commonWords = words.filter(w => descWords.includes(w));
|
|
230
|
+
score += 0.1 * Math.min(1, commonWords.length / 3);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Normalize score
|
|
234
|
+
return maxScore > 0 ? score / maxScore : 0;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Get confidence level from score
|
|
239
|
+
* @private
|
|
240
|
+
*/
|
|
241
|
+
_getConfidenceLevel(score) {
|
|
242
|
+
if (score >= 0.8) return ConfidenceLevel.HIGH;
|
|
243
|
+
if (score >= 0.5) return ConfidenceLevel.MEDIUM;
|
|
244
|
+
if (score >= 0.3) return ConfidenceLevel.LOW;
|
|
245
|
+
return ConfidenceLevel.NONE;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Get matched keywords
|
|
250
|
+
* @private
|
|
251
|
+
*/
|
|
252
|
+
_getMatchedKeywords(taskLower, skill) {
|
|
253
|
+
const keywords = skill?.keywords || [];
|
|
254
|
+
return keywords.filter(k => taskLower.includes(k.toLowerCase()));
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Tokenize text into words
|
|
259
|
+
* @private
|
|
260
|
+
*/
|
|
261
|
+
_tokenize(text) {
|
|
262
|
+
return text
|
|
263
|
+
.split(/\s+/)
|
|
264
|
+
.map(w => w.replace(/[^\w]/g, ''))
|
|
265
|
+
.filter(w => w.length > 2);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Execute a single skill
|
|
270
|
+
* @private
|
|
271
|
+
*/
|
|
272
|
+
async _executeSingleSkill(skillName, input, context, engine, matchInfo) {
|
|
273
|
+
const stepContext = new ExecutionContext({
|
|
274
|
+
task: `Auto-selected: ${skillName}`,
|
|
275
|
+
skill: skillName,
|
|
276
|
+
input,
|
|
277
|
+
parentId: context.id,
|
|
278
|
+
metadata: {
|
|
279
|
+
pattern: PatternType.AUTO,
|
|
280
|
+
confidence: matchInfo.confidence,
|
|
281
|
+
confidenceLevel: matchInfo.confidenceLevel,
|
|
282
|
+
matchedKeywords: matchInfo.matchedKeywords
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
context.children.push(stepContext);
|
|
287
|
+
|
|
288
|
+
try {
|
|
289
|
+
stepContext.start();
|
|
290
|
+
const output = await engine.executeSkill(skillName, input, context);
|
|
291
|
+
stepContext.complete(output);
|
|
292
|
+
|
|
293
|
+
engine.emit('autoPatternCompleted', {
|
|
294
|
+
context,
|
|
295
|
+
selectedSkill: skillName,
|
|
296
|
+
confidence: matchInfo.confidence,
|
|
297
|
+
output
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
return {
|
|
301
|
+
selectedSkill: skillName,
|
|
302
|
+
confidence: matchInfo.confidence,
|
|
303
|
+
confidenceLevel: matchInfo.confidenceLevel,
|
|
304
|
+
output,
|
|
305
|
+
multiMatch: false
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
} catch (error) {
|
|
309
|
+
stepContext.fail(error);
|
|
310
|
+
throw error;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Execute multiple matching skills
|
|
316
|
+
* @private
|
|
317
|
+
*/
|
|
318
|
+
async _executeMultipleSkills(matches, input, context, engine) {
|
|
319
|
+
const results = [];
|
|
320
|
+
|
|
321
|
+
for (const match of matches) {
|
|
322
|
+
const stepContext = new ExecutionContext({
|
|
323
|
+
task: `Auto-selected (multi): ${match.skill}`,
|
|
324
|
+
skill: match.skill,
|
|
325
|
+
input,
|
|
326
|
+
parentId: context.id,
|
|
327
|
+
metadata: {
|
|
328
|
+
pattern: PatternType.AUTO,
|
|
329
|
+
confidence: match.confidence,
|
|
330
|
+
multiMatch: true
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
context.children.push(stepContext);
|
|
335
|
+
|
|
336
|
+
try {
|
|
337
|
+
stepContext.start();
|
|
338
|
+
const output = await engine.executeSkill(match.skill, input, context);
|
|
339
|
+
stepContext.complete(output);
|
|
340
|
+
|
|
341
|
+
results.push({
|
|
342
|
+
skill: match.skill,
|
|
343
|
+
confidence: match.confidence,
|
|
344
|
+
status: ExecutionStatus.COMPLETED,
|
|
345
|
+
output
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
} catch (error) {
|
|
349
|
+
stepContext.fail(error);
|
|
350
|
+
results.push({
|
|
351
|
+
skill: match.skill,
|
|
352
|
+
confidence: match.confidence,
|
|
353
|
+
status: ExecutionStatus.FAILED,
|
|
354
|
+
error: error.message
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
engine.emit('autoPatternCompleted', {
|
|
360
|
+
context,
|
|
361
|
+
results,
|
|
362
|
+
multiMatch: true
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
return {
|
|
366
|
+
selectedSkills: matches.map(m => m.skill),
|
|
367
|
+
results,
|
|
368
|
+
multiMatch: true
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Create an auto pattern with custom options
|
|
375
|
+
* @param {object} options - Pattern options
|
|
376
|
+
* @returns {AutoPattern} Auto pattern instance
|
|
377
|
+
*/
|
|
378
|
+
function createAutoPattern(options = {}) {
|
|
379
|
+
return new AutoPattern(options);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
module.exports = {
|
|
383
|
+
AutoPattern,
|
|
384
|
+
ConfidenceLevel,
|
|
385
|
+
createAutoPattern
|
|
386
|
+
};
|