@iservu-inc/adf-cli 0.13.0 → 0.14.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.
Files changed (73) hide show
  1. package/.context/memory/architecture.md +40 -0
  2. package/.context/memory/glossary.md +19 -0
  3. package/.project/docs/VERSIONING-GUIDE.md +127 -0
  4. package/AGENTS.md +53 -0
  5. package/CHANGELOG.md +57 -0
  6. package/README.md +12 -2
  7. package/bin/adf.js +10 -0
  8. package/conductor/archive/context_synthesis_20260112/metadata.json +8 -0
  9. package/conductor/archive/context_synthesis_20260112/plan.md +40 -0
  10. package/conductor/archive/context_synthesis_20260112/spec.md +43 -0
  11. package/conductor/archive/verify_opencode_20260111/metadata.json +8 -0
  12. package/conductor/archive/verify_opencode_20260111/plan.md +34 -0
  13. package/conductor/archive/verify_opencode_20260111/spec.md +25 -0
  14. package/conductor/code_styleguides/javascript.md +51 -0
  15. package/conductor/product-guidelines.md +26 -0
  16. package/conductor/product.md +25 -0
  17. package/conductor/setup_state.json +1 -0
  18. package/conductor/tech-stack.md +28 -0
  19. package/conductor/tracks/bootstrap_agents_20260111/metadata.json +8 -0
  20. package/conductor/tracks/bootstrap_agents_20260111/plan.md +17 -0
  21. package/conductor/tracks/bootstrap_agents_20260111/spec.md +27 -0
  22. package/conductor/tracks.md +9 -0
  23. package/conductor/workflow.md +333 -0
  24. package/lib/analysis/ai-gap-analyzer.js +66 -0
  25. package/lib/analysis/dynamic-question-generator.js +55 -0
  26. package/lib/analysis/heuristic-gap-analyzer.js +45 -0
  27. package/lib/analysis/synthesis-engine.js +142 -0
  28. package/lib/commands/deploy.js +28 -2
  29. package/lib/commands/init.js +94 -0
  30. package/lib/commands/tools.js +38 -0
  31. package/lib/frameworks/interviewer.js +4 -3
  32. package/lib/generators/codex-cli-generator.js +41 -0
  33. package/lib/generators/index.js +33 -0
  34. package/lib/generators/kiro-generator.js +49 -0
  35. package/lib/generators/opencode-generator.js +332 -313
  36. package/lib/generators/trae-generator.js +34 -0
  37. package/lib/templates/scripts/analyze-framework-updates.js +361 -0
  38. package/lib/templates/scripts/build.js +608 -0
  39. package/lib/templates/scripts/check-framework-updates.js +118 -0
  40. package/lib/templates/scripts/config-helpers.js +1 -1
  41. package/lib/templates/scripts/deploy.js +13 -28
  42. package/lib/templates/scripts/init.js +110 -220
  43. package/lib/templates/scripts/postinstall.js +13 -0
  44. package/lib/templates/scripts/update-frameworks.js +28 -0
  45. package/lib/templates/scripts/validate-env.js +428 -0
  46. package/lib/templates/scripts/validate-mcp.js +471 -0
  47. package/lib/templates/scripts/validate.js +482 -0
  48. package/lib/templates/shared/agents/analyst.md +1 -1
  49. package/lib/templates/shared/agents/architect.md +13 -17
  50. package/lib/templates/shared/agents/dev.md +2 -2
  51. package/lib/templates/shared/agents/pm.md +1 -1
  52. package/lib/templates/shared/agents/qa.md +1 -1
  53. package/lib/templates/shared/agents/sm.md +2 -2
  54. package/lib/templates/shared/templates/README.md +2 -2
  55. package/lib/templates/shared/templates/openspec-proposal.md +2 -2
  56. package/lib/templates/shared/templates/prd-template.md +1 -1
  57. package/lib/templates/shared/templates/story-template.md +1 -1
  58. package/lib/utils/context-extractor.js +157 -0
  59. package/lib/utils/framework-detector.js +54 -0
  60. package/lib/utils/tool-feature-registry.js +102 -0
  61. package/package.json +1 -1
  62. package/tests/ai-gap-analyzer.test.js +38 -0
  63. package/tests/codex-cli-generator.test.js +29 -0
  64. package/tests/context-extractor.test.js +70 -0
  65. package/tests/deploy-integration.test.js +36 -0
  66. package/tests/deploy.test.js +57 -0
  67. package/tests/dynamic-question-generator.test.js +29 -0
  68. package/tests/framework-detector.test.js +55 -0
  69. package/tests/heuristic-gap-analyzer.test.js +46 -0
  70. package/tests/kiro-trae-generators.test.js +43 -0
  71. package/tests/opencode-generator.test.js +113 -0
  72. package/tests/synthesis-engine.test.js +52 -0
  73. package/tests/tool-feature-registry.test.js +23 -0
@@ -0,0 +1,471 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * AgentDevFramework MCP Configuration Validator
5
+ * Validates MCP server configuration and connectivity
6
+ */
7
+
8
+ const fs = require('fs-extra');
9
+ const path = require('path');
10
+ const chalk = require('chalk');
11
+ const ora = require('ora');
12
+ const dotenv = require('dotenv');
13
+
14
+ const FRAMEWORK_ROOT = path.join(__dirname, '..');
15
+ const ENV_FILE = path.join(FRAMEWORK_ROOT, '.env');
16
+ const MCP_CONFIG = path.join(FRAMEWORK_ROOT, 'shared', 'mcp', 'mcp-config.json');
17
+
18
+ // MCP server requirements
19
+ const MCP_SERVERS = {
20
+ 'context7': {
21
+ type: 'http',
22
+ required: false,
23
+ envVars: ['CONTEXT7_API_KEY'],
24
+ description: 'Current framework documentation retrieval',
25
+ url: 'https://context7.com'
26
+ },
27
+ 'brave-search': {
28
+ type: 'command',
29
+ required: true,
30
+ envVars: ['BRAVE_API_KEY'],
31
+ description: 'Web search for latest information',
32
+ url: 'https://brave.com/search/api/',
33
+ freeTier: '2,000 queries/month'
34
+ },
35
+ 'mem0': {
36
+ type: 'command',
37
+ required: true,
38
+ envVars: ['SMITHERY_KEY', 'SMITHERY_PROFILE', 'OPENAI_API_KEY'],
39
+ description: 'Persistent memory across sessions',
40
+ url: 'https://smithery.ai'
41
+ },
42
+ 'clear-thought': {
43
+ type: 'command',
44
+ required: true,
45
+ envVars: ['SMITHERY_KEY', 'OPENAI_API_KEY'],
46
+ description: 'Structured reasoning for complex problems',
47
+ url: 'https://smithery.ai'
48
+ },
49
+ 'archon': {
50
+ type: 'http',
51
+ required: false,
52
+ envVars: ['ARCHON_URL', 'SUPABASE_URL', 'SUPABASE_SERVICE_ROLE_KEY', 'OPENAI_API_KEY'],
53
+ description: 'Project knowledge management and task tracking',
54
+ url: 'https://github.com/archon-ai/archon'
55
+ },
56
+ 'openmemory': {
57
+ type: 'command',
58
+ required: false,
59
+ envVars: ['OPENMEMORY_API_KEY', 'CLIENT_NAME'],
60
+ description: 'Alternative persistent memory system',
61
+ url: 'https://openmemory.ai',
62
+ note: 'Alternative to mem0 - choose one based on preference'
63
+ },
64
+ 'deepwiki': {
65
+ type: 'http',
66
+ required: true,
67
+ envVars: [],
68
+ description: 'GitHub repository documentation and analysis',
69
+ note: 'No API key required'
70
+ }
71
+ };
72
+
73
+ class MCPValidator {
74
+ constructor() {
75
+ this.errors = [];
76
+ this.warnings = [];
77
+ this.passed = 0;
78
+ this.failed = 0;
79
+ this.env = {};
80
+ this.mcpConfig = null;
81
+ }
82
+
83
+ log(message, type = 'info') {
84
+ const symbols = {
85
+ success: chalk.green('āœ“'),
86
+ error: chalk.red('āœ—'),
87
+ warning: chalk.yellow('⚠'),
88
+ info: chalk.blue('ℹ')
89
+ };
90
+ console.log(`${symbols[type]} ${message}`);
91
+ }
92
+
93
+ addError(message) {
94
+ this.errors.push(message);
95
+ this.failed++;
96
+ }
97
+
98
+ addWarning(message) {
99
+ this.warnings.push(message);
100
+ }
101
+
102
+ loadEnvFile() {
103
+ try {
104
+ if (fs.existsSync(ENV_FILE)) {
105
+ const result = dotenv.config({ path: ENV_FILE });
106
+ this.env = result.parsed || {};
107
+ // Also merge process.env
108
+ Object.keys(process.env).forEach(key => {
109
+ if (!this.env[key]) {
110
+ this.env[key] = process.env[key];
111
+ }
112
+ });
113
+ this.log('Loaded environment variables', 'success');
114
+ this.passed++;
115
+ return true;
116
+ } else {
117
+ this.addError('.env file not found - run validate:env first');
118
+ return false;
119
+ }
120
+ } catch (error) {
121
+ this.addError(`Failed to load .env: ${error.message}`);
122
+ return false;
123
+ }
124
+ }
125
+
126
+ checkMCPConfigExists() {
127
+ if (fs.existsSync(MCP_CONFIG)) {
128
+ this.log('MCP configuration file found', 'success');
129
+ this.passed++;
130
+ return true;
131
+ } else {
132
+ this.addError('MCP configuration file not found: shared/mcp/mcp-config.json');
133
+ return false;
134
+ }
135
+ }
136
+
137
+ loadMCPConfig() {
138
+ try {
139
+ const configContent = fs.readFileSync(MCP_CONFIG, 'utf-8');
140
+ this.mcpConfig = JSON.parse(configContent);
141
+
142
+ if (!this.mcpConfig.mcpServers) {
143
+ this.addError('MCP config missing "mcpServers" section');
144
+ return false;
145
+ }
146
+
147
+ this.log(`Loaded MCP configuration with ${Object.keys(this.mcpConfig.mcpServers).length} servers`, 'success');
148
+ this.passed++;
149
+ return true;
150
+ } catch (error) {
151
+ this.addError(`Failed to parse MCP config: ${error.message}`);
152
+ return false;
153
+ }
154
+ }
155
+
156
+ replaceEnvVars(value) {
157
+ if (typeof value !== 'string') return value;
158
+
159
+ return value.replace(/\$\{([^}]+)\}/g, (match, envVar) => {
160
+ return this.env[envVar] || match;
161
+ });
162
+ }
163
+
164
+ validateServerConfig(serverName, config) {
165
+ const requirements = MCP_SERVERS[serverName];
166
+
167
+ if (!requirements) {
168
+ this.addWarning(`Unknown MCP server: ${serverName}`);
169
+ return;
170
+ }
171
+
172
+ console.log(chalk.bold(`\n ${serverName}:`));
173
+ console.log(chalk.gray(` ${requirements.description}`));
174
+
175
+ // Check type
176
+ if (config.type && config.type !== requirements.type) {
177
+ this.addWarning(`${serverName}: Expected type "${requirements.type}", found "${config.type}"`);
178
+ }
179
+
180
+ // Check required environment variables
181
+ const missingVars = [];
182
+ requirements.envVars.forEach(envVar => {
183
+ const value = this.env[envVar];
184
+ if (!value || value.trim() === '') {
185
+ missingVars.push(envVar);
186
+ }
187
+ });
188
+
189
+ if (missingVars.length > 0) {
190
+ if (requirements.required) {
191
+ this.addError(`${serverName}: Missing required environment variables: ${missingVars.join(', ')}`);
192
+ console.log(chalk.red(` āœ— Missing: ${missingVars.join(', ')}`));
193
+ if (requirements.url) {
194
+ console.log(chalk.cyan(` Setup: ${requirements.url}`));
195
+ }
196
+ } else {
197
+ this.addWarning(`${serverName}: Missing optional environment variables: ${missingVars.join(', ')}`);
198
+ console.log(chalk.yellow(` ⚠ Missing: ${missingVars.join(', ')}`));
199
+ }
200
+ } else {
201
+ this.log(`${serverName}: Configuration valid`, 'success');
202
+ this.passed++;
203
+ }
204
+
205
+ // Display notes
206
+ if (requirements.note) {
207
+ console.log(chalk.gray(` Note: ${requirements.note}`));
208
+ }
209
+ if (requirements.freeTier) {
210
+ console.log(chalk.gray(` Free tier: ${requirements.freeTier}`));
211
+ }
212
+ }
213
+
214
+ validateAllServers() {
215
+ console.log(chalk.bold('\nšŸ”Œ Validating MCP Servers...'));
216
+
217
+ const configuredServers = Object.keys(this.mcpConfig.mcpServers);
218
+ const expectedServers = Object.keys(MCP_SERVERS);
219
+
220
+ // Check each expected server
221
+ expectedServers.forEach(serverName => {
222
+ if (configuredServers.includes(serverName)) {
223
+ const config = this.mcpConfig.mcpServers[serverName];
224
+ this.validateServerConfig(serverName, config);
225
+ } else {
226
+ const requirements = MCP_SERVERS[serverName];
227
+ if (requirements.required) {
228
+ this.addError(`Missing required MCP server: ${serverName}`);
229
+ console.log(chalk.red(`\n ${serverName}: Not configured`));
230
+ console.log(chalk.gray(` ${requirements.description}`));
231
+ } else {
232
+ this.addWarning(`Missing optional MCP server: ${serverName}`);
233
+ console.log(chalk.yellow(`\n ${serverName}: Not configured (optional)`));
234
+ }
235
+ }
236
+ });
237
+
238
+ // Check for unknown servers
239
+ configuredServers.forEach(serverName => {
240
+ if (!expectedServers.includes(serverName)) {
241
+ this.addWarning(`Unknown MCP server in config: ${serverName}`);
242
+ }
243
+ });
244
+ }
245
+
246
+ validateServerConnectivity() {
247
+ console.log(chalk.bold('\n🌐 Checking Server Configuration...'));
248
+
249
+ Object.entries(this.mcpConfig.mcpServers).forEach(([serverName, config]) => {
250
+ // Check command-based servers
251
+ if (config.command) {
252
+ const command = this.replaceEnvVars(config.command);
253
+ console.log(chalk.gray(` ${serverName}: Command-based (${command})`));
254
+
255
+ // Check if npx is available for npx-based servers
256
+ if (command === 'npx') {
257
+ try {
258
+ require('child_process').execSync('npx --version', { stdio: 'ignore' });
259
+ this.log(`${serverName}: npx available`, 'success');
260
+ this.passed++;
261
+ } catch (error) {
262
+ this.addWarning(`${serverName}: npx not available - install Node.js`);
263
+ }
264
+ }
265
+ }
266
+
267
+ // Check URL-based servers
268
+ if (config.url) {
269
+ const url = this.replaceEnvVars(config.url);
270
+ console.log(chalk.gray(` ${serverName}: URL-based (${url})`));
271
+
272
+ if (!url.startsWith('http')) {
273
+ this.addWarning(`${serverName}: Invalid URL format: ${url}`);
274
+ } else {
275
+ this.log(`${serverName}: URL configured`, 'success');
276
+ this.passed++;
277
+ }
278
+ }
279
+
280
+ // Check environment variables are properly configured
281
+ if (config.env) {
282
+ const envKeys = Object.keys(config.env);
283
+ const hasPlaceholders = envKeys.some(key => {
284
+ const value = config.env[key];
285
+ return typeof value === 'string' && value.includes('${');
286
+ });
287
+
288
+ if (hasPlaceholders) {
289
+ this.log(`${serverName}: Using environment variables`, 'success');
290
+ this.passed++;
291
+ }
292
+ }
293
+ });
294
+ }
295
+
296
+ checkCriticalToolStatus() {
297
+ console.log(chalk.bold('\nšŸŽÆ Critical Tool Status...'));
298
+
299
+ const criticalTools = ['brave-search', 'mem0', 'clear-thought', 'deepwiki'];
300
+ const configured = [];
301
+ const missing = [];
302
+
303
+ criticalTools.forEach(tool => {
304
+ const requirements = MCP_SERVERS[tool];
305
+ const isConfigured = this.mcpConfig.mcpServers[tool];
306
+
307
+ if (!isConfigured) {
308
+ missing.push(tool);
309
+ return;
310
+ }
311
+
312
+ const missingVars = requirements.envVars.filter(envVar => {
313
+ const value = this.env[envVar];
314
+ return !value || value.trim() === '';
315
+ });
316
+
317
+ if (missingVars.length === 0) {
318
+ configured.push(tool);
319
+ } else {
320
+ missing.push(tool);
321
+ }
322
+ });
323
+
324
+ if (configured.length > 0) {
325
+ this.log(`${configured.length} critical tools ready: ${configured.join(', ')}`, 'success');
326
+ this.passed++;
327
+ }
328
+
329
+ if (missing.length > 0) {
330
+ this.addError(`${missing.length} critical tools not ready: ${missing.join(', ')}`);
331
+ console.log(chalk.red(` Missing: ${missing.join(', ')}`));
332
+ }
333
+ }
334
+
335
+ checkMemorySystemStatus() {
336
+ console.log(chalk.bold('\nšŸ’¾ Memory System Status...'));
337
+
338
+ const mem0Ready = this.mcpConfig.mcpServers['mem0'] &&
339
+ this.env['SMITHERY_KEY'] &&
340
+ this.env['OPENAI_API_KEY'];
341
+
342
+ const openmemoryReady = this.mcpConfig.mcpServers['openmemory'] &&
343
+ this.env['OPENMEMORY_API_KEY'];
344
+
345
+ if (mem0Ready && openmemoryReady) {
346
+ this.log('Both memory systems configured (mem0 and openmemory)', 'success');
347
+ console.log(chalk.gray(' Note: You only need one memory system'));
348
+ this.passed++;
349
+ } else if (mem0Ready) {
350
+ this.log('mem0 configured and ready', 'success');
351
+ this.passed++;
352
+ } else if (openmemoryReady) {
353
+ this.log('openmemory configured and ready', 'success');
354
+ this.passed++;
355
+ } else {
356
+ this.addError('No memory system configured - configure either mem0 or openmemory');
357
+ console.log(chalk.red(' Both mem0 and openmemory are unavailable'));
358
+ console.log(chalk.cyan(' Setup mem0: https://smithery.ai'));
359
+ console.log(chalk.cyan(' Setup openmemory: https://openmemory.ai'));
360
+ }
361
+ }
362
+
363
+ generateReport() {
364
+ console.log(chalk.bold('\n\nšŸ“Š MCP Configuration Report\n'));
365
+ console.log(chalk.bold('━'.repeat(50)));
366
+
367
+ // Summary
368
+ console.log(chalk.bold('\nSummary:'));
369
+ console.log(` ${chalk.green('āœ“')} Configured: ${chalk.bold(this.passed)}`);
370
+ console.log(` ${chalk.red('āœ—')} Missing: ${chalk.bold(this.failed)}`);
371
+ console.log(` ${chalk.yellow('⚠')} Warnings: ${chalk.bold(this.warnings.length)}`);
372
+
373
+ // Errors
374
+ if (this.errors.length > 0) {
375
+ console.log(chalk.bold('\n\nConfiguration Issues:'));
376
+ this.errors.forEach((error, i) => {
377
+ console.log(` ${i + 1}. ${chalk.red(error)}`);
378
+ });
379
+ }
380
+
381
+ // Warnings
382
+ if (this.warnings.length > 0) {
383
+ console.log(chalk.bold('\n\nWarnings:'));
384
+ this.warnings.forEach((warning, i) => {
385
+ console.log(` ${i + 1}. ${chalk.yellow(warning)}`);
386
+ });
387
+ }
388
+
389
+ console.log(chalk.bold('\n' + '━'.repeat(50)));
390
+
391
+ // Overall status
392
+ console.log(chalk.bold('\nOverall Status:'));
393
+ if (this.failed === 0) {
394
+ console.log(chalk.green(' āœ“ MCP configuration is valid'));
395
+ console.log(chalk.green('\n All critical MCP tools are configured!\n'));
396
+ console.log(chalk.cyan(' Next steps:'));
397
+ console.log(chalk.gray(' 1. Test your MCP tools in Claude Code or other AI tools'));
398
+ console.log(chalk.gray(' 2. Try: @context7 react'));
399
+ console.log(chalk.gray(' 3. Try: /mem0 save "test message"'));
400
+ console.log(chalk.gray(' 4. Try: @deepwiki facebook/react\n'));
401
+ } else {
402
+ console.log(chalk.red(` āœ— Missing ${this.failed} required configuration(s)`));
403
+ console.log(chalk.yellow('\n Setup Instructions:\n'));
404
+ console.log(chalk.cyan(' 1. Fix environment variables:'));
405
+ console.log(chalk.gray(' npm run validate:env\n'));
406
+ console.log(chalk.cyan(' 2. Add missing API keys to .env\n'));
407
+ console.log(chalk.cyan(' 3. Run MCP validation again:'));
408
+ console.log(chalk.gray(' npm run validate:mcp\n'));
409
+ }
410
+
411
+ return this.failed === 0;
412
+ }
413
+
414
+ async run() {
415
+ console.log(chalk.bold.cyan('\nšŸ” AgentDevFramework MCP Configuration Validator\n'));
416
+
417
+ const spinner = ora('Starting validation...').start();
418
+
419
+ try {
420
+ spinner.text = 'Loading environment variables...';
421
+ const envLoaded = this.loadEnvFile();
422
+
423
+ spinner.text = 'Checking MCP configuration file...';
424
+ const configExists = this.checkMCPConfigExists();
425
+
426
+ if (!configExists) {
427
+ spinner.fail('MCP configuration file not found');
428
+ return this.generateReport();
429
+ }
430
+
431
+ spinner.text = 'Loading MCP configuration...';
432
+ const configLoaded = this.loadMCPConfig();
433
+
434
+ if (!configLoaded) {
435
+ spinner.fail('Failed to load MCP configuration');
436
+ return this.generateReport();
437
+ }
438
+
439
+ spinner.text = 'Validating MCP servers...';
440
+ this.validateAllServers();
441
+
442
+ spinner.text = 'Checking server connectivity...';
443
+ this.validateServerConnectivity();
444
+
445
+ spinner.text = 'Checking critical tools...';
446
+ this.checkCriticalToolStatus();
447
+
448
+ spinner.text = 'Checking memory systems...';
449
+ this.checkMemorySystemStatus();
450
+
451
+ spinner.succeed('Validation complete');
452
+
453
+ return this.generateReport();
454
+ } catch (error) {
455
+ spinner.fail('Validation failed');
456
+ console.error(chalk.red(`\nError: ${error.message}`));
457
+ console.error(error.stack);
458
+ return false;
459
+ }
460
+ }
461
+ }
462
+
463
+ // Run validation if called directly
464
+ if (require.main === module) {
465
+ const validator = new MCPValidator();
466
+ validator.run().then(success => {
467
+ process.exit(success ? 0 : 1);
468
+ });
469
+ }
470
+
471
+ module.exports = MCPValidator;