claude-flow-novice 2.14.15 → 2.14.17
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/.claude/commands/cfn-loop-cli.md +160 -53
- package/claude-assets/agents/custom/cfn-system-expert.md +262 -0
- package/claude-assets/commands/cfn-loop-cli.md +160 -53
- package/dist/agent/skill-mcp-selector.js +459 -0
- package/dist/agent/skill-mcp-selector.js.map +1 -0
- package/dist/agents/agent-loader.js +146 -165
- package/dist/agents/agent-loader.js.map +1 -1
- package/dist/cli/agent-token-manager.js +382 -0
- package/dist/cli/agent-token-manager.js.map +1 -0
- package/dist/cli/config-manager.js.map +1 -1
- package/dist/mcp/auth-middleware.js +367 -0
- package/dist/mcp/auth-middleware.js.map +1 -0
- package/dist/mcp/playwright-mcp-server-auth.js +515 -0
- package/dist/mcp/playwright-mcp-server-auth.js.map +1 -0
- package/package.json +1 -1
|
@@ -15,7 +15,7 @@ Execute CFN Loop using CLI spawning for maximum cost savings (95-98% vs Task too
|
|
|
15
15
|
## What is CLI Mode?
|
|
16
16
|
|
|
17
17
|
**CLI Mode Architecture v3.0 (Enhanced):**
|
|
18
|
-
- Main Chat spawns **single coordinator agent**
|
|
18
|
+
- Main Chat spawns **single coordinator agent**
|
|
19
19
|
- Enhanced coordinator spawns **all workers via CLI** with protocol compliance
|
|
20
20
|
- CLI agents use **Z.ai custom routing** (when enabled)
|
|
21
21
|
- **Real-time monitoring** with automatic recovery from stuck agents
|
|
@@ -77,59 +77,16 @@ Savings: 64% with custom routing, 95-98% vs all-Task
|
|
|
77
77
|
| Standard | ≥0.75 | ≥0.90 | 10 | 3-4 | Production features |
|
|
78
78
|
| Enterprise | ≥0.85 | ≥0.95 | 15 | 5 | Security, compliance, critical systems |
|
|
79
79
|
|
|
80
|
-
##
|
|
80
|
+
## How CLI Mode Works
|
|
81
81
|
|
|
82
|
-
**
|
|
82
|
+
1. **Main Chat** spawns a single `cfn-v3-coordinator` agent
|
|
83
|
+
2. **Coordinator** orchestrates the entire CFN Loop workflow
|
|
84
|
+
3. **Loop 3** agents implement the solution and validate against quality gates
|
|
85
|
+
4. **Loop 2** agents review and provide validation feedback
|
|
86
|
+
5. **Product Owner** makes the final decision on deliverables
|
|
87
|
+
6. **Background execution** with Redis coordination for scalability
|
|
83
88
|
|
|
84
|
-
|
|
85
|
-
**DO NOT spawn cfn-v3-coordinator manually**
|
|
86
|
-
**DO NOT spawn Loop 3 agents (backend-dev, researcher, etc.)**
|
|
87
|
-
**DO NOT spawn Loop 2 agents (reviewer, tester, etc.)**
|
|
88
|
-
**DO NOT spawn product-owner**
|
|
89
|
-
|
|
90
|
-
**Main Chat simply executes the slash command - everything else is automatic**
|
|
91
|
-
|
|
92
|
-
---
|
|
93
|
-
|
|
94
|
-
## How This Command Works:
|
|
95
|
-
|
|
96
|
-
When Main Chat executes `/cfn-loop-cli "task description"`, this slash command:
|
|
97
|
-
|
|
98
|
-
1. **Automatically spawns cfn-v3-coordinator** with proper parameters
|
|
99
|
-
2. **Coordinator invokes enhanced orchestrator** with monitoring v3.0
|
|
100
|
-
3. **Orchestrator spawns all agents via CLI** (background execution)
|
|
101
|
-
4. **Handles complete CFN Loop workflow** with real-time monitoring
|
|
102
|
-
5. **Returns structured result** to Main Chat when complete
|
|
103
|
-
|
|
104
|
-
## Enhanced Features v3.0:
|
|
105
|
-
|
|
106
|
-
- ✅ **Real-time monitoring** with automatic stuck agent recovery
|
|
107
|
-
- ✅ **Process health checking** and dead process cleanup
|
|
108
|
-
- ✅ **Protocol compliance** preventing "consensus on vapor" anti-patterns
|
|
109
|
-
- ✅ **Progress visibility** with detailed timestamped reports
|
|
110
|
-
- ✅ **95-98% cost savings** with Z.ai routing optimization
|
|
111
|
-
- ✅ **Background execution** with Redis persistence
|
|
112
|
-
|
|
113
|
-
## Main Chat Execution Rules
|
|
114
|
-
|
|
115
|
-
**THIS SLASH COMMAND HANDLES EVERYTHING AUTOMATICALLY**
|
|
116
|
-
|
|
117
|
-
**Main Chat simply executes:**
|
|
118
|
-
```bash
|
|
119
|
-
/cfn-loop-cli "Task description" --mode=standard
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
**The slash command automatically:**
|
|
123
|
-
- ✅ Spawns coordinator with proper parameters
|
|
124
|
-
- ✅ Handles all agent spawning via CLI
|
|
125
|
-
- ✅ Manages complete CFN Loop workflow
|
|
126
|
-
- ✅ Returns structured result when complete
|
|
127
|
-
|
|
128
|
-
**Main Chat should NOT:**
|
|
129
|
-
- ❌ Manually spawn any Task() agents for CFN Loop
|
|
130
|
-
- ❌ Ask about retry/iteration decisions (handled automatically)
|
|
131
|
-
- ❌ Monitor agent progress (slash command handles this)
|
|
132
|
-
- ❌ Coordinate between agents (built-in coordination)
|
|
89
|
+
The coordinator handles all agent spawning internally using optimized CLI processes.
|
|
133
90
|
|
|
134
91
|
## CLI Mode Benefits
|
|
135
92
|
|
|
@@ -186,6 +143,33 @@ When Main Chat executes `/cfn-loop-cli "task description"`, this slash command:
|
|
|
186
143
|
- Will force ITERATE if git diff shows zero changes
|
|
187
144
|
- Check coordinator output for validation failures
|
|
188
145
|
|
|
146
|
+
**Web Portal Access:**
|
|
147
|
+
- Monitor real-time agent progress at http://localhost:3000
|
|
148
|
+
- View detailed execution logs and health status
|
|
149
|
+
- Track iteration progress and confidence scores
|
|
150
|
+
|
|
151
|
+
## Usage Examples
|
|
152
|
+
|
|
153
|
+
**Simple API Development:**
|
|
154
|
+
```bash
|
|
155
|
+
/cfn-loop-cli "Build REST API with user authentication"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Complex Feature with High Quality Requirements:**
|
|
159
|
+
```bash
|
|
160
|
+
/cfn-loop-cli "Implement payment processing with PCI compliance" --mode=enterprise --max-iterations=15
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Quick Prototype:**
|
|
164
|
+
```bash
|
|
165
|
+
/cfn-loop-cli "Build MVP landing page" --mode=mvp
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Infrastructure Deployment:**
|
|
169
|
+
```bash
|
|
170
|
+
/cfn-loop-cli "Set up CI/CD pipeline for microservices"
|
|
171
|
+
```
|
|
172
|
+
|
|
189
173
|
## Related Commands
|
|
190
174
|
|
|
191
175
|
- **Task Mode**: `/cfn-loop-task` (debugging, full visibility)
|
|
@@ -201,4 +185,127 @@ When Main Chat executes `/cfn-loop-cli "task description"`, this slash command:
|
|
|
201
185
|
|
|
202
186
|
---
|
|
203
187
|
|
|
204
|
-
|
|
188
|
+
## 🚨 EXECUTION INSTRUCTIONS (Internal Use)
|
|
189
|
+
|
|
190
|
+
**Main Chat: Execute this Task() call after slash command processing:**
|
|
191
|
+
|
|
192
|
+
```javascript
|
|
193
|
+
Task("cfn-v3-coordinator", `
|
|
194
|
+
CFN LOOP CLI MODE v3.0 - PRODUCTION EXECUTION WITH ENHANCED MONITORING
|
|
195
|
+
|
|
196
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
197
|
+
TASK SPECIFICATION
|
|
198
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
199
|
+
|
|
200
|
+
Task Description: $ARGUMENTS
|
|
201
|
+
Task ID: cfn-cli-$(date +%s%N | tail -c 7)-${RANDOM}
|
|
202
|
+
Mode: ${mode.toUpperCase()}
|
|
203
|
+
|
|
204
|
+
Enhanced Monitoring: Real-time agent tracking, automatic recovery, protocol compliance
|
|
205
|
+
|
|
206
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
207
|
+
SUCCESS CRITERIA
|
|
208
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
209
|
+
|
|
210
|
+
Acceptance Criteria:
|
|
211
|
+
- [ ] Core functionality implemented
|
|
212
|
+
- [ ] All tests pass with >80% coverage
|
|
213
|
+
- [ ] Security review completed
|
|
214
|
+
- [ ] Documentation updated
|
|
215
|
+
- [ ] No regression in existing features
|
|
216
|
+
|
|
217
|
+
Quality Gates (${mode.toUpperCase()} MODE):
|
|
218
|
+
- Loop 3 Gate Threshold: ${mode === 'enterprise' ? 0.85 : mode === 'standard' ? 0.75 : 0.70}
|
|
219
|
+
- Loop 2 Consensus Threshold: ${mode === 'enterprise' ? 0.95 : mode === 'standard' ? 0.90 : 0.80}
|
|
220
|
+
- Max Iterations: ${maxIterations}
|
|
221
|
+
|
|
222
|
+
Definition of Done:
|
|
223
|
+
- Consensus ≥ threshold achieved
|
|
224
|
+
- All acceptance criteria met
|
|
225
|
+
- Product Owner approval received
|
|
226
|
+
|
|
227
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
228
|
+
ENHANCED ORCHESTRATION CONFIGURATION v3.0
|
|
229
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
230
|
+
|
|
231
|
+
Mode: ${mode.toUpperCase()}
|
|
232
|
+
Enhanced Features: Real-time monitoring, automatic recovery, protocol compliance
|
|
233
|
+
|
|
234
|
+
Loop 3 Agents (Implementation) - SELECT BASED ON TASK:
|
|
235
|
+
Examples:
|
|
236
|
+
- Backend API: backend-dev, researcher, devops
|
|
237
|
+
- Full-Stack: backend-dev, react-frontend-engineer, devops
|
|
238
|
+
- Infrastructure: devops, rust-developer, researcher
|
|
239
|
+
- Security: security-specialist, backend-dev, researcher
|
|
240
|
+
|
|
241
|
+
Loop 2 Agents (Validation) - SCALE BY COMPLEXITY:
|
|
242
|
+
Simple (1-2 files): reviewer, tester
|
|
243
|
+
Standard (3-5 files): reviewer, tester, architect, security-specialist
|
|
244
|
+
Complex (>5 files): +code-analyzer, +performance-benchmarker
|
|
245
|
+
|
|
246
|
+
Product Owner: product-owner
|
|
247
|
+
|
|
248
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
249
|
+
EXECUTION INSTRUCTIONS (Enhanced v3.0)
|
|
250
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
251
|
+
|
|
252
|
+
1. INVOKE ENHANCED ORCHESTRATOR (CLI spawning with monitoring):
|
|
253
|
+
|
|
254
|
+
TASK_ID="cfn-cli-$(date +%s%N | tail -c 7)-${RANDOM}"
|
|
255
|
+
MODE="${mode}"
|
|
256
|
+
LOOP3_AGENTS="backend-dev,researcher,devops" # Customize for task
|
|
257
|
+
LOOP2_AGENTS="reviewer,tester,architect,security-specialist" # Scale by complexity
|
|
258
|
+
|
|
259
|
+
./.claude/skills/cfn-loop-orchestration/orchestrate.sh \\
|
|
260
|
+
--task-id "$TASK_ID" \\
|
|
261
|
+
--mode "$MODE" \\
|
|
262
|
+
--loop3-agents "$LOOP3_AGENTS" \\
|
|
263
|
+
--loop2-agents "$LOOP2_AGENTS" \\
|
|
264
|
+
--product-owner "product-owner" \\
|
|
265
|
+
--max-iterations ${maxIterations}
|
|
266
|
+
|
|
267
|
+
2. ENHANCED ORCHESTRATOR HANDLES v3.0:
|
|
268
|
+
- ✅ Spawns all agents via CLI (background) with protocol compliance
|
|
269
|
+
- ✅ Real-time agent progress monitoring and stuck detection
|
|
270
|
+
- ✅ Automatic recovery from dead processes
|
|
271
|
+
- ✅ Enhanced context validation prevents "consensus on vapor"
|
|
272
|
+
- ✅ Loop 3: Gate check (≥threshold) → PASS/ITERATE with health verification
|
|
273
|
+
- ✅ Loop 2: Consensus check (≥threshold) → COMPLETE/ITERATE
|
|
274
|
+
- ✅ Product Owner: PROCEED/ITERATE/ABORT decision with deliverable validation
|
|
275
|
+
- ✅ Git commit/push on PROCEED
|
|
276
|
+
- ✅ Returns structured result to Main Chat
|
|
277
|
+
|
|
278
|
+
3. RETURN STRUCTURED RESULT:
|
|
279
|
+
{
|
|
280
|
+
"taskId": "cfn-cli-XXXXX",
|
|
281
|
+
"status": "complete|failed",
|
|
282
|
+
"iterations": {"loop3": N, "loop2": M},
|
|
283
|
+
"finalConsensus": 0.XX,
|
|
284
|
+
"acceptanceCriteria": {
|
|
285
|
+
"met": [...],
|
|
286
|
+
"pending": [...]
|
|
287
|
+
},
|
|
288
|
+
"deliverables": [...],
|
|
289
|
+
"enhancedMonitoring": {
|
|
290
|
+
"agentHealth": "healthy|recovered",
|
|
291
|
+
"processRecovery": true,
|
|
292
|
+
"protocolCompliance": true
|
|
293
|
+
},
|
|
294
|
+
"recommendations": [...]
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
298
|
+
CRITICAL ENHANCED RULES v3.0
|
|
299
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
300
|
+
|
|
301
|
+
- ✅ USE enhanced orchestration script with real-time monitoring
|
|
302
|
+
- ✅ ALL agents run in background via npx claude-flow-novice (enhanced v3.0)
|
|
303
|
+
- ✅ USE Redis BLPOP for loop dependencies (zero-token coordination)
|
|
304
|
+
- ✅ AGENTS use Z.ai routing automatically (when enabled)
|
|
305
|
+
- ✅ ENFORCE protocol compliance (prevent "consensus on vapor")
|
|
306
|
+
- ✅ MONITOR agent health and auto-recover stuck processes
|
|
307
|
+
- ✅ RETURN structured result with enhanced monitoring data
|
|
308
|
+
`, "cfn-v3-coordinator")
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
**Version:** 3.0.0 (2025-11-05) - Enhanced CLI mode: production execution with real-time monitoring, automatic recovery, and protocol compliance
|
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill-based MCP Selection System
|
|
3
|
+
* Automatically selects MCP servers based on agent skills and requirements
|
|
4
|
+
*/ const fs = require('fs').promises;
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const AgentTokenManager = require('../cli/agent-token-manager.js');
|
|
7
|
+
let SkillMCPSelector = class SkillMCPSelector {
|
|
8
|
+
constructor(options = {}){
|
|
9
|
+
this.tokenManager = new AgentTokenManager(options);
|
|
10
|
+
this.agentConfigPath = options.agentConfigPath || './config/agent-whitelist.json';
|
|
11
|
+
this.skillConfigPath = options.skillConfigPath || './config/skill-requirements.json';
|
|
12
|
+
this.mcpServersPath = options.mcpServersPath || './config/mcp-servers.json';
|
|
13
|
+
this.agentWhitelist = new Map();
|
|
14
|
+
this.skillRequirements = new Map();
|
|
15
|
+
this.mcpServers = new Map();
|
|
16
|
+
}
|
|
17
|
+
async initialize() {
|
|
18
|
+
await this.tokenManager.initialize();
|
|
19
|
+
await this.loadConfigurations();
|
|
20
|
+
console.log('[SkillMCPSelector] Initialized successfully');
|
|
21
|
+
}
|
|
22
|
+
async loadConfigurations() {
|
|
23
|
+
// Load agent whitelist
|
|
24
|
+
const agentConfig = await this.loadJson(this.agentConfigPath);
|
|
25
|
+
this.agentWhitelist.clear();
|
|
26
|
+
for (const agent of agentConfig.agents){
|
|
27
|
+
this.agentWhitelist.set(agent.type, agent);
|
|
28
|
+
}
|
|
29
|
+
// Load skill requirements
|
|
30
|
+
const skillConfig = await this.loadJson(this.skillConfigPath);
|
|
31
|
+
this.skillRequirements.clear();
|
|
32
|
+
for (const [tool, requirements] of Object.entries(skillConfig.tools)){
|
|
33
|
+
this.skillRequirements.set(tool, requirements);
|
|
34
|
+
}
|
|
35
|
+
// Load MCP server configurations
|
|
36
|
+
try {
|
|
37
|
+
const mcpConfig = await this.loadJson(this.mcpServersPath);
|
|
38
|
+
for (const [name, config] of Object.entries(mcpConfig.servers)){
|
|
39
|
+
this.mcpServers.set(name, config);
|
|
40
|
+
}
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.warn('[SkillMCPSelector] MCP servers config not found, using defaults');
|
|
43
|
+
this.initializeDefaultMCPServers();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async loadJson(filePath) {
|
|
47
|
+
const resolvedPath = path.resolve(filePath);
|
|
48
|
+
const content = await fs.readFile(resolvedPath, 'utf8');
|
|
49
|
+
return JSON.parse(content);
|
|
50
|
+
}
|
|
51
|
+
initializeDefaultMCPServers() {
|
|
52
|
+
// Default MCP server configurations
|
|
53
|
+
const defaultServers = {
|
|
54
|
+
'playwright': {
|
|
55
|
+
name: 'playwright',
|
|
56
|
+
displayName: 'Playwright Browser Automation',
|
|
57
|
+
description: 'Browser automation and screenshot capabilities',
|
|
58
|
+
containerImage: 'claude-flow-novice:mcp-playwright',
|
|
59
|
+
tools: [
|
|
60
|
+
'take_screenshot',
|
|
61
|
+
'search_google',
|
|
62
|
+
'navigate_and_interact'
|
|
63
|
+
],
|
|
64
|
+
skills: [
|
|
65
|
+
'browser-automation',
|
|
66
|
+
'screenshot-capture',
|
|
67
|
+
'web-interaction'
|
|
68
|
+
],
|
|
69
|
+
resourceRequirements: {
|
|
70
|
+
memoryMB: 1024,
|
|
71
|
+
cpuUnits: 2
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
'redis': {
|
|
75
|
+
name: 'redis',
|
|
76
|
+
displayName: 'Redis Database',
|
|
77
|
+
description: 'Redis key-value store operations',
|
|
78
|
+
containerImage: 'claude-flow-novice:mcp-redis',
|
|
79
|
+
tools: [
|
|
80
|
+
'redis_get',
|
|
81
|
+
'redis_set',
|
|
82
|
+
'redis_keys'
|
|
83
|
+
],
|
|
84
|
+
skills: [
|
|
85
|
+
'redis-operations',
|
|
86
|
+
'cache-management'
|
|
87
|
+
],
|
|
88
|
+
resourceRequirements: {
|
|
89
|
+
memoryMB: 256,
|
|
90
|
+
cpuUnits: 1
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
'postgres': {
|
|
94
|
+
name: 'postgres',
|
|
95
|
+
displayName: 'PostgreSQL Database',
|
|
96
|
+
description: 'PostgreSQL database operations',
|
|
97
|
+
containerImage: 'claude-flow-novice:mcp-postgres',
|
|
98
|
+
tools: [
|
|
99
|
+
'postgres_query',
|
|
100
|
+
'postgres_schema',
|
|
101
|
+
'postgres_migrate'
|
|
102
|
+
],
|
|
103
|
+
skills: [
|
|
104
|
+
'database-design',
|
|
105
|
+
'sql-operations'
|
|
106
|
+
],
|
|
107
|
+
resourceRequirements: {
|
|
108
|
+
memoryMB: 512,
|
|
109
|
+
cpuUnits: 2
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
'security-scanner': {
|
|
113
|
+
name: 'security-scanner',
|
|
114
|
+
displayName: 'Security Scanner',
|
|
115
|
+
description: 'Security vulnerability scanning and analysis',
|
|
116
|
+
containerImage: 'claude-flow-novice:mcp-security',
|
|
117
|
+
tools: [
|
|
118
|
+
'security_scan',
|
|
119
|
+
'vulnerability_check',
|
|
120
|
+
'compliance_validate'
|
|
121
|
+
],
|
|
122
|
+
skills: [
|
|
123
|
+
'security-auditing',
|
|
124
|
+
'vulnerability-scanning'
|
|
125
|
+
],
|
|
126
|
+
resourceRequirements: {
|
|
127
|
+
memoryMB: 1536,
|
|
128
|
+
cpuUnits: 4
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
for (const [name, config] of Object.entries(defaultServers)){
|
|
133
|
+
this.mcpServers.set(name, config);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Determine which MCP servers an agent needs based on their skills
|
|
138
|
+
*/ selectMCPServers(agentType, agentSkills = null) {
|
|
139
|
+
const agentConfig = this.agentWhitelist.get(agentType);
|
|
140
|
+
if (!agentConfig) {
|
|
141
|
+
throw new Error(`Unknown agent type: ${agentType}`);
|
|
142
|
+
}
|
|
143
|
+
// Use provided skills or fall back to agent config
|
|
144
|
+
const skills = agentSkills || agentConfig.skills;
|
|
145
|
+
// Determine required MCP servers based on skills
|
|
146
|
+
const requiredMCPServers = new Set();
|
|
147
|
+
const skillToMCPServerMap = this.getSkillToMCPServerMapping();
|
|
148
|
+
// Map skills to required MCP servers
|
|
149
|
+
for (const skill of skills){
|
|
150
|
+
if (skillToMCPServerMap.has(skill)) {
|
|
151
|
+
const servers = skillToMCPServerMap.get(skill);
|
|
152
|
+
servers.forEach((server)=>requiredMCPServers.add(server));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// Add explicitly allowed MCP servers from agent config
|
|
156
|
+
if (agentConfig.allowedMcpServers) {
|
|
157
|
+
agentConfig.allowedMcpServers.forEach((server)=>requiredMCPServers.add(server));
|
|
158
|
+
}
|
|
159
|
+
// Convert to array and sort by priority
|
|
160
|
+
const selectedServers = Array.from(requiredMCPServers).filter((server)=>this.mcpServers.has(server)).sort((a, b)=>{
|
|
161
|
+
const priorityA = this.mcpServers.get(a).priority || 999;
|
|
162
|
+
const priorityB = this.mcpServers.get(b).priority || 999;
|
|
163
|
+
return priorityA - priorityB;
|
|
164
|
+
});
|
|
165
|
+
return {
|
|
166
|
+
agentType,
|
|
167
|
+
agentSkills: skills,
|
|
168
|
+
selectedMCPServers,
|
|
169
|
+
serverDetails: selectedServers.map((server)=>this.mcpServers.get(server)),
|
|
170
|
+
totalMemoryRequired: selectedServers.reduce((sum, server)=>sum + (this.mcpServers.get(server).resourceRequirements?.memoryMB || 512), 0),
|
|
171
|
+
totalCPURequired: selectedServers.reduce((sum, server)=>sum + (this.mcpServers.get(server).resourceRequirements?.cpuUnits || 1), 0)
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Get mapping from skills to required MCP servers
|
|
176
|
+
*/ getSkillToMCPServerMapping() {
|
|
177
|
+
const skillMap = new Map();
|
|
178
|
+
// Build mapping from MCP server configurations
|
|
179
|
+
for (const [serverName, serverConfig] of this.mcpServers.entries()){
|
|
180
|
+
for (const skill of serverConfig.skills || []){
|
|
181
|
+
if (!skillMap.has(skill)) {
|
|
182
|
+
skillMap.set(skill, new Set());
|
|
183
|
+
}
|
|
184
|
+
skillMap.get(skill).add(serverName);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// Also add mappings from tool requirements
|
|
188
|
+
for (const [toolName, toolConfig] of this.skillRequirements.entries()){
|
|
189
|
+
for (const skill of toolConfig.requiredSkills || []){
|
|
190
|
+
// Find MCP servers that provide this tool
|
|
191
|
+
for (const [serverName, serverConfig] of this.mcpServers.entries()){
|
|
192
|
+
if (serverConfig.tools?.includes(toolName)) {
|
|
193
|
+
if (!skillMap.has(skill)) {
|
|
194
|
+
skillMap.set(skill, new Set());
|
|
195
|
+
}
|
|
196
|
+
skillMap.get(skill).add(serverName);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return skillMap;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Generate tokens for selected MCP servers
|
|
205
|
+
*/ async generateMCPTokens(agentType, selectedServers, options = {}) {
|
|
206
|
+
const tokens = [];
|
|
207
|
+
for (const serverName of selectedServers){
|
|
208
|
+
try {
|
|
209
|
+
const serverConfig = this.mcpServers.get(serverName);
|
|
210
|
+
if (!serverConfig) {
|
|
211
|
+
console.warn(`[SkillMCPSelector] Server configuration not found: ${serverName}`);
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
// Generate server-specific token
|
|
215
|
+
const tokenData = await this.tokenManager.registerAgentToken(agentType, {
|
|
216
|
+
expiresIn: options.expiresIn || '24h',
|
|
217
|
+
description: `Token for ${serverConfig.displayName}`,
|
|
218
|
+
createdBy: 'skill-mcp-selector',
|
|
219
|
+
mcpServer: serverName
|
|
220
|
+
});
|
|
221
|
+
tokens.push({
|
|
222
|
+
serverName,
|
|
223
|
+
displayName: serverConfig.displayName,
|
|
224
|
+
token: tokenData.token,
|
|
225
|
+
expiresAt: tokenData.expiresAt,
|
|
226
|
+
containerImage: serverConfig.containerImage,
|
|
227
|
+
connectionInfo: this.generateConnectionInfo(serverName, serverConfig, tokenData.token)
|
|
228
|
+
});
|
|
229
|
+
console.log(`[SkillMCPSelector] Generated token for ${agentType} → ${serverName}`);
|
|
230
|
+
} catch (error) {
|
|
231
|
+
console.error(`[SkillMCPSelector] Failed to generate token for ${serverName}:`, error);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return tokens;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Generate connection information for MCP server
|
|
238
|
+
*/ generateConnectionInfo(serverName, serverConfig, token) {
|
|
239
|
+
const baseInfo = {
|
|
240
|
+
serverName,
|
|
241
|
+
token,
|
|
242
|
+
authentication: {
|
|
243
|
+
type: 'token-based',
|
|
244
|
+
header: 'x-agent-token',
|
|
245
|
+
agentTypeHeader: 'x-agent-type'
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
// Add server-specific connection details
|
|
249
|
+
if (serverConfig.connectionType === 'docker') {
|
|
250
|
+
return {
|
|
251
|
+
...baseInfo,
|
|
252
|
+
type: 'docker-container',
|
|
253
|
+
containerName: `mcp-${serverName}`,
|
|
254
|
+
containerImage: serverConfig.containerImage,
|
|
255
|
+
dockerArgs: [
|
|
256
|
+
'run',
|
|
257
|
+
'--rm',
|
|
258
|
+
'--init',
|
|
259
|
+
'--name',
|
|
260
|
+
`mcp-${serverName}`,
|
|
261
|
+
'--memory',
|
|
262
|
+
`${serverConfig.resourceRequirements?.memoryMB || 512}m`,
|
|
263
|
+
'--cpus',
|
|
264
|
+
`${serverConfig.resourceRequirements?.cpuUnits || 1}`,
|
|
265
|
+
'-e',
|
|
266
|
+
`MCP_SERVER=${serverName}`,
|
|
267
|
+
'-e',
|
|
268
|
+
`MCP_AUTH_REQUIRED=true`,
|
|
269
|
+
'-e',
|
|
270
|
+
`MCP_REDIS_URL=${process.env.MCP_REDIS_URL || 'redis://localhost:6379'}`,
|
|
271
|
+
serverConfig.containerImage,
|
|
272
|
+
'node',
|
|
273
|
+
`/app/mcp-${serverName}-server.js`
|
|
274
|
+
]
|
|
275
|
+
};
|
|
276
|
+
} else {
|
|
277
|
+
return {
|
|
278
|
+
...baseInfo,
|
|
279
|
+
type: 'http-endpoint',
|
|
280
|
+
url: serverConfig.url || `http://localhost:${3000 + this.mcpServers.size}`,
|
|
281
|
+
headers: {
|
|
282
|
+
'Content-Type': 'application/json',
|
|
283
|
+
'x-agent-token': token,
|
|
284
|
+
'x-agent-type': 'dynamic'
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Get complete MCP configuration for an agent
|
|
291
|
+
*/ async getAgentMCPConfiguration(agentType, agentSkills = null, options = {}) {
|
|
292
|
+
try {
|
|
293
|
+
// Select required MCP servers
|
|
294
|
+
const selection = this.selectMCPServers(agentType, agentSkills);
|
|
295
|
+
// Generate tokens for selected servers
|
|
296
|
+
const tokens = await this.generateMCPTokens(agentType, selection.selectedMCPServers, options);
|
|
297
|
+
return {
|
|
298
|
+
agentType,
|
|
299
|
+
agentSkills: selection.agentSkills,
|
|
300
|
+
mcpConfiguration: {
|
|
301
|
+
mcpServers: tokens.reduce((config, tokenInfo)=>{
|
|
302
|
+
config[tokenInfo.serverName] = {
|
|
303
|
+
command: 'docker',
|
|
304
|
+
args: tokenInfo.connectionInfo.dockerArgs,
|
|
305
|
+
env: {
|
|
306
|
+
'MCP_SERVER': tokenInfo.serverName,
|
|
307
|
+
'MCP_AUTH_REQUIRED': 'true',
|
|
308
|
+
'AGENT_TOKEN': tokenInfo.token
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
return config;
|
|
312
|
+
}, {})
|
|
313
|
+
},
|
|
314
|
+
selection,
|
|
315
|
+
tokens,
|
|
316
|
+
resourceSummary: {
|
|
317
|
+
totalMemoryMB: selection.totalMemoryRequired,
|
|
318
|
+
totalCPUUnits: selection.totalCPUUnits,
|
|
319
|
+
serverCount: selection.selectedMCPServers.length
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
} catch (error) {
|
|
323
|
+
console.error(`[SkillMCPSelector] Failed to get MCP configuration for ${agentType}:`, error);
|
|
324
|
+
throw error;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Generate Docker Compose configuration for agent with MCP servers
|
|
329
|
+
*/ async generateDockerComposeConfiguration(agentType, agentSkills = null, options = {}) {
|
|
330
|
+
const config = await this.getAgentMCPConfiguration(agentType, agentSkills, options);
|
|
331
|
+
const dockerCompose = {
|
|
332
|
+
version: '3.8',
|
|
333
|
+
services: {},
|
|
334
|
+
networks: {
|
|
335
|
+
'mcp-network': {
|
|
336
|
+
driver: 'bridge'
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
// Add agent service
|
|
341
|
+
dockerCompose.services[`${agentType}-agent`] = {
|
|
342
|
+
image: 'claude-flow-novice:agent-container',
|
|
343
|
+
container_name: `agent-${agentType}-${Date.now()}`,
|
|
344
|
+
networks: [
|
|
345
|
+
'mcp-network'
|
|
346
|
+
],
|
|
347
|
+
environment: {
|
|
348
|
+
'AGENT_TYPE': agentType,
|
|
349
|
+
'AGENT_MODE': 'containerized',
|
|
350
|
+
'MCP_AUTH_ENABLED': 'true',
|
|
351
|
+
'REDIS_URL': process.env.MCP_REDIS_URL || 'redis://redis:6379'
|
|
352
|
+
},
|
|
353
|
+
volumes: [
|
|
354
|
+
'${PWD}/.claude:/app/.claude:ro',
|
|
355
|
+
'${PWD}/screenshots:/app/screenshots'
|
|
356
|
+
],
|
|
357
|
+
mem_limit: `${config.resourceSummary.totalMemoryMB + 512}m`,
|
|
358
|
+
depends_on: config.selection.selectedMCPServers.map((server)=>`mcp-${server}`).join(' ')
|
|
359
|
+
};
|
|
360
|
+
// Add MCP server services
|
|
361
|
+
for (const tokenInfo of config.tokens){
|
|
362
|
+
const serverName = `mcp-${tokenInfo.serverName}`;
|
|
363
|
+
const serverConfig = this.mcpServers.get(tokenInfo.serverName);
|
|
364
|
+
dockerCompose.services[serverName] = {
|
|
365
|
+
image: tokenInfo.containerImage,
|
|
366
|
+
container_name: `${serverName}-${Date.now()}`,
|
|
367
|
+
networks: [
|
|
368
|
+
'mcp-network'
|
|
369
|
+
],
|
|
370
|
+
environment: {
|
|
371
|
+
'MCP_SERVER': tokenInfo.serverName,
|
|
372
|
+
'MCP_AUTH_REQUIRED': 'true',
|
|
373
|
+
'MCP_REDIS_URL': process.env.MCP_REDIS_URL || 'redis://redis:6379',
|
|
374
|
+
'AGENT_TOKEN': tokenInfo.token
|
|
375
|
+
},
|
|
376
|
+
volumes: [
|
|
377
|
+
'${PWD}/screenshots:/app/screenshots'
|
|
378
|
+
],
|
|
379
|
+
mem_limit: `${serverConfig.resourceRequirements?.memoryMB || 512}m`,
|
|
380
|
+
cpus: `${(serverConfig.resourceRequirements?.cpuUnits || 1) / 4}`
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
// Add Redis service if not present
|
|
384
|
+
if (!dockerCompose.services.redis) {
|
|
385
|
+
dockerCompose.services.redis = {
|
|
386
|
+
image: 'redis:7-alpine',
|
|
387
|
+
container_name: 'mcp-redis',
|
|
388
|
+
networks: [
|
|
389
|
+
'mcp-network'
|
|
390
|
+
],
|
|
391
|
+
volumes: [
|
|
392
|
+
'redis-data:/data'
|
|
393
|
+
],
|
|
394
|
+
mem_limit: '256m'
|
|
395
|
+
};
|
|
396
|
+
dockerCompose.volumes = {
|
|
397
|
+
'redis-data': {}
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
return dockerCompose;
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Get statistics about skill-MCP mappings
|
|
404
|
+
*/ getStatistics() {
|
|
405
|
+
const skillMap = this.getSkillToMCPServerMapping();
|
|
406
|
+
return {
|
|
407
|
+
totalAgents: this.agentWhitelist.size,
|
|
408
|
+
totalMCPServers: this.mcpServers.size,
|
|
409
|
+
totalSkills: skillMap.size,
|
|
410
|
+
agentTypes: Array.from(this.agentWhitelist.keys()),
|
|
411
|
+
mcpServerNames: Array.from(this.mcpServers.keys()),
|
|
412
|
+
skillCoverage: Array.from(skillMap.entries()).map(([skill, servers])=>({
|
|
413
|
+
skill,
|
|
414
|
+
requiredServers: Array.from(servers),
|
|
415
|
+
serverCount: servers.size
|
|
416
|
+
}))
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Validate agent-MCP configuration
|
|
421
|
+
*/ validateConfiguration(agentType, mcpConfiguration) {
|
|
422
|
+
const agentConfig = this.agentWhitelist.get(agentType);
|
|
423
|
+
if (!agentConfig) {
|
|
424
|
+
return {
|
|
425
|
+
valid: false,
|
|
426
|
+
errors: [
|
|
427
|
+
`Unknown agent type: ${agentType}`
|
|
428
|
+
]
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
const errors = [];
|
|
432
|
+
const warnings = [];
|
|
433
|
+
// Check required MCP servers
|
|
434
|
+
const requiredServers = agentConfig.allowedMcpServers || [];
|
|
435
|
+
const configuredServers = Object.keys(mcpConfiguration.mcpServers || {});
|
|
436
|
+
for (const server of requiredServers){
|
|
437
|
+
if (!configuredServers.includes(server)) {
|
|
438
|
+
errors.push(`Required MCP server missing: ${server}`);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
// Check for unauthorized servers
|
|
442
|
+
for (const server of configuredServers){
|
|
443
|
+
if (!requiredServers.includes(server)) {
|
|
444
|
+
warnings.push(`Potentially unauthorized MCP server: ${server}`);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
return {
|
|
448
|
+
valid: errors.length === 0,
|
|
449
|
+
errors,
|
|
450
|
+
warnings
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
async shutdown() {
|
|
454
|
+
await this.tokenManager.shutdown();
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
module.exports = SkillMCPSelector;
|
|
458
|
+
|
|
459
|
+
//# sourceMappingURL=skill-mcp-selector.js.map
|