@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.
- package/.context/memory/architecture.md +40 -0
- package/.context/memory/glossary.md +19 -0
- package/.project/docs/VERSIONING-GUIDE.md +127 -0
- package/AGENTS.md +53 -0
- package/CHANGELOG.md +57 -0
- package/README.md +12 -2
- package/bin/adf.js +10 -0
- package/conductor/archive/context_synthesis_20260112/metadata.json +8 -0
- package/conductor/archive/context_synthesis_20260112/plan.md +40 -0
- package/conductor/archive/context_synthesis_20260112/spec.md +43 -0
- package/conductor/archive/verify_opencode_20260111/metadata.json +8 -0
- package/conductor/archive/verify_opencode_20260111/plan.md +34 -0
- package/conductor/archive/verify_opencode_20260111/spec.md +25 -0
- package/conductor/code_styleguides/javascript.md +51 -0
- package/conductor/product-guidelines.md +26 -0
- package/conductor/product.md +25 -0
- package/conductor/setup_state.json +1 -0
- package/conductor/tech-stack.md +28 -0
- package/conductor/tracks/bootstrap_agents_20260111/metadata.json +8 -0
- package/conductor/tracks/bootstrap_agents_20260111/plan.md +17 -0
- package/conductor/tracks/bootstrap_agents_20260111/spec.md +27 -0
- package/conductor/tracks.md +9 -0
- package/conductor/workflow.md +333 -0
- package/lib/analysis/ai-gap-analyzer.js +66 -0
- package/lib/analysis/dynamic-question-generator.js +55 -0
- package/lib/analysis/heuristic-gap-analyzer.js +45 -0
- package/lib/analysis/synthesis-engine.js +142 -0
- package/lib/commands/deploy.js +28 -2
- package/lib/commands/init.js +94 -0
- package/lib/commands/tools.js +38 -0
- package/lib/frameworks/interviewer.js +4 -3
- package/lib/generators/codex-cli-generator.js +41 -0
- package/lib/generators/index.js +33 -0
- package/lib/generators/kiro-generator.js +49 -0
- package/lib/generators/opencode-generator.js +332 -313
- package/lib/generators/trae-generator.js +34 -0
- package/lib/templates/scripts/analyze-framework-updates.js +361 -0
- package/lib/templates/scripts/build.js +608 -0
- package/lib/templates/scripts/check-framework-updates.js +118 -0
- package/lib/templates/scripts/config-helpers.js +1 -1
- package/lib/templates/scripts/deploy.js +13 -28
- package/lib/templates/scripts/init.js +110 -220
- package/lib/templates/scripts/postinstall.js +13 -0
- package/lib/templates/scripts/update-frameworks.js +28 -0
- package/lib/templates/scripts/validate-env.js +428 -0
- package/lib/templates/scripts/validate-mcp.js +471 -0
- package/lib/templates/scripts/validate.js +482 -0
- package/lib/templates/shared/agents/analyst.md +1 -1
- package/lib/templates/shared/agents/architect.md +13 -17
- package/lib/templates/shared/agents/dev.md +2 -2
- package/lib/templates/shared/agents/pm.md +1 -1
- package/lib/templates/shared/agents/qa.md +1 -1
- package/lib/templates/shared/agents/sm.md +2 -2
- package/lib/templates/shared/templates/README.md +2 -2
- package/lib/templates/shared/templates/openspec-proposal.md +2 -2
- package/lib/templates/shared/templates/prd-template.md +1 -1
- package/lib/templates/shared/templates/story-template.md +1 -1
- package/lib/utils/context-extractor.js +157 -0
- package/lib/utils/framework-detector.js +54 -0
- package/lib/utils/tool-feature-registry.js +102 -0
- package/package.json +1 -1
- package/tests/ai-gap-analyzer.test.js +38 -0
- package/tests/codex-cli-generator.test.js +29 -0
- package/tests/context-extractor.test.js +70 -0
- package/tests/deploy-integration.test.js +36 -0
- package/tests/deploy.test.js +57 -0
- package/tests/dynamic-question-generator.test.js +29 -0
- package/tests/framework-detector.test.js +55 -0
- package/tests/heuristic-gap-analyzer.test.js +46 -0
- package/tests/kiro-trae-generators.test.js +43 -0
- package/tests/opencode-generator.test.js +113 -0
- package/tests/synthesis-engine.test.js +52 -0
- package/tests/tool-feature-registry.test.js +23 -0
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AgentDevFramework Environment Validator
|
|
5
|
+
* Validates .env configuration and API keys for MCP tools
|
|
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 ENV_TEMPLATE = path.join(FRAMEWORK_ROOT, '.env.template');
|
|
17
|
+
|
|
18
|
+
// Define required and optional environment variables
|
|
19
|
+
const ENV_VARS = {
|
|
20
|
+
required: {
|
|
21
|
+
// Core MCP tools
|
|
22
|
+
BRAVE_API_KEY: {
|
|
23
|
+
description: 'Brave Search API key (required for web search)',
|
|
24
|
+
url: 'https://brave.com/search/api/',
|
|
25
|
+
freeT tier: '2,000 queries/month'
|
|
26
|
+
},
|
|
27
|
+
OPENAI_API_KEY: {
|
|
28
|
+
description: 'OpenAI API key (required for mem0, archon, clear-thought)',
|
|
29
|
+
url: 'https://platform.openai.com/api-keys'
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
// Memory & Knowledge Management
|
|
33
|
+
LLM_PROVIDER: {
|
|
34
|
+
description: 'LLM provider for mem0',
|
|
35
|
+
default: 'openai',
|
|
36
|
+
validation: (val) => ['openai', 'anthropic', 'ollama'].includes(val)
|
|
37
|
+
},
|
|
38
|
+
LLM_CHOICE: {
|
|
39
|
+
description: 'LLM model choice for mem0',
|
|
40
|
+
default: 'gpt-4o-mini'
|
|
41
|
+
},
|
|
42
|
+
EMBEDDING_MODEL_CHOICE: {
|
|
43
|
+
description: 'Embedding model for mem0',
|
|
44
|
+
default: 'text-embedding-3-small'
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
optional: {
|
|
49
|
+
// Optional API keys
|
|
50
|
+
CONTEXT7_API_KEY: {
|
|
51
|
+
description: 'Context7 API key (optional - provides higher rate limits)',
|
|
52
|
+
url: 'https://context7.com'
|
|
53
|
+
},
|
|
54
|
+
OPENMEMORY_API_KEY: {
|
|
55
|
+
description: 'OpenMemory API key (alternative memory system)',
|
|
56
|
+
url: 'https://openmemory.ai'
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
// Supabase (for Archon)
|
|
60
|
+
SUPABASE_URL: {
|
|
61
|
+
description: 'Supabase URL (required if using Archon)',
|
|
62
|
+
url: 'https://supabase.com/dashboard'
|
|
63
|
+
},
|
|
64
|
+
SUPABASE_SERVICE_ROLE_KEY: {
|
|
65
|
+
description: 'Supabase service role key (required if using Archon)'
|
|
66
|
+
},
|
|
67
|
+
SUPABASE_ANON_KEY: {
|
|
68
|
+
description: 'Supabase anonymous key (required if using Archon)'
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
// Smithery
|
|
72
|
+
SMITHERY_KEY: {
|
|
73
|
+
description: 'Smithery API key (for mem0 and clear-thought)',
|
|
74
|
+
url: 'https://smithery.ai'
|
|
75
|
+
},
|
|
76
|
+
SMITHERY_PROFILE: {
|
|
77
|
+
description: 'Smithery profile name'
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
// OpenAI Organization
|
|
81
|
+
OPENAI_ORG_ID: {
|
|
82
|
+
description: 'OpenAI organization ID (optional)'
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
// Archon
|
|
86
|
+
ARCHON_URL: {
|
|
87
|
+
description: 'Local Archon instance URL (if self-hosting)',
|
|
88
|
+
default: 'http://localhost:8051/mcp'
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
// Neo4j (for Archon knowledge graphs)
|
|
92
|
+
NEO4J_URI: {
|
|
93
|
+
description: 'Neo4j URI (optional - for advanced Archon features)',
|
|
94
|
+
default: 'bolt://localhost:7687'
|
|
95
|
+
},
|
|
96
|
+
NEO4J_USER: {
|
|
97
|
+
description: 'Neo4j username',
|
|
98
|
+
default: 'neo4j'
|
|
99
|
+
},
|
|
100
|
+
NEO4J_PASSWORD: {
|
|
101
|
+
description: 'Neo4j password'
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
// Memory databases
|
|
105
|
+
DATABASE_URL: {
|
|
106
|
+
description: 'PostgreSQL database URL for mem0',
|
|
107
|
+
default: 'postgresql://user:password@localhost:5432/mem0'
|
|
108
|
+
},
|
|
109
|
+
MEMORY_DB_PATH: {
|
|
110
|
+
description: 'SQLite database path for local memory',
|
|
111
|
+
default: './data/memory.sqlite'
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
// Development settings
|
|
115
|
+
NODE_ENV: {
|
|
116
|
+
description: 'Node environment',
|
|
117
|
+
default: 'development',
|
|
118
|
+
validation: (val) => ['development', 'production', 'test'].includes(val)
|
|
119
|
+
},
|
|
120
|
+
DEBUG: {
|
|
121
|
+
description: 'Enable debug mode',
|
|
122
|
+
default: 'false',
|
|
123
|
+
validation: (val) => ['true', 'false'].includes(val)
|
|
124
|
+
},
|
|
125
|
+
LOG_LEVEL: {
|
|
126
|
+
description: 'Logging level',
|
|
127
|
+
default: 'info',
|
|
128
|
+
validation: (val) => ['error', 'warn', 'info', 'debug'].includes(val)
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
// Client identification
|
|
132
|
+
CLIENT_NAME: {
|
|
133
|
+
description: 'Client name for openmemory',
|
|
134
|
+
default: 'agentdevframework'
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
class EnvValidator {
|
|
140
|
+
constructor() {
|
|
141
|
+
this.errors = [];
|
|
142
|
+
this.warnings = [];
|
|
143
|
+
this.passed = 0;
|
|
144
|
+
this.failed = 0;
|
|
145
|
+
this.env = {};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
log(message, type = 'info') {
|
|
149
|
+
const symbols = {
|
|
150
|
+
success: chalk.green('ā'),
|
|
151
|
+
error: chalk.red('ā'),
|
|
152
|
+
warning: chalk.yellow('ā '),
|
|
153
|
+
info: chalk.blue('ā¹')
|
|
154
|
+
};
|
|
155
|
+
console.log(`${symbols[type]} ${message}`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
addError(message) {
|
|
159
|
+
this.errors.push(message);
|
|
160
|
+
this.failed++;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
addWarning(message) {
|
|
164
|
+
this.warnings.push(message);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
checkEnvFileExists() {
|
|
168
|
+
if (fs.existsSync(ENV_FILE)) {
|
|
169
|
+
this.log('.env file found', 'success');
|
|
170
|
+
this.passed++;
|
|
171
|
+
return true;
|
|
172
|
+
} else {
|
|
173
|
+
this.addError('.env file not found');
|
|
174
|
+
|
|
175
|
+
if (fs.existsSync(ENV_TEMPLATE)) {
|
|
176
|
+
this.log('Found .env.template - copy it to .env to get started', 'info');
|
|
177
|
+
console.log(chalk.cyan(`\n Run: cp .env.template .env\n`));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
loadEnvFile() {
|
|
185
|
+
try {
|
|
186
|
+
const result = dotenv.config({ path: ENV_FILE });
|
|
187
|
+
|
|
188
|
+
if (result.error) {
|
|
189
|
+
this.addError(`Failed to load .env file: ${result.error.message}`);
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
this.env = result.parsed || {};
|
|
194
|
+
this.log(`Loaded ${Object.keys(this.env).length} environment variables`, 'success');
|
|
195
|
+
this.passed++;
|
|
196
|
+
return true;
|
|
197
|
+
} catch (error) {
|
|
198
|
+
this.addError(`Failed to parse .env file: ${error.message}`);
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
validateRequired() {
|
|
204
|
+
console.log(chalk.bold('\nš Validating Required Variables...'));
|
|
205
|
+
|
|
206
|
+
Object.entries(ENV_VARS.required).forEach(([key, config]) => {
|
|
207
|
+
const value = this.env[key] || process.env[key];
|
|
208
|
+
|
|
209
|
+
if (!value || value.trim() === '') {
|
|
210
|
+
this.addError(`Missing required variable: ${key}`);
|
|
211
|
+
console.log(chalk.red(` ā ${key}`));
|
|
212
|
+
console.log(chalk.gray(` ${config.description}`));
|
|
213
|
+
if (config.url) {
|
|
214
|
+
console.log(chalk.cyan(` Get key: ${config.url}`));
|
|
215
|
+
}
|
|
216
|
+
if (config.default) {
|
|
217
|
+
console.log(chalk.yellow(` Default: ${config.default}`));
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
// Validate value if validation function exists
|
|
221
|
+
if (config.validation && !config.validation(value)) {
|
|
222
|
+
this.addError(`Invalid value for ${key}: ${value}`);
|
|
223
|
+
} else {
|
|
224
|
+
this.passed++;
|
|
225
|
+
this.log(`${key} is set`, 'success');
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
validateOptional() {
|
|
232
|
+
console.log(chalk.bold('\nš§ Validating Optional Variables...'));
|
|
233
|
+
|
|
234
|
+
const configuredOptional = [];
|
|
235
|
+
const missingOptional = [];
|
|
236
|
+
|
|
237
|
+
Object.entries(ENV_VARS.optional).forEach(([key, config]) => {
|
|
238
|
+
const value = this.env[key] || process.env[key];
|
|
239
|
+
|
|
240
|
+
if (value && value.trim() !== '') {
|
|
241
|
+
// Validate value if validation function exists
|
|
242
|
+
if (config.validation && !config.validation(value)) {
|
|
243
|
+
this.addWarning(`Invalid value for ${key}: ${value}`);
|
|
244
|
+
} else {
|
|
245
|
+
this.passed++;
|
|
246
|
+
configuredOptional.push(key);
|
|
247
|
+
}
|
|
248
|
+
} else {
|
|
249
|
+
missingOptional.push({ key, config });
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
if (configuredOptional.length > 0) {
|
|
254
|
+
this.log(`${configuredOptional.length} optional variables configured`, 'success');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (missingOptional.length > 0) {
|
|
258
|
+
console.log(chalk.yellow(`\n ${missingOptional.length} optional variables not configured:`));
|
|
259
|
+
missingOptional.forEach(({ key, config }) => {
|
|
260
|
+
console.log(chalk.gray(` ${key} - ${config.description}`));
|
|
261
|
+
if (config.url) {
|
|
262
|
+
console.log(chalk.cyan(` ${config.url}`));
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
checkForSensitiveData() {
|
|
269
|
+
console.log(chalk.bold('\nš Checking for Sensitive Data...'));
|
|
270
|
+
|
|
271
|
+
// Check if .env is in .gitignore
|
|
272
|
+
const gitignorePath = path.join(FRAMEWORK_ROOT, '.gitignore');
|
|
273
|
+
|
|
274
|
+
if (fs.existsSync(gitignorePath)) {
|
|
275
|
+
const gitignore = fs.readFileSync(gitignorePath, 'utf-8');
|
|
276
|
+
|
|
277
|
+
if (gitignore.includes('.env') || gitignore.includes('*.env')) {
|
|
278
|
+
this.log('.env is properly excluded from git', 'success');
|
|
279
|
+
this.passed++;
|
|
280
|
+
} else {
|
|
281
|
+
this.addWarning('.env should be added to .gitignore');
|
|
282
|
+
}
|
|
283
|
+
} else {
|
|
284
|
+
this.addWarning('.gitignore file not found');
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Warn about placeholder values
|
|
288
|
+
Object.entries(this.env).forEach(([key, value]) => {
|
|
289
|
+
if (value.includes('your-') || value.includes('placeholder') || value === 'changeme') {
|
|
290
|
+
this.addWarning(`${key} appears to contain a placeholder value`);
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
validateMCPToolCompatibility() {
|
|
296
|
+
console.log(chalk.bold('\nš Checking MCP Tool Compatibility...'));
|
|
297
|
+
|
|
298
|
+
const tools = {
|
|
299
|
+
'context7': ['CONTEXT7_API_KEY'],
|
|
300
|
+
'brave-search': ['BRAVE_API_KEY'],
|
|
301
|
+
'mem0': ['OPENAI_API_KEY', 'LLM_PROVIDER', 'LLM_CHOICE', 'EMBEDDING_MODEL_CHOICE'],
|
|
302
|
+
'clear-thought': ['OPENAI_API_KEY'],
|
|
303
|
+
'archon': ['OPENAI_API_KEY', 'SUPABASE_URL', 'SUPABASE_SERVICE_ROLE_KEY'],
|
|
304
|
+
'openmemory': ['OPENMEMORY_API_KEY', 'CLIENT_NAME'],
|
|
305
|
+
'deepwiki': [] // No API key required
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
Object.entries(tools).forEach(([tool, requiredVars]) => {
|
|
309
|
+
if (requiredVars.length === 0) {
|
|
310
|
+
this.log(`${tool}: Ready (no API key required)`, 'success');
|
|
311
|
+
this.passed++;
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const missing = requiredVars.filter(
|
|
316
|
+
varName => !this.env[varName] && !process.env[varName]
|
|
317
|
+
);
|
|
318
|
+
|
|
319
|
+
if (missing.length === 0) {
|
|
320
|
+
this.log(`${tool}: Ready`, 'success');
|
|
321
|
+
this.passed++;
|
|
322
|
+
} else {
|
|
323
|
+
this.addWarning(`${tool}: Missing ${missing.join(', ')}`);
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
generateReport() {
|
|
329
|
+
console.log(chalk.bold('\n\nš Environment Validation Report\n'));
|
|
330
|
+
console.log(chalk.bold('ā'.repeat(50)));
|
|
331
|
+
|
|
332
|
+
// Summary
|
|
333
|
+
console.log(chalk.bold('\nSummary:'));
|
|
334
|
+
console.log(` ${chalk.green('ā')} Configured: ${chalk.bold(this.passed)}`);
|
|
335
|
+
console.log(` ${chalk.red('ā')} Missing: ${chalk.bold(this.failed)}`);
|
|
336
|
+
console.log(` ${chalk.yellow('ā ')} Warnings: ${chalk.bold(this.warnings.length)}`);
|
|
337
|
+
|
|
338
|
+
// Errors
|
|
339
|
+
if (this.errors.length > 0) {
|
|
340
|
+
console.log(chalk.bold('\n\nRequired Configuration Missing:'));
|
|
341
|
+
this.errors.forEach((error, i) => {
|
|
342
|
+
console.log(` ${i + 1}. ${chalk.red(error)}`);
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Warnings
|
|
347
|
+
if (this.warnings.length > 0) {
|
|
348
|
+
console.log(chalk.bold('\n\nWarnings:'));
|
|
349
|
+
this.warnings.forEach((warning, i) => {
|
|
350
|
+
console.log(` ${i + 1}. ${chalk.yellow(warning)}`);
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
console.log(chalk.bold('\n' + 'ā'.repeat(50)));
|
|
355
|
+
|
|
356
|
+
// Overall status
|
|
357
|
+
console.log(chalk.bold('\nOverall Status:'));
|
|
358
|
+
if (this.failed === 0) {
|
|
359
|
+
console.log(chalk.green(' ā Environment configuration is valid'));
|
|
360
|
+
console.log(chalk.green('\n All required MCP tools are configured!\n'));
|
|
361
|
+
} else {
|
|
362
|
+
console.log(chalk.red(` ā Missing ${this.failed} required configuration(s)`));
|
|
363
|
+
console.log(chalk.yellow('\n Setup Instructions:\n'));
|
|
364
|
+
console.log(chalk.cyan(' 1. Copy .env.template to .env:'));
|
|
365
|
+
console.log(chalk.gray(' cp .env.template .env\n'));
|
|
366
|
+
console.log(chalk.cyan(' 2. Add your API keys to .env\n'));
|
|
367
|
+
console.log(chalk.cyan(' 3. Run validation again:'));
|
|
368
|
+
console.log(chalk.gray(' npm run validate:env\n'));
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return this.failed === 0;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
async run() {
|
|
375
|
+
console.log(chalk.bold.cyan('\nš AgentDevFramework Environment Validator\n'));
|
|
376
|
+
|
|
377
|
+
const spinner = ora('Starting validation...').start();
|
|
378
|
+
|
|
379
|
+
try {
|
|
380
|
+
spinner.text = 'Checking .env file...';
|
|
381
|
+
const envExists = this.checkEnvFileExists();
|
|
382
|
+
|
|
383
|
+
if (!envExists) {
|
|
384
|
+
spinner.fail('Environment file not found');
|
|
385
|
+
return this.generateReport();
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
spinner.text = 'Loading environment variables...';
|
|
389
|
+
const loaded = this.loadEnvFile();
|
|
390
|
+
|
|
391
|
+
if (!loaded) {
|
|
392
|
+
spinner.fail('Failed to load environment file');
|
|
393
|
+
return this.generateReport();
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
spinner.text = 'Validating required variables...';
|
|
397
|
+
this.validateRequired();
|
|
398
|
+
|
|
399
|
+
spinner.text = 'Validating optional variables...';
|
|
400
|
+
this.validateOptional();
|
|
401
|
+
|
|
402
|
+
spinner.text = 'Checking for sensitive data...';
|
|
403
|
+
this.checkForSensitiveData();
|
|
404
|
+
|
|
405
|
+
spinner.text = 'Checking MCP tool compatibility...';
|
|
406
|
+
this.validateMCPToolCompatibility();
|
|
407
|
+
|
|
408
|
+
spinner.succeed('Validation complete');
|
|
409
|
+
|
|
410
|
+
return this.generateReport();
|
|
411
|
+
} catch (error) {
|
|
412
|
+
spinner.fail('Validation failed');
|
|
413
|
+
console.error(chalk.red(`\nError: ${error.message}`));
|
|
414
|
+
console.error(error.stack);
|
|
415
|
+
return false;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Run validation if called directly
|
|
421
|
+
if (require.main === module) {
|
|
422
|
+
const validator = new EnvValidator();
|
|
423
|
+
validator.run().then(success => {
|
|
424
|
+
process.exit(success ? 0 : 1);
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
module.exports = EnvValidator;
|