telos-framework 0.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/LICENSE +21 -0
- package/README.md +245 -0
- package/USAGE.md +337 -0
- package/bin/telos-cli.js +41 -0
- package/lib/commands/init.js +112 -0
- package/lib/commands/rediscover.js +48 -0
- package/lib/commands/status.js +77 -0
- package/lib/commands/validate.js +148 -0
- package/lib/discovery/code-scanner.js +129 -0
- package/lib/discovery/hierarchy-builder.js +147 -0
- package/lib/discovery/mcp-discovery.js +90 -0
- package/lib/discovery/telos-discovery.js +69 -0
- package/lib/discovery/tool-mapper.js +151 -0
- package/lib/generators/agent-generator.js +374 -0
- package/lib/generators/agents-md-generator.js +73 -0
- package/lib/generators/all-agents-generator.js +196 -0
- package/lib/generators/logos-md-generator.js +192 -0
- package/lib/generators/telos-md-generator.js +121 -0
- package/lib/generators/tools-md-generator.js +204 -0
- package/lib/integration/capability-abstraction.js +162 -0
- package/lib/integration/graceful-degradation.js +152 -0
- package/lib/integration/mcp-client.js +109 -0
- package/lib/integration/tool-config-writers.js +142 -0
- package/lib/integration/tool-invoker.js +166 -0
- package/lib/platform/platform-detector.js +74 -0
- package/lib/platform/symlink-creator.js +103 -0
- package/lib/spec/spec-formatter.js +79 -0
- package/lib/spec/spec-translator.js +150 -0
- package/lib/spec/validation-cascade.js +156 -0
- package/logos/orchestrator.js +139 -0
- package/logos/state-manager.js +137 -0
- package/package.json +59 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
const fs = require('fs').promises;
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
async function generateToolsMd(levelTools, projectScan, mcpServers, recommendations, outputPath) {
|
|
5
|
+
let content = `# Discovered Tools & Capabilities
|
|
6
|
+
|
|
7
|
+
**Generated**: ${new Date().toISOString()}
|
|
8
|
+
|
|
9
|
+
## Project Context
|
|
10
|
+
|
|
11
|
+
- **Languages**: ${projectScan.languages.join(', ') || 'None detected'}
|
|
12
|
+
- **Frameworks**: ${projectScan.frameworks.join(', ') || 'None detected'}
|
|
13
|
+
- **Package Managers**: ${projectScan.packageManagers.join(', ') || 'None detected'}
|
|
14
|
+
|
|
15
|
+
## MCP Servers
|
|
16
|
+
|
|
17
|
+
${mcpServers.length > 0 ? mcpServers.map(s => `- **${s.name}**: \`${s.command}\``).join('\n') : 'No MCP servers detected'}
|
|
18
|
+
|
|
19
|
+
## Tools by Agent Level
|
|
20
|
+
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
for (const [level, data] of Object.entries(levelTools)) {
|
|
24
|
+
content += `### ${level}: ${data.name}\n\n`;
|
|
25
|
+
|
|
26
|
+
if (data.tools.length > 0) {
|
|
27
|
+
content += '**Available Tools**:\n\n';
|
|
28
|
+
for (const tool of data.tools) {
|
|
29
|
+
content += `- **${tool.name}** (${tool.category}): ${tool.capability}\n`;
|
|
30
|
+
}
|
|
31
|
+
content += '\n';
|
|
32
|
+
} else {
|
|
33
|
+
content += '*No tools detected for this level*\n\n';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (recommendations.length > 0) {
|
|
38
|
+
content += `## Recommendations\n\n`;
|
|
39
|
+
for (const rec of recommendations) {
|
|
40
|
+
content += `- **${rec.level}** [${rec.priority}]: ${rec.message}\n`;
|
|
41
|
+
}
|
|
42
|
+
content += '\n';
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
content += `## Capability Matrix
|
|
46
|
+
|
|
47
|
+
| Level | Agent | Detected Capabilities |
|
|
48
|
+
|-------|-------|----------------------|
|
|
49
|
+
`;
|
|
50
|
+
|
|
51
|
+
for (const [level, data] of Object.entries(levelTools)) {
|
|
52
|
+
const caps = data.tools.map(t => t.capability).join(', ') || 'None';
|
|
53
|
+
content += `| ${level} | ${data.name} | ${caps} |\n`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
content += `
|
|
57
|
+
## Usage Instructions by Agent
|
|
58
|
+
|
|
59
|
+
### L1: Syntax-Linter
|
|
60
|
+
|
|
61
|
+
**Tools**: ${levelTools.L1.tools.map(t => t.name).join(', ') || 'None'}
|
|
62
|
+
|
|
63
|
+
**Workflow**:
|
|
64
|
+
1. Run linter before committing code
|
|
65
|
+
2. Fix syntax and style violations automatically when possible
|
|
66
|
+
3. Report unfixable issues for manual review
|
|
67
|
+
|
|
68
|
+
**Example Commands**:
|
|
69
|
+
- \`eslint --fix .\` - Auto-fix JavaScript/TypeScript issues
|
|
70
|
+
- \`prettier --write .\` - Format code
|
|
71
|
+
- \`ruff check .\` - Lint Python code
|
|
72
|
+
|
|
73
|
+
### L2: Function-Author
|
|
74
|
+
|
|
75
|
+
**Tools**: ${levelTools.L2.tools.map(t => t.name).join(', ') || 'None'}
|
|
76
|
+
|
|
77
|
+
**Workflow**:
|
|
78
|
+
1. Write tests first (TDD)
|
|
79
|
+
2. Implement function to pass tests
|
|
80
|
+
3. Verify with unit test suite
|
|
81
|
+
4. Refactor while keeping tests green
|
|
82
|
+
|
|
83
|
+
**Example Commands**:
|
|
84
|
+
- \`vitest run\` - Run unit tests
|
|
85
|
+
- \`jest --coverage\` - Run tests with coverage
|
|
86
|
+
- \`npm test\` - Run test script
|
|
87
|
+
|
|
88
|
+
### L3: Component-Architect
|
|
89
|
+
|
|
90
|
+
**Tools**: ${levelTools.L3.tools.map(t => t.name).join(', ') || 'None'}
|
|
91
|
+
|
|
92
|
+
**Workflow**:
|
|
93
|
+
1. Design component interface
|
|
94
|
+
2. Write component tests
|
|
95
|
+
3. Implement component
|
|
96
|
+
4. Verify integration with parent components
|
|
97
|
+
|
|
98
|
+
**Example Commands**:
|
|
99
|
+
- \`vitest --ui\` - Interactive test UI
|
|
100
|
+
- \`jest --testPathPattern=components\` - Test components only
|
|
101
|
+
|
|
102
|
+
### L4: Integration-Contractor
|
|
103
|
+
|
|
104
|
+
**Tools**: ${levelTools.L4.tools.map(t => t.name).join(', ') || 'None'}
|
|
105
|
+
|
|
106
|
+
**Workflow**:
|
|
107
|
+
1. Define API contracts
|
|
108
|
+
2. Write integration tests
|
|
109
|
+
3. Implement API endpoints
|
|
110
|
+
4. Verify contracts hold
|
|
111
|
+
|
|
112
|
+
**Example Commands**:
|
|
113
|
+
- \`curl -X POST http://localhost:3000/api/test\` - Manual API test
|
|
114
|
+
- Check integration test suite
|
|
115
|
+
|
|
116
|
+
### L5: Journey-Validator
|
|
117
|
+
|
|
118
|
+
**Tools**: ${levelTools.L5.tools.map(t => t.name).join(', ') || 'None'}
|
|
119
|
+
|
|
120
|
+
**Workflow**:
|
|
121
|
+
1. Define user journeys
|
|
122
|
+
2. Write E2E tests for critical paths
|
|
123
|
+
3. Run tests in multiple browsers
|
|
124
|
+
4. Verify complete user flows
|
|
125
|
+
|
|
126
|
+
**Example Commands**:
|
|
127
|
+
- \`playwright test\` - Run E2E tests
|
|
128
|
+
- \`cypress run\` - Run Cypress tests
|
|
129
|
+
- \`playwright test --ui\` - Debug tests interactively
|
|
130
|
+
|
|
131
|
+
### L6: UX-Simulator
|
|
132
|
+
|
|
133
|
+
**Tools**: ${levelTools.L6.tools.map(t => t.name).join(', ') || 'None'}
|
|
134
|
+
|
|
135
|
+
**Workflow**:
|
|
136
|
+
1. Create user personas
|
|
137
|
+
2. Simulate persona interactions
|
|
138
|
+
3. Test accessibility
|
|
139
|
+
4. Verify UX principles
|
|
140
|
+
|
|
141
|
+
**Example Commands**:
|
|
142
|
+
- Use browser MCP for automation
|
|
143
|
+
- Manual testing with personas
|
|
144
|
+
|
|
145
|
+
### L7: Insight-Synthesizer
|
|
146
|
+
|
|
147
|
+
**Tools**: ${levelTools.L7.tools.map(t => t.name).join(', ') || 'None'}
|
|
148
|
+
|
|
149
|
+
**Workflow**:
|
|
150
|
+
1. Collect analytics data
|
|
151
|
+
2. Gather user feedback
|
|
152
|
+
3. Synthesize insights
|
|
153
|
+
4. Report findings to higher levels
|
|
154
|
+
|
|
155
|
+
**Example Commands**:
|
|
156
|
+
- Query analytics MCP servers
|
|
157
|
+
- Review user feedback channels
|
|
158
|
+
|
|
159
|
+
### L8: Market-Analyst
|
|
160
|
+
|
|
161
|
+
**Tools**: ${levelTools.L8.tools.map(t => t.name).join(', ') || 'None'}
|
|
162
|
+
|
|
163
|
+
**Workflow**:
|
|
164
|
+
1. Define business KPIs
|
|
165
|
+
2. Track metrics
|
|
166
|
+
3. Analyze performance
|
|
167
|
+
4. Report to Telos-Guardian
|
|
168
|
+
|
|
169
|
+
**Example Commands**:
|
|
170
|
+
- Query business metrics databases
|
|
171
|
+
- Generate reports
|
|
172
|
+
|
|
173
|
+
### L9: Telos-Guardian
|
|
174
|
+
|
|
175
|
+
**Tools**: ${levelTools.L9.tools.map(t => t.name).join(', ') || 'None'}
|
|
176
|
+
|
|
177
|
+
**Workflow**:
|
|
178
|
+
1. Review alignment with Telos
|
|
179
|
+
2. Validate strategic decisions
|
|
180
|
+
3. Guide overall direction
|
|
181
|
+
4. Maintain purpose coherence
|
|
182
|
+
|
|
183
|
+
**Example Commands**:
|
|
184
|
+
- Review project documentation
|
|
185
|
+
- Validate specs against Telos
|
|
186
|
+
|
|
187
|
+
## Re-Discovery
|
|
188
|
+
|
|
189
|
+
To update this file after adding tools or MCP servers, run:
|
|
190
|
+
|
|
191
|
+
\`\`\`bash
|
|
192
|
+
telos rediscover
|
|
193
|
+
\`\`\`
|
|
194
|
+
|
|
195
|
+
This will re-scan your project and update agent configurations accordingly.
|
|
196
|
+
`;
|
|
197
|
+
|
|
198
|
+
await fs.mkdir(path.dirname(outputPath), { recursive: true });
|
|
199
|
+
await fs.writeFile(outputPath, content, 'utf8');
|
|
200
|
+
|
|
201
|
+
return outputPath;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
module.exports = { generateToolsMd };
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
const CAPABILITY_DEFINITIONS = {
|
|
2
|
+
'static-analysis': {
|
|
3
|
+
description: 'Analyze code for syntax errors, style violations, and potential bugs',
|
|
4
|
+
tools: ['eslint', 'ruff', 'pylint', 'rubocop', 'golint'],
|
|
5
|
+
fallback: 'manual-code-review'
|
|
6
|
+
},
|
|
7
|
+
'file-operations': {
|
|
8
|
+
description: 'Read, write, and manipulate files',
|
|
9
|
+
tools: ['filesystem-mcp', 'node-fs'],
|
|
10
|
+
fallback: 'direct-file-access'
|
|
11
|
+
},
|
|
12
|
+
'unit-testing': {
|
|
13
|
+
description: 'Execute and validate unit tests',
|
|
14
|
+
tools: ['vitest', 'jest', 'pytest', 'mocha', 'jasmine'],
|
|
15
|
+
fallback: 'manual-testing'
|
|
16
|
+
},
|
|
17
|
+
'component-testing': {
|
|
18
|
+
description: 'Test UI components in isolation',
|
|
19
|
+
tools: ['vitest', 'jest', 'testing-library', 'enzyme'],
|
|
20
|
+
fallback: 'unit-testing'
|
|
21
|
+
},
|
|
22
|
+
'api-testing': {
|
|
23
|
+
description: 'Test HTTP APIs and external integrations',
|
|
24
|
+
tools: ['supertest', 'requests', 'axios', 'fetch-mcp'],
|
|
25
|
+
fallback: 'manual-api-calls'
|
|
26
|
+
},
|
|
27
|
+
'journey-validation': {
|
|
28
|
+
description: 'End-to-end user journey testing',
|
|
29
|
+
tools: ['playwright', 'cypress', 'selenium'],
|
|
30
|
+
fallback: 'manual-ux-testing'
|
|
31
|
+
},
|
|
32
|
+
'ux-testing': {
|
|
33
|
+
description: 'User experience and accessibility testing',
|
|
34
|
+
tools: ['playwright', 'browser-mcp', 'axe-core'],
|
|
35
|
+
fallback: 'manual-ux-review'
|
|
36
|
+
},
|
|
37
|
+
'analytics': {
|
|
38
|
+
description: 'Collect and analyze user behavior metrics',
|
|
39
|
+
tools: ['analytics-mcp', 'posthog', 'mixpanel'],
|
|
40
|
+
fallback: 'log-analysis'
|
|
41
|
+
},
|
|
42
|
+
'business-metrics': {
|
|
43
|
+
description: 'Track KPIs and business performance',
|
|
44
|
+
tools: ['analytics-mcp', 'database-mcp'],
|
|
45
|
+
fallback: 'manual-reporting'
|
|
46
|
+
},
|
|
47
|
+
'version-control': {
|
|
48
|
+
description: 'Interact with Git and version control systems',
|
|
49
|
+
tools: ['github-mcp', 'git'],
|
|
50
|
+
fallback: 'manual-git'
|
|
51
|
+
},
|
|
52
|
+
'browser-automation': {
|
|
53
|
+
description: 'Automate browser interactions',
|
|
54
|
+
tools: ['playwright', 'browser-mcp', 'chrome-mcp'],
|
|
55
|
+
fallback: 'manual-browser-testing'
|
|
56
|
+
},
|
|
57
|
+
'database-access': {
|
|
58
|
+
description: 'Query and manipulate databases',
|
|
59
|
+
tools: ['postgres-mcp', 'mysql-mcp', 'database-mcp'],
|
|
60
|
+
fallback: 'manual-db-queries'
|
|
61
|
+
},
|
|
62
|
+
'web-research': {
|
|
63
|
+
description: 'Fetch and analyze web content',
|
|
64
|
+
tools: ['fetch-mcp', 'brave-search-mcp', 'http-client'],
|
|
65
|
+
fallback: 'manual-web-search'
|
|
66
|
+
},
|
|
67
|
+
'user-feedback': {
|
|
68
|
+
description: 'Collect and process user feedback',
|
|
69
|
+
tools: ['slack-mcp', 'email-mcp'],
|
|
70
|
+
fallback: 'manual-feedback-review'
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
class CapabilityManager {
|
|
75
|
+
constructor(availableTools = []) {
|
|
76
|
+
this.availableTools = availableTools;
|
|
77
|
+
this.capabilityMap = this.buildCapabilityMap();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
buildCapabilityMap() {
|
|
81
|
+
const map = {};
|
|
82
|
+
|
|
83
|
+
for (const [capability, definition] of Object.entries(CAPABILITY_DEFINITIONS)) {
|
|
84
|
+
const matchingTools = this.availableTools.filter(tool => {
|
|
85
|
+
const toolName = tool.name.toLowerCase();
|
|
86
|
+
return definition.tools.some(defTool => toolName.includes(defTool.toLowerCase()));
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
map[capability] = {
|
|
90
|
+
...definition,
|
|
91
|
+
available: matchingTools.length > 0,
|
|
92
|
+
tools: matchingTools,
|
|
93
|
+
fallback: definition.fallback
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return map;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
hasCapability(capability) {
|
|
101
|
+
return this.capabilityMap[capability]?.available || false;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
getToolsForCapability(capability) {
|
|
105
|
+
return this.capabilityMap[capability]?.tools || [];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
getFallbackForCapability(capability) {
|
|
109
|
+
return this.capabilityMap[capability]?.fallback || 'manual-implementation';
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
getCapabilitiesForLevel(level) {
|
|
113
|
+
const levelCapabilities = {
|
|
114
|
+
L1: ['static-analysis', 'file-operations'],
|
|
115
|
+
L2: ['unit-testing', 'file-operations'],
|
|
116
|
+
L3: ['component-testing', 'file-operations'],
|
|
117
|
+
L4: ['api-testing', 'database-access', 'version-control'],
|
|
118
|
+
L5: ['journey-validation', 'browser-automation'],
|
|
119
|
+
L6: ['ux-testing', 'browser-automation'],
|
|
120
|
+
L7: ['analytics', 'web-research', 'user-feedback'],
|
|
121
|
+
L8: ['business-metrics', 'analytics'],
|
|
122
|
+
L9: ['version-control', 'web-research']
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
return (levelCapabilities[level] || []).map(cap => ({
|
|
126
|
+
capability: cap,
|
|
127
|
+
available: this.hasCapability(cap),
|
|
128
|
+
tools: this.getToolsForCapability(cap),
|
|
129
|
+
fallback: this.getFallbackForCapability(cap)
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
getReport() {
|
|
134
|
+
const report = {
|
|
135
|
+
totalCapabilities: Object.keys(CAPABILITY_DEFINITIONS).length,
|
|
136
|
+
availableCapabilities: 0,
|
|
137
|
+
missingCapabilities: [],
|
|
138
|
+
byLevel: {}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
for (const [cap, data] of Object.entries(this.capabilityMap)) {
|
|
142
|
+
if (data.available) {
|
|
143
|
+
report.availableCapabilities++;
|
|
144
|
+
} else {
|
|
145
|
+
report.missingCapabilities.push({
|
|
146
|
+
capability: cap,
|
|
147
|
+
description: data.description,
|
|
148
|
+
fallback: data.fallback
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
for (let i = 1; i <= 9; i++) {
|
|
154
|
+
const level = `L${i}`;
|
|
155
|
+
report.byLevel[level] = this.getCapabilitiesForLevel(level);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return report;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
module.exports = { CapabilityManager, CAPABILITY_DEFINITIONS };
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
const DEGRADATION_STRATEGIES = {
|
|
2
|
+
'manual-code-review': {
|
|
3
|
+
type: 'manual',
|
|
4
|
+
instructions: 'Perform manual code review focusing on syntax, style, and common patterns',
|
|
5
|
+
guidance: 'Check for: indentation consistency, naming conventions, error handling, edge cases'
|
|
6
|
+
},
|
|
7
|
+
'direct-file-access': {
|
|
8
|
+
type: 'native',
|
|
9
|
+
instructions: 'Use built-in filesystem APIs (fs.readFile, fs.writeFile)',
|
|
10
|
+
guidance: 'Ensure proper error handling and encoding specifications'
|
|
11
|
+
},
|
|
12
|
+
'manual-testing': {
|
|
13
|
+
type: 'manual',
|
|
14
|
+
instructions: 'Manually verify function behavior with sample inputs',
|
|
15
|
+
guidance: 'Test edge cases, error conditions, and expected outputs'
|
|
16
|
+
},
|
|
17
|
+
'manual-api-calls': {
|
|
18
|
+
type: 'manual',
|
|
19
|
+
instructions: 'Use curl or similar HTTP clients to test API endpoints',
|
|
20
|
+
guidance: 'Verify status codes, response bodies, and error handling'
|
|
21
|
+
},
|
|
22
|
+
'manual-ux-testing': {
|
|
23
|
+
type: 'manual',
|
|
24
|
+
instructions: 'Manually test user journeys in browser',
|
|
25
|
+
guidance: 'Follow user personas through critical flows, noting UX issues'
|
|
26
|
+
},
|
|
27
|
+
'manual-ux-review': {
|
|
28
|
+
type: 'manual',
|
|
29
|
+
instructions: 'Review UI implementation against design principles',
|
|
30
|
+
guidance: 'Check accessibility, responsiveness, and usability heuristics'
|
|
31
|
+
},
|
|
32
|
+
'log-analysis': {
|
|
33
|
+
type: 'manual',
|
|
34
|
+
instructions: 'Analyze application logs for usage patterns',
|
|
35
|
+
guidance: 'Look for error rates, performance bottlenecks, user behavior patterns'
|
|
36
|
+
},
|
|
37
|
+
'manual-reporting': {
|
|
38
|
+
type: 'manual',
|
|
39
|
+
instructions: 'Create manual reports from available data sources',
|
|
40
|
+
guidance: 'Collect metrics from logs, databases, and manual observations'
|
|
41
|
+
},
|
|
42
|
+
'manual-git': {
|
|
43
|
+
type: 'cli',
|
|
44
|
+
instructions: 'Use git CLI commands directly',
|
|
45
|
+
guidance: 'Standard git workflow: status, add, commit, push, pull'
|
|
46
|
+
},
|
|
47
|
+
'manual-browser-testing': {
|
|
48
|
+
type: 'manual',
|
|
49
|
+
instructions: 'Manually interact with application in browser',
|
|
50
|
+
guidance: 'Test functionality, check console for errors, verify behavior'
|
|
51
|
+
},
|
|
52
|
+
'manual-db-queries': {
|
|
53
|
+
type: 'cli',
|
|
54
|
+
instructions: 'Use database CLI tools (psql, mysql) directly',
|
|
55
|
+
guidance: 'Connect to database and execute queries manually'
|
|
56
|
+
},
|
|
57
|
+
'manual-web-search': {
|
|
58
|
+
type: 'manual',
|
|
59
|
+
instructions: 'Manually search web using browser',
|
|
60
|
+
guidance: 'Use search engines and visit relevant documentation sites'
|
|
61
|
+
},
|
|
62
|
+
'manual-feedback-review': {
|
|
63
|
+
type: 'manual',
|
|
64
|
+
instructions: 'Manually review feedback from support channels',
|
|
65
|
+
guidance: 'Check email, Slack, support tickets for user feedback'
|
|
66
|
+
},
|
|
67
|
+
'manual-implementation': {
|
|
68
|
+
type: 'manual',
|
|
69
|
+
instructions: 'Implement manually without automated tools',
|
|
70
|
+
guidance: 'Follow best practices and manual verification procedures'
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
function getDegradationStrategy(capability, availableCapabilities) {
|
|
75
|
+
if (!availableCapabilities[capability] || !availableCapabilities[capability].available) {
|
|
76
|
+
const fallback = availableCapabilities[capability]?.fallback || 'manual-implementation';
|
|
77
|
+
return DEGRADATION_STRATEGIES[fallback] || DEGRADATION_STRATEGIES['manual-implementation'];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function generateDegradationGuidance(level, capabilities) {
|
|
84
|
+
const guidance = {
|
|
85
|
+
level,
|
|
86
|
+
missingCapabilities: [],
|
|
87
|
+
workflowAdjustments: [],
|
|
88
|
+
recommendations: []
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
for (const cap of capabilities) {
|
|
92
|
+
if (!cap.available) {
|
|
93
|
+
const strategy = DEGRADATION_STRATEGIES[cap.fallback] || DEGRADATION_STRATEGIES['manual-implementation'];
|
|
94
|
+
|
|
95
|
+
guidance.missingCapabilities.push({
|
|
96
|
+
capability: cap.capability,
|
|
97
|
+
fallback: cap.fallback,
|
|
98
|
+
strategy: strategy.type,
|
|
99
|
+
instructions: strategy.instructions,
|
|
100
|
+
guidance: strategy.guidance
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
if (strategy.type === 'manual') {
|
|
104
|
+
guidance.workflowAdjustments.push(
|
|
105
|
+
`For ${cap.capability}: ${strategy.instructions}`
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
guidance.recommendations.push(
|
|
110
|
+
`Consider adding tools for ${cap.capability} to improve automation`
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return guidance;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function createAgentInstructions(level, capabilities) {
|
|
119
|
+
const missing = capabilities.filter(cap => !cap.available);
|
|
120
|
+
|
|
121
|
+
if (missing.length === 0) {
|
|
122
|
+
return {
|
|
123
|
+
hasAllTools: true,
|
|
124
|
+
message: 'All required tools are available',
|
|
125
|
+
instructions: []
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const instructions = missing.map(cap => {
|
|
130
|
+
const strategy = DEGRADATION_STRATEGIES[cap.fallback] || DEGRADATION_STRATEGIES['manual-implementation'];
|
|
131
|
+
return {
|
|
132
|
+
capability: cap.capability,
|
|
133
|
+
type: strategy.type,
|
|
134
|
+
action: strategy.instructions,
|
|
135
|
+
guidance: strategy.guidance
|
|
136
|
+
};
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
hasAllTools: false,
|
|
141
|
+
message: `${missing.length} tool(s) missing for ${level}`,
|
|
142
|
+
instructions,
|
|
143
|
+
summary: `You will need to use ${instructions.filter(i => i.type === 'manual').length} manual workflow(s)`
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
module.exports = {
|
|
148
|
+
DEGRADATION_STRATEGIES,
|
|
149
|
+
getDegradationStrategy,
|
|
150
|
+
generateDegradationGuidance,
|
|
151
|
+
createAgentInstructions
|
|
152
|
+
};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
const { spawn } = require('child_process');
|
|
2
|
+
|
|
3
|
+
class McpClient {
|
|
4
|
+
constructor(serverConfig) {
|
|
5
|
+
this.name = serverConfig.name;
|
|
6
|
+
this.command = serverConfig.command;
|
|
7
|
+
this.args = serverConfig.args || [];
|
|
8
|
+
this.env = serverConfig.env || {};
|
|
9
|
+
this.process = null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async start() {
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
this.process = spawn(this.command, this.args, {
|
|
15
|
+
env: { ...process.env, ...this.env },
|
|
16
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
this.process.on('error', (error) => {
|
|
20
|
+
reject(new Error(`Failed to start MCP server ${this.name}: ${error.message}`));
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
this.process.stdout.once('data', () => {
|
|
24
|
+
resolve();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
setTimeout(() => {
|
|
28
|
+
if (!this.process.killed) {
|
|
29
|
+
resolve();
|
|
30
|
+
}
|
|
31
|
+
}, 1000);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async call(method, params = {}) {
|
|
36
|
+
if (!this.process) {
|
|
37
|
+
throw new Error(`MCP server ${this.name} not started`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
const request = {
|
|
42
|
+
jsonrpc: '2.0',
|
|
43
|
+
id: Date.now(),
|
|
44
|
+
method,
|
|
45
|
+
params
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
let responseData = '';
|
|
49
|
+
|
|
50
|
+
const timeout = setTimeout(() => {
|
|
51
|
+
reject(new Error(`MCP call to ${this.name}.${method} timed out`));
|
|
52
|
+
}, 5000);
|
|
53
|
+
|
|
54
|
+
const onData = (data) => {
|
|
55
|
+
responseData += data.toString();
|
|
56
|
+
try {
|
|
57
|
+
const response = JSON.parse(responseData);
|
|
58
|
+
clearTimeout(timeout);
|
|
59
|
+
this.process.stdout.off('data', onData);
|
|
60
|
+
|
|
61
|
+
if (response.error) {
|
|
62
|
+
reject(new Error(`MCP error: ${response.error.message}`));
|
|
63
|
+
} else {
|
|
64
|
+
resolve(response.result);
|
|
65
|
+
}
|
|
66
|
+
} catch (e) {
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
this.process.stdout.on('data', onData);
|
|
71
|
+
this.process.stdin.write(JSON.stringify(request) + '\n');
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async stop() {
|
|
76
|
+
if (this.process && !this.process.killed) {
|
|
77
|
+
this.process.kill();
|
|
78
|
+
this.process = null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async listTools() {
|
|
83
|
+
try {
|
|
84
|
+
const result = await this.call('tools/list');
|
|
85
|
+
return result.tools || [];
|
|
86
|
+
} catch (error) {
|
|
87
|
+
return [];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async callTool(toolName, args) {
|
|
92
|
+
try {
|
|
93
|
+
return await this.call('tools/call', {
|
|
94
|
+
name: toolName,
|
|
95
|
+
arguments: args
|
|
96
|
+
});
|
|
97
|
+
} catch (error) {
|
|
98
|
+
throw new Error(`Tool ${toolName} failed: ${error.message}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function createMcpClient(serverConfig) {
|
|
104
|
+
const client = new McpClient(serverConfig);
|
|
105
|
+
await client.start();
|
|
106
|
+
return client;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
module.exports = { McpClient, createMcpClient };
|