musubi-sdd 3.10.0 → 5.1.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.
- package/README.md +24 -19
- package/package.json +1 -1
- package/src/agents/agent-loop.js +532 -0
- package/src/agents/agentic/code-generator.js +767 -0
- package/src/agents/agentic/code-reviewer.js +698 -0
- package/src/agents/agentic/index.js +43 -0
- package/src/agents/function-tool.js +432 -0
- package/src/agents/index.js +45 -0
- package/src/agents/schema-generator.js +514 -0
- package/src/analyzers/ast-extractor.js +870 -0
- package/src/analyzers/context-optimizer.js +681 -0
- package/src/analyzers/repository-map.js +692 -0
- package/src/integrations/index.js +7 -1
- package/src/integrations/mcp/index.js +175 -0
- package/src/integrations/mcp/mcp-context-provider.js +472 -0
- package/src/integrations/mcp/mcp-discovery.js +436 -0
- package/src/integrations/mcp/mcp-tool-registry.js +467 -0
- package/src/integrations/mcp-connector.js +818 -0
- package/src/integrations/tool-discovery.js +589 -0
- package/src/managers/index.js +7 -0
- package/src/managers/skill-tools.js +565 -0
- package/src/monitoring/cost-tracker.js +7 -0
- package/src/monitoring/incident-manager.js +10 -0
- package/src/monitoring/observability.js +10 -0
- package/src/monitoring/quality-dashboard.js +491 -0
- package/src/monitoring/release-manager.js +10 -0
- package/src/orchestration/agent-skill-binding.js +655 -0
- package/src/orchestration/error-handler.js +827 -0
- package/src/orchestration/index.js +235 -1
- package/src/orchestration/mcp-tool-adapters.js +896 -0
- package/src/orchestration/reasoning/index.js +58 -0
- package/src/orchestration/reasoning/planning-engine.js +831 -0
- package/src/orchestration/reasoning/reasoning-engine.js +710 -0
- package/src/orchestration/reasoning/self-correction.js +751 -0
- package/src/orchestration/skill-executor.js +665 -0
- package/src/orchestration/skill-registry.js +650 -0
- package/src/orchestration/workflow-examples.js +1072 -0
- package/src/orchestration/workflow-executor.js +779 -0
- package/src/phase4-integration.js +248 -0
- package/src/phase5-integration.js +402 -0
- package/src/steering/steering-auto-update.js +572 -0
- package/src/steering/steering-validator.js +547 -0
- package/src/templates/template-constraints.js +646 -0
- package/src/validators/advanced-validation.js +580 -0
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Skill Tools Manager
|
|
3
|
+
* @description Manage allowed-tools configuration for MUSUBI skills
|
|
4
|
+
* @version 3.11.0
|
|
5
|
+
*
|
|
6
|
+
* Features:
|
|
7
|
+
* - Load skill tool configurations from YAML
|
|
8
|
+
* - Validate tool availability
|
|
9
|
+
* - Generate optimized tool sets per skill
|
|
10
|
+
* - Tool dependency resolution
|
|
11
|
+
* - Skill-aware tool filtering
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
'use strict';
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const yaml = require('js-yaml');
|
|
19
|
+
const { EventEmitter } = require('events');
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Default tool sets for common skill categories
|
|
23
|
+
*/
|
|
24
|
+
const DEFAULT_TOOL_SETS = {
|
|
25
|
+
requirements: [
|
|
26
|
+
'file_read',
|
|
27
|
+
'file_write',
|
|
28
|
+
'search_files',
|
|
29
|
+
'read_resource'
|
|
30
|
+
],
|
|
31
|
+
design: [
|
|
32
|
+
'file_read',
|
|
33
|
+
'file_write',
|
|
34
|
+
'search_files',
|
|
35
|
+
'create_directory',
|
|
36
|
+
'read_resource'
|
|
37
|
+
],
|
|
38
|
+
implementation: [
|
|
39
|
+
'file_read',
|
|
40
|
+
'file_write',
|
|
41
|
+
'search_files',
|
|
42
|
+
'create_directory',
|
|
43
|
+
'run_command',
|
|
44
|
+
'read_resource',
|
|
45
|
+
'code_analysis'
|
|
46
|
+
],
|
|
47
|
+
testing: [
|
|
48
|
+
'file_read',
|
|
49
|
+
'file_write',
|
|
50
|
+
'search_files',
|
|
51
|
+
'run_command',
|
|
52
|
+
'test_runner'
|
|
53
|
+
],
|
|
54
|
+
validation: [
|
|
55
|
+
'file_read',
|
|
56
|
+
'search_files',
|
|
57
|
+
'read_resource',
|
|
58
|
+
'validate'
|
|
59
|
+
],
|
|
60
|
+
documentation: [
|
|
61
|
+
'file_read',
|
|
62
|
+
'file_write',
|
|
63
|
+
'search_files',
|
|
64
|
+
'read_resource'
|
|
65
|
+
],
|
|
66
|
+
analysis: [
|
|
67
|
+
'file_read',
|
|
68
|
+
'search_files',
|
|
69
|
+
'code_analysis',
|
|
70
|
+
'read_resource'
|
|
71
|
+
],
|
|
72
|
+
deployment: [
|
|
73
|
+
'file_read',
|
|
74
|
+
'run_command',
|
|
75
|
+
'deploy'
|
|
76
|
+
]
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Tool restriction levels
|
|
81
|
+
*/
|
|
82
|
+
const RestrictionLevel = {
|
|
83
|
+
NONE: 'none', // No restrictions
|
|
84
|
+
STANDARD: 'standard', // Default restrictions
|
|
85
|
+
STRICT: 'strict', // Minimal tools only
|
|
86
|
+
CUSTOM: 'custom' // Custom configuration
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Skill Tool Configuration
|
|
91
|
+
*/
|
|
92
|
+
class SkillToolConfig {
|
|
93
|
+
constructor(skillName, config = {}) {
|
|
94
|
+
this.skillName = skillName;
|
|
95
|
+
this.allowedTools = config.allowedTools || [];
|
|
96
|
+
this.deniedTools = config.deniedTools || [];
|
|
97
|
+
this.restrictionLevel = config.restrictionLevel || RestrictionLevel.STANDARD;
|
|
98
|
+
this.toolOverrides = config.toolOverrides || {};
|
|
99
|
+
this.inheritFrom = config.inheritFrom || null;
|
|
100
|
+
this.toolDependencies = config.toolDependencies || {};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Check if a tool is allowed
|
|
105
|
+
* @param {string} toolName - Tool name
|
|
106
|
+
* @returns {boolean} Whether tool is allowed
|
|
107
|
+
*/
|
|
108
|
+
isToolAllowed(toolName) {
|
|
109
|
+
// Explicitly denied
|
|
110
|
+
if (this.deniedTools.includes(toolName)) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// No restrictions
|
|
115
|
+
if (this.restrictionLevel === RestrictionLevel.NONE) {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Explicitly allowed
|
|
120
|
+
if (this.allowedTools.includes(toolName)) {
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// If allowed list is specified, deny everything else
|
|
125
|
+
if (this.allowedTools.length > 0) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Standard mode allows common tools
|
|
130
|
+
return this.restrictionLevel === RestrictionLevel.STANDARD;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Get effective tool list with dependencies resolved
|
|
135
|
+
* @param {Map<string, Array<string>>} dependencyMap - Tool dependencies
|
|
136
|
+
* @returns {Array<string>} Resolved tool list
|
|
137
|
+
*/
|
|
138
|
+
getEffectiveTools(dependencyMap = new Map()) {
|
|
139
|
+
const tools = new Set(this.allowedTools);
|
|
140
|
+
|
|
141
|
+
// Add dependencies
|
|
142
|
+
for (const tool of this.allowedTools) {
|
|
143
|
+
const deps = this.toolDependencies[tool] || dependencyMap.get(tool) || [];
|
|
144
|
+
for (const dep of deps) {
|
|
145
|
+
tools.add(dep);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Remove denied
|
|
150
|
+
for (const denied of this.deniedTools) {
|
|
151
|
+
tools.delete(denied);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return Array.from(tools);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
toJSON() {
|
|
158
|
+
return {
|
|
159
|
+
skillName: this.skillName,
|
|
160
|
+
allowedTools: this.allowedTools,
|
|
161
|
+
deniedTools: this.deniedTools,
|
|
162
|
+
restrictionLevel: this.restrictionLevel,
|
|
163
|
+
toolOverrides: this.toolOverrides,
|
|
164
|
+
inheritFrom: this.inheritFrom
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Skill Tools Manager
|
|
171
|
+
*/
|
|
172
|
+
class SkillToolsManager extends EventEmitter {
|
|
173
|
+
constructor(options = {}) {
|
|
174
|
+
super();
|
|
175
|
+
this.options = {
|
|
176
|
+
configDir: options.configDir || '.musubi/tools',
|
|
177
|
+
defaultToolSet: options.defaultToolSet || 'standard',
|
|
178
|
+
enableInheritance: options.enableInheritance !== false,
|
|
179
|
+
...options
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
this.skillConfigs = new Map();
|
|
183
|
+
this.toolDependencies = new Map();
|
|
184
|
+
this.availableTools = new Set();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Load tool configuration from file
|
|
189
|
+
* @param {string} configPath - Path to config file
|
|
190
|
+
* @returns {Promise<Object>} Loaded configuration
|
|
191
|
+
*/
|
|
192
|
+
async loadConfig(configPath) {
|
|
193
|
+
try {
|
|
194
|
+
const content = await fs.promises.readFile(configPath, 'utf-8');
|
|
195
|
+
const ext = path.extname(configPath).toLowerCase();
|
|
196
|
+
|
|
197
|
+
let config;
|
|
198
|
+
if (ext === '.yaml' || ext === '.yml') {
|
|
199
|
+
config = yaml.load(content);
|
|
200
|
+
} else if (ext === '.json') {
|
|
201
|
+
config = JSON.parse(content);
|
|
202
|
+
} else {
|
|
203
|
+
throw new Error(`Unsupported config format: ${ext}`);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
await this._processConfig(config);
|
|
207
|
+
this.emit('configLoaded', configPath);
|
|
208
|
+
return config;
|
|
209
|
+
|
|
210
|
+
} catch (error) {
|
|
211
|
+
if (error.code === 'ENOENT') {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
throw error;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Load tool configuration from string
|
|
220
|
+
* @param {string} content - YAML or JSON content
|
|
221
|
+
* @param {string} format - 'yaml' or 'json'
|
|
222
|
+
* @returns {Object} Loaded configuration
|
|
223
|
+
*/
|
|
224
|
+
loadConfigFromString(content, format = 'yaml') {
|
|
225
|
+
let config;
|
|
226
|
+
if (format === 'yaml') {
|
|
227
|
+
config = yaml.load(content);
|
|
228
|
+
} else {
|
|
229
|
+
config = JSON.parse(content);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
this._processConfig(config);
|
|
233
|
+
return config;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Process loaded configuration
|
|
238
|
+
* @private
|
|
239
|
+
*/
|
|
240
|
+
_processConfig(config) {
|
|
241
|
+
// Load tool dependencies
|
|
242
|
+
if (config.toolDependencies) {
|
|
243
|
+
for (const [tool, deps] of Object.entries(config.toolDependencies)) {
|
|
244
|
+
this.toolDependencies.set(tool, deps);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Load skill configurations
|
|
249
|
+
if (config.skills) {
|
|
250
|
+
for (const [skillName, skillConfig] of Object.entries(config.skills)) {
|
|
251
|
+
this.setSkillConfig(skillName, skillConfig);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Load global defaults
|
|
256
|
+
if (config.defaults) {
|
|
257
|
+
this.options.defaultToolSet = config.defaults.toolSet || this.options.defaultToolSet;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Set configuration for a skill
|
|
263
|
+
* @param {string} skillName - Skill name
|
|
264
|
+
* @param {Object} config - Tool configuration
|
|
265
|
+
* @returns {SkillToolConfig} Created configuration
|
|
266
|
+
*/
|
|
267
|
+
setSkillConfig(skillName, config) {
|
|
268
|
+
const skillConfig = new SkillToolConfig(skillName, config);
|
|
269
|
+
|
|
270
|
+
// Handle inheritance
|
|
271
|
+
if (this.options.enableInheritance && skillConfig.inheritFrom) {
|
|
272
|
+
const parentConfig = this.skillConfigs.get(skillConfig.inheritFrom);
|
|
273
|
+
if (parentConfig) {
|
|
274
|
+
// Merge parent allowed tools
|
|
275
|
+
const parentTools = new Set(parentConfig.allowedTools);
|
|
276
|
+
for (const tool of skillConfig.allowedTools) {
|
|
277
|
+
parentTools.add(tool);
|
|
278
|
+
}
|
|
279
|
+
skillConfig.allowedTools = Array.from(parentTools);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
this.skillConfigs.set(skillName, skillConfig);
|
|
284
|
+
this.emit('skillConfigSet', skillName, skillConfig);
|
|
285
|
+
return skillConfig;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Get configuration for a skill
|
|
290
|
+
* @param {string} skillName - Skill name
|
|
291
|
+
* @returns {SkillToolConfig|null} Skill configuration
|
|
292
|
+
*/
|
|
293
|
+
getSkillConfig(skillName) {
|
|
294
|
+
return this.skillConfigs.get(skillName) || null;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Get allowed tools for a skill
|
|
299
|
+
* @param {string} skillName - Skill name
|
|
300
|
+
* @param {Object} options - Options
|
|
301
|
+
* @returns {Array<string>} Allowed tools
|
|
302
|
+
*/
|
|
303
|
+
getAllowedTools(skillName, options = {}) {
|
|
304
|
+
const config = this.skillConfigs.get(skillName);
|
|
305
|
+
|
|
306
|
+
if (!config) {
|
|
307
|
+
// Return default tools based on skill category
|
|
308
|
+
return this._getDefaultToolsForSkill(skillName);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
let tools = config.getEffectiveTools(this.toolDependencies);
|
|
312
|
+
|
|
313
|
+
// Filter by available tools if specified
|
|
314
|
+
if (options.filterByAvailable && this.availableTools.size > 0) {
|
|
315
|
+
tools = tools.filter(t => this.availableTools.has(t));
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return tools;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Get default tools for a skill based on naming convention
|
|
323
|
+
* @private
|
|
324
|
+
*/
|
|
325
|
+
_getDefaultToolsForSkill(skillName) {
|
|
326
|
+
const lowerName = skillName.toLowerCase();
|
|
327
|
+
|
|
328
|
+
for (const [category, tools] of Object.entries(DEFAULT_TOOL_SETS)) {
|
|
329
|
+
if (lowerName.includes(category)) {
|
|
330
|
+
return [...tools];
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Return minimal set
|
|
335
|
+
return ['file_read', 'search_files'];
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Set available tools from MCP discovery
|
|
340
|
+
* @param {Array<string>} tools - Available tool names
|
|
341
|
+
*/
|
|
342
|
+
setAvailableTools(tools) {
|
|
343
|
+
this.availableTools = new Set(tools);
|
|
344
|
+
this.emit('availableToolsUpdated', tools);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Validate tool availability for a skill
|
|
349
|
+
* @param {string} skillName - Skill name
|
|
350
|
+
* @returns {Object} Validation result
|
|
351
|
+
*/
|
|
352
|
+
validateToolAvailability(skillName) {
|
|
353
|
+
const allowedTools = this.getAllowedTools(skillName);
|
|
354
|
+
const available = [];
|
|
355
|
+
const missing = [];
|
|
356
|
+
|
|
357
|
+
for (const tool of allowedTools) {
|
|
358
|
+
if (this.availableTools.size === 0 || this.availableTools.has(tool)) {
|
|
359
|
+
available.push(tool);
|
|
360
|
+
} else {
|
|
361
|
+
missing.push(tool);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return {
|
|
366
|
+
valid: missing.length === 0,
|
|
367
|
+
available,
|
|
368
|
+
missing,
|
|
369
|
+
coverage: available.length / allowedTools.length
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Generate optimized tool configuration for a skill
|
|
375
|
+
* @param {string} skillName - Skill name
|
|
376
|
+
* @param {Object} context - Execution context
|
|
377
|
+
* @returns {Object} Optimized tool config
|
|
378
|
+
*/
|
|
379
|
+
generateOptimizedConfig(skillName, context = {}) {
|
|
380
|
+
const config = this.getSkillConfig(skillName);
|
|
381
|
+
const allowedTools = this.getAllowedTools(skillName, { filterByAvailable: true });
|
|
382
|
+
|
|
383
|
+
// Apply context-based optimization
|
|
384
|
+
let optimizedTools = [...allowedTools];
|
|
385
|
+
|
|
386
|
+
if (context.readOnly) {
|
|
387
|
+
// Remove write operations
|
|
388
|
+
optimizedTools = optimizedTools.filter(t =>
|
|
389
|
+
!t.includes('write') && !t.includes('create') && !t.includes('delete')
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (context.noNetwork) {
|
|
394
|
+
// Remove network operations
|
|
395
|
+
optimizedTools = optimizedTools.filter(t =>
|
|
396
|
+
!t.includes('http') && !t.includes('api') && !t.includes('fetch')
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if (context.minimalPermissions) {
|
|
401
|
+
// Keep only essential tools
|
|
402
|
+
optimizedTools = optimizedTools.filter(t =>
|
|
403
|
+
t.includes('read') || t.includes('search') || t.includes('list')
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return {
|
|
408
|
+
skillName,
|
|
409
|
+
allowedTools: optimizedTools,
|
|
410
|
+
restrictionLevel: config?.restrictionLevel || RestrictionLevel.STANDARD,
|
|
411
|
+
context
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Auto-configure skills based on skill definitions
|
|
417
|
+
* @param {Array<Object>} skills - Skill definitions
|
|
418
|
+
* @returns {Map<string, SkillToolConfig>} Generated configurations
|
|
419
|
+
*/
|
|
420
|
+
autoConfigureSkills(skills) {
|
|
421
|
+
const configs = new Map();
|
|
422
|
+
|
|
423
|
+
for (const skill of skills) {
|
|
424
|
+
const skillName = skill.name || skill.id;
|
|
425
|
+
|
|
426
|
+
// Determine category from skill metadata
|
|
427
|
+
const category = this._detectSkillCategory(skill);
|
|
428
|
+
const defaultTools = DEFAULT_TOOL_SETS[category] || DEFAULT_TOOL_SETS.validation;
|
|
429
|
+
|
|
430
|
+
// Merge with explicitly defined tools
|
|
431
|
+
const allowedTools = skill.allowedTools
|
|
432
|
+
? [...new Set([...defaultTools, ...skill.allowedTools])]
|
|
433
|
+
: defaultTools;
|
|
434
|
+
|
|
435
|
+
const config = this.setSkillConfig(skillName, {
|
|
436
|
+
allowedTools,
|
|
437
|
+
restrictionLevel: skill.restrictionLevel || RestrictionLevel.STANDARD
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
configs.set(skillName, config);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return configs;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Detect skill category from definition
|
|
448
|
+
* @private
|
|
449
|
+
*/
|
|
450
|
+
_detectSkillCategory(skill) {
|
|
451
|
+
const text = `${skill.name || ''} ${skill.description || ''} ${skill.purpose || ''}`.toLowerCase();
|
|
452
|
+
|
|
453
|
+
const categoryKeywords = {
|
|
454
|
+
requirements: ['requirement', 'ears', 'spec', 'feature'],
|
|
455
|
+
design: ['design', 'architecture', 'c4', 'adr'],
|
|
456
|
+
implementation: ['implement', 'code', 'develop', 'build'],
|
|
457
|
+
testing: ['test', 'spec', 'coverage', 'assertion'],
|
|
458
|
+
validation: ['validate', 'check', 'verify', 'lint'],
|
|
459
|
+
documentation: ['document', 'readme', 'guide', 'doc'],
|
|
460
|
+
analysis: ['analyze', 'audit', 'review', 'inspect'],
|
|
461
|
+
deployment: ['deploy', 'release', 'publish', 'ci']
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
for (const [category, keywords] of Object.entries(categoryKeywords)) {
|
|
465
|
+
for (const keyword of keywords) {
|
|
466
|
+
if (text.includes(keyword)) {
|
|
467
|
+
return category;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return 'validation'; // Default category
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Export all configurations
|
|
477
|
+
* @returns {Object} Configuration export
|
|
478
|
+
*/
|
|
479
|
+
exportConfig() {
|
|
480
|
+
const skills = {};
|
|
481
|
+
for (const [name, config] of this.skillConfigs) {
|
|
482
|
+
skills[name] = config.toJSON();
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
const toolDependencies = {};
|
|
486
|
+
for (const [tool, deps] of this.toolDependencies) {
|
|
487
|
+
toolDependencies[tool] = deps;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
return {
|
|
491
|
+
version: '1.0.0',
|
|
492
|
+
exportedAt: new Date().toISOString(),
|
|
493
|
+
defaults: {
|
|
494
|
+
toolSet: this.options.defaultToolSet
|
|
495
|
+
},
|
|
496
|
+
toolDependencies,
|
|
497
|
+
skills
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Save configuration to file
|
|
503
|
+
* @param {string} filePath - Output file path
|
|
504
|
+
* @returns {Promise<void>}
|
|
505
|
+
*/
|
|
506
|
+
async saveConfig(filePath) {
|
|
507
|
+
const config = this.exportConfig();
|
|
508
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
509
|
+
|
|
510
|
+
let content;
|
|
511
|
+
if (ext === '.yaml' || ext === '.yml') {
|
|
512
|
+
content = yaml.dump(config, { indent: 2 });
|
|
513
|
+
} else {
|
|
514
|
+
content = JSON.stringify(config, null, 2);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
|
|
518
|
+
await fs.promises.writeFile(filePath, content, 'utf-8');
|
|
519
|
+
|
|
520
|
+
this.emit('configSaved', filePath);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Clear all configurations
|
|
525
|
+
*/
|
|
526
|
+
clear() {
|
|
527
|
+
this.skillConfigs.clear();
|
|
528
|
+
this.toolDependencies.clear();
|
|
529
|
+
this.availableTools.clear();
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Get summary statistics
|
|
534
|
+
* @returns {Object} Statistics
|
|
535
|
+
*/
|
|
536
|
+
getStats() {
|
|
537
|
+
const skills = Array.from(this.skillConfigs.values());
|
|
538
|
+
|
|
539
|
+
const byRestriction = {};
|
|
540
|
+
for (const level of Object.values(RestrictionLevel)) {
|
|
541
|
+
byRestriction[level] = skills.filter(s => s.restrictionLevel === level).length;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
const allTools = new Set();
|
|
545
|
+
for (const config of skills) {
|
|
546
|
+
for (const tool of config.allowedTools) {
|
|
547
|
+
allTools.add(tool);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
return {
|
|
552
|
+
totalSkills: this.skillConfigs.size,
|
|
553
|
+
totalUniqueTools: allTools.size,
|
|
554
|
+
availableTools: this.availableTools.size,
|
|
555
|
+
byRestrictionLevel: byRestriction
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
module.exports = {
|
|
561
|
+
SkillToolsManager,
|
|
562
|
+
SkillToolConfig,
|
|
563
|
+
RestrictionLevel,
|
|
564
|
+
DEFAULT_TOOL_SETS
|
|
565
|
+
};
|
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
* @module monitoring/cost-tracker
|
|
4
4
|
* @version 1.0.0
|
|
5
5
|
* @description Tracks LLM API usage and costs across providers
|
|
6
|
+
*
|
|
7
|
+
* Part of MUSUBI v5.0.0 - Production Readiness
|
|
8
|
+
*
|
|
9
|
+
* @traceability
|
|
10
|
+
* - Requirement: REQ-P5-005 (Cost Tracking)
|
|
11
|
+
* - Design: docs/design/tdd-musubi-v5.0.0.md#3.5
|
|
12
|
+
* - Test: tests/monitoring/cost-tracker.test.js
|
|
6
13
|
*/
|
|
7
14
|
|
|
8
15
|
'use strict';
|
|
@@ -6,6 +6,16 @@
|
|
|
6
6
|
* - Runbook execution
|
|
7
7
|
* - Post-mortem generation
|
|
8
8
|
* - On-call management
|
|
9
|
+
*
|
|
10
|
+
* Part of MUSUBI v5.0.0 - Production Readiness
|
|
11
|
+
*
|
|
12
|
+
* @module monitoring/incident-manager
|
|
13
|
+
* @version 1.0.0
|
|
14
|
+
*
|
|
15
|
+
* @traceability
|
|
16
|
+
* - Requirement: REQ-P5-002 (Incident Management)
|
|
17
|
+
* - Design: docs/design/tdd-musubi-v5.0.0.md#3.2
|
|
18
|
+
* - Test: tests/monitoring/incident-manager.test.js
|
|
9
19
|
*/
|
|
10
20
|
|
|
11
21
|
const { EventEmitter } = require('events');
|
|
@@ -6,6 +6,16 @@
|
|
|
6
6
|
* - Metrics collection
|
|
7
7
|
* - Distributed tracing
|
|
8
8
|
* - Correlation IDs
|
|
9
|
+
*
|
|
10
|
+
* Part of MUSUBI v5.0.0 - Production Readiness
|
|
11
|
+
*
|
|
12
|
+
* @module monitoring/observability
|
|
13
|
+
* @version 1.0.0
|
|
14
|
+
*
|
|
15
|
+
* @traceability
|
|
16
|
+
* - Requirement: REQ-P5-004 (Observability Integration)
|
|
17
|
+
* - Design: docs/design/tdd-musubi-v5.0.0.md#3.4
|
|
18
|
+
* - Test: tests/monitoring/observability.test.js
|
|
9
19
|
*/
|
|
10
20
|
|
|
11
21
|
const { EventEmitter } = require('events');
|