@juspay/neurolink 1.2.4 → 1.3.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.
@@ -0,0 +1,532 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * NeuroLink CLI Configuration Management
4
+ *
5
+ * Enhanced configuration system with interactive setup,
6
+ * multi-profile support, and smart validation.
7
+ */
8
+ import inquirer from 'inquirer';
9
+ import fs from 'fs';
10
+ import path from 'path';
11
+ import os from 'os';
12
+ import chalk from 'chalk';
13
+ import { z } from 'zod';
14
+ // Configuration schema for validation
15
+ const ConfigSchema = z.object({
16
+ defaultProvider: z.enum(['auto', 'openai', 'bedrock', 'vertex', 'anthropic', 'azure', 'huggingface']).default('auto'),
17
+ providers: z.object({
18
+ openai: z.object({
19
+ apiKey: z.string().optional(),
20
+ model: z.string().default('gpt-4'),
21
+ baseURL: z.string().optional()
22
+ }).optional(),
23
+ bedrock: z.object({
24
+ region: z.string().optional(),
25
+ accessKeyId: z.string().optional(),
26
+ secretAccessKey: z.string().optional(),
27
+ sessionToken: z.string().optional(),
28
+ model: z.string().default('arn:aws:bedrock:us-east-2:225681119357:inference-profile/us.anthropic.claude-3-7-sonnet-20250219-v1:0')
29
+ }).optional(),
30
+ vertex: z.object({
31
+ projectId: z.string().optional(),
32
+ location: z.string().default('us-east5'),
33
+ credentials: z.string().optional(),
34
+ serviceAccountKey: z.string().optional(),
35
+ clientEmail: z.string().optional(),
36
+ privateKey: z.string().optional(),
37
+ model: z.string().default('gemini-1.5-pro')
38
+ }).optional(),
39
+ anthropic: z.object({
40
+ apiKey: z.string().optional(),
41
+ model: z.string().default('claude-3-5-sonnet-20241022')
42
+ }).optional(),
43
+ azure: z.object({
44
+ apiKey: z.string().optional(),
45
+ endpoint: z.string().optional(),
46
+ deploymentId: z.string().optional(),
47
+ model: z.string().default('gpt-4')
48
+ }).optional(),
49
+ huggingface: z.object({
50
+ apiKey: z.string().optional(),
51
+ model: z.string().default('microsoft/DialoGPT-large')
52
+ }).optional()
53
+ }).default({}),
54
+ profiles: z.record(z.string(), z.any()).default({}),
55
+ preferences: z.object({
56
+ outputFormat: z.enum(['text', 'json', 'yaml']).default('text'),
57
+ temperature: z.number().min(0).max(2).default(0.7),
58
+ maxTokens: z.number().min(1).max(4000).default(500),
59
+ enableLogging: z.boolean().default(false),
60
+ enableCaching: z.boolean().default(true),
61
+ cacheStrategy: z.enum(['memory', 'file', 'redis']).default('memory')
62
+ }).default({})
63
+ });
64
+ export class ConfigManager {
65
+ configDir;
66
+ configFile;
67
+ config;
68
+ constructor() {
69
+ this.configDir = path.join(os.homedir(), '.neurolink');
70
+ this.configFile = path.join(this.configDir, 'config.json');
71
+ this.config = this.loadConfig();
72
+ }
73
+ /**
74
+ * Load configuration from file or create default
75
+ */
76
+ loadConfig() {
77
+ try {
78
+ if (fs.existsSync(this.configFile)) {
79
+ const configData = JSON.parse(fs.readFileSync(this.configFile, 'utf8'));
80
+ return ConfigSchema.parse(configData);
81
+ }
82
+ }
83
+ catch (error) {
84
+ console.warn(chalk.yellow(`⚠️ Invalid config file: ${error instanceof Error ? error.message : 'Unknown error'}`));
85
+ }
86
+ return ConfigSchema.parse({});
87
+ }
88
+ /**
89
+ * Save configuration to file
90
+ */
91
+ saveConfig() {
92
+ try {
93
+ // Ensure config directory exists
94
+ if (!fs.existsSync(this.configDir)) {
95
+ fs.mkdirSync(this.configDir, { recursive: true });
96
+ }
97
+ // Validate before saving
98
+ const validatedConfig = ConfigSchema.parse(this.config);
99
+ fs.writeFileSync(this.configFile, JSON.stringify(validatedConfig, null, 2));
100
+ console.log(chalk.green(`✅ Configuration saved to ${this.configFile}`));
101
+ }
102
+ catch (error) {
103
+ console.error(chalk.red(`❌ Failed to save config: ${error instanceof Error ? error.message : 'Unknown error'}`));
104
+ process.exit(1);
105
+ }
106
+ }
107
+ /**
108
+ * Interactive configuration setup
109
+ */
110
+ async initInteractive() {
111
+ console.log(chalk.blue('🧠 NeuroLink Configuration Setup\n'));
112
+ try {
113
+ // Basic preferences
114
+ const preferences = await inquirer.prompt([
115
+ {
116
+ type: 'list',
117
+ name: 'defaultProvider',
118
+ message: 'Select your default AI provider:',
119
+ choices: [
120
+ { name: 'Auto (recommended) - Automatically select best available', value: 'auto' },
121
+ { name: 'OpenAI - GPT models', value: 'openai' },
122
+ { name: 'Amazon Bedrock - Claude, Llama, Titan', value: 'bedrock' },
123
+ { name: 'Google Vertex AI - Gemini models', value: 'vertex' },
124
+ { name: 'Anthropic - Claude models (direct)', value: 'anthropic' },
125
+ { name: 'Azure OpenAI - Enterprise GPT', value: 'azure' },
126
+ { name: 'Hugging Face - Open source models', value: 'huggingface' }
127
+ ],
128
+ default: this.config.defaultProvider
129
+ },
130
+ {
131
+ type: 'list',
132
+ name: 'outputFormat',
133
+ message: 'Preferred output format:',
134
+ choices: ['text', 'json', 'yaml'],
135
+ default: this.config.preferences.outputFormat
136
+ },
137
+ {
138
+ type: 'number',
139
+ name: 'temperature',
140
+ message: 'Default creativity level (0.0 = focused, 1.0 = creative):',
141
+ default: this.config.preferences.temperature,
142
+ validate: (value) => value >= 0 && value <= 2
143
+ },
144
+ {
145
+ type: 'confirm',
146
+ name: 'setupProviders',
147
+ message: 'Would you like to configure provider credentials now?',
148
+ default: true
149
+ }
150
+ ]);
151
+ // Update config with preferences
152
+ this.config.defaultProvider = preferences.defaultProvider;
153
+ this.config.preferences.outputFormat = preferences.outputFormat;
154
+ this.config.preferences.temperature = preferences.temperature;
155
+ // Setup providers if requested
156
+ if (preferences.setupProviders) {
157
+ await this.setupProviders();
158
+ }
159
+ this.saveConfig();
160
+ console.log(chalk.green('\n✅ Configuration setup complete!'));
161
+ console.log(chalk.blue('💡 You can modify settings anytime with: neurolink config edit'));
162
+ console.log(chalk.blue('💡 Test your setup with: neurolink status'));
163
+ }
164
+ catch (error) {
165
+ if (error instanceof Error && error.message === 'User force closed the prompt with 0 null') {
166
+ console.log(chalk.yellow('\n⚠️ Setup cancelled by user'));
167
+ process.exit(0);
168
+ }
169
+ throw error;
170
+ }
171
+ }
172
+ /**
173
+ * Setup individual providers
174
+ */
175
+ async setupProviders() {
176
+ const { selectedProviders } = await inquirer.prompt([
177
+ {
178
+ type: 'checkbox',
179
+ name: 'selectedProviders',
180
+ message: 'Select providers to configure:',
181
+ choices: [
182
+ { name: 'OpenAI (GPT-4, GPT-3.5)', value: 'openai' },
183
+ { name: 'Amazon Bedrock (Claude, Llama)', value: 'bedrock' },
184
+ { name: 'Google Vertex AI (Gemini)', value: 'vertex' },
185
+ { name: 'Anthropic Direct (Claude)', value: 'anthropic' },
186
+ { name: 'Azure OpenAI (Enterprise)', value: 'azure' },
187
+ { name: 'Hugging Face (Open Source)', value: 'huggingface' }
188
+ ]
189
+ }
190
+ ]);
191
+ for (const provider of selectedProviders) {
192
+ await this.setupProvider(provider);
193
+ }
194
+ }
195
+ /**
196
+ * Setup individual provider
197
+ */
198
+ async setupProvider(provider) {
199
+ console.log(chalk.blue(`\n🔧 Configuring ${provider.toUpperCase()}`));
200
+ switch (provider) {
201
+ case 'openai':
202
+ await this.setupOpenAI();
203
+ break;
204
+ case 'bedrock':
205
+ await this.setupBedrock();
206
+ break;
207
+ case 'vertex':
208
+ await this.setupVertex();
209
+ break;
210
+ case 'anthropic':
211
+ await this.setupAnthropic();
212
+ break;
213
+ case 'azure':
214
+ await this.setupAzure();
215
+ break;
216
+ case 'huggingface':
217
+ await this.setupHuggingFace();
218
+ break;
219
+ }
220
+ }
221
+ /**
222
+ * OpenAI provider setup
223
+ */
224
+ async setupOpenAI() {
225
+ const answers = await inquirer.prompt([
226
+ {
227
+ type: 'password',
228
+ name: 'apiKey',
229
+ message: 'OpenAI API Key (sk-...):',
230
+ validate: (value) => value.startsWith('sk-') || 'API key should start with "sk-"'
231
+ },
232
+ {
233
+ type: 'list',
234
+ name: 'model',
235
+ message: 'Default model:',
236
+ choices: ['gpt-4', 'gpt-4-turbo', 'gpt-3.5-turbo'],
237
+ default: 'gpt-4'
238
+ },
239
+ {
240
+ type: 'input',
241
+ name: 'baseURL',
242
+ message: 'Custom base URL (optional):',
243
+ default: ''
244
+ }
245
+ ]);
246
+ this.config.providers.openai = {
247
+ apiKey: answers.apiKey,
248
+ model: answers.model,
249
+ ...(answers.baseURL && { baseURL: answers.baseURL })
250
+ };
251
+ }
252
+ /**
253
+ * Amazon Bedrock provider setup
254
+ */
255
+ async setupBedrock() {
256
+ const answers = await inquirer.prompt([
257
+ {
258
+ type: 'input',
259
+ name: 'region',
260
+ message: 'AWS Region:',
261
+ default: 'us-east-1'
262
+ },
263
+ {
264
+ type: 'input',
265
+ name: 'accessKeyId',
266
+ message: 'AWS Access Key ID (optional if using IAM roles):'
267
+ },
268
+ {
269
+ type: 'password',
270
+ name: 'secretAccessKey',
271
+ message: 'AWS Secret Access Key (optional if using IAM roles):'
272
+ },
273
+ {
274
+ type: 'password',
275
+ name: 'sessionToken',
276
+ message: 'AWS Session Token (optional):'
277
+ },
278
+ {
279
+ type: 'input',
280
+ name: 'model',
281
+ message: 'Model ARN:',
282
+ default: 'arn:aws:bedrock:us-east-2:225681119357:inference-profile/us.anthropic.claude-3-7-sonnet-20250219-v1:0'
283
+ }
284
+ ]);
285
+ this.config.providers.bedrock = {
286
+ region: answers.region,
287
+ ...(answers.accessKeyId && { accessKeyId: answers.accessKeyId }),
288
+ ...(answers.secretAccessKey && { secretAccessKey: answers.secretAccessKey }),
289
+ ...(answers.sessionToken && { sessionToken: answers.sessionToken }),
290
+ model: answers.model
291
+ };
292
+ }
293
+ /**
294
+ * Google Vertex AI provider setup
295
+ */
296
+ async setupVertex() {
297
+ const { authMethod } = await inquirer.prompt([
298
+ {
299
+ type: 'list',
300
+ name: 'authMethod',
301
+ message: 'Authentication method:',
302
+ choices: [
303
+ { name: 'Service Account File', value: 'file' },
304
+ { name: 'Service Account JSON String', value: 'json' },
305
+ { name: 'Individual Environment Variables', value: 'env' }
306
+ ]
307
+ }
308
+ ]);
309
+ const commonAnswers = await inquirer.prompt([
310
+ {
311
+ type: 'input',
312
+ name: 'projectId',
313
+ message: 'Google Cloud Project ID:',
314
+ validate: (value) => value.length > 0 || 'Project ID is required'
315
+ },
316
+ {
317
+ type: 'input',
318
+ name: 'location',
319
+ message: 'Vertex AI Location:',
320
+ default: 'us-east5'
321
+ },
322
+ {
323
+ type: 'list',
324
+ name: 'model',
325
+ message: 'Default model:',
326
+ choices: ['gemini-1.5-pro', 'gemini-1.5-flash', 'gemini-pro'],
327
+ default: 'gemini-1.5-pro'
328
+ }
329
+ ]);
330
+ let authConfig = {};
331
+ switch (authMethod) {
332
+ case 'file':
333
+ const fileAnswers = await inquirer.prompt([
334
+ {
335
+ type: 'input',
336
+ name: 'credentials',
337
+ message: 'Path to service account JSON file:',
338
+ validate: (value) => fs.existsSync(value) || 'File does not exist'
339
+ }
340
+ ]);
341
+ authConfig = { credentials: fileAnswers.credentials };
342
+ break;
343
+ case 'json':
344
+ const jsonAnswers = await inquirer.prompt([
345
+ {
346
+ type: 'input',
347
+ name: 'serviceAccountKey',
348
+ message: 'Service account JSON string:',
349
+ validate: (value) => {
350
+ try {
351
+ JSON.parse(value);
352
+ return true;
353
+ }
354
+ catch {
355
+ return 'Invalid JSON';
356
+ }
357
+ }
358
+ }
359
+ ]);
360
+ authConfig = { serviceAccountKey: jsonAnswers.serviceAccountKey };
361
+ break;
362
+ case 'env':
363
+ const envAnswers = await inquirer.prompt([
364
+ {
365
+ type: 'input',
366
+ name: 'clientEmail',
367
+ message: 'Service account email:',
368
+ validate: (value) => value.includes('@') || 'Invalid email format'
369
+ },
370
+ {
371
+ type: 'password',
372
+ name: 'privateKey',
373
+ message: 'Private key:'
374
+ }
375
+ ]);
376
+ authConfig = {
377
+ clientEmail: envAnswers.clientEmail,
378
+ privateKey: envAnswers.privateKey
379
+ };
380
+ break;
381
+ }
382
+ this.config.providers.vertex = {
383
+ projectId: commonAnswers.projectId,
384
+ location: commonAnswers.location,
385
+ model: commonAnswers.model,
386
+ ...authConfig
387
+ };
388
+ }
389
+ /**
390
+ * Anthropic provider setup
391
+ */
392
+ async setupAnthropic() {
393
+ const answers = await inquirer.prompt([
394
+ {
395
+ type: 'password',
396
+ name: 'apiKey',
397
+ message: 'Anthropic API Key:',
398
+ validate: (value) => value.length > 0 || 'API key is required'
399
+ },
400
+ {
401
+ type: 'list',
402
+ name: 'model',
403
+ message: 'Default model:',
404
+ choices: [
405
+ 'claude-3-5-sonnet-20241022',
406
+ 'claude-3-5-haiku-20241022',
407
+ 'claude-3-opus-20240229'
408
+ ],
409
+ default: 'claude-3-5-sonnet-20241022'
410
+ }
411
+ ]);
412
+ this.config.providers.anthropic = answers;
413
+ }
414
+ /**
415
+ * Azure OpenAI provider setup
416
+ */
417
+ async setupAzure() {
418
+ const answers = await inquirer.prompt([
419
+ {
420
+ type: 'password',
421
+ name: 'apiKey',
422
+ message: 'Azure OpenAI API Key:'
423
+ },
424
+ {
425
+ type: 'input',
426
+ name: 'endpoint',
427
+ message: 'Azure OpenAI Endpoint:',
428
+ validate: (value) => value.startsWith('https://') || 'Endpoint should start with https://'
429
+ },
430
+ {
431
+ type: 'input',
432
+ name: 'deploymentId',
433
+ message: 'Deployment ID:'
434
+ },
435
+ {
436
+ type: 'list',
437
+ name: 'model',
438
+ message: 'Model:',
439
+ choices: ['gpt-4', 'gpt-4-turbo', 'gpt-35-turbo'],
440
+ default: 'gpt-4'
441
+ }
442
+ ]);
443
+ this.config.providers.azure = answers;
444
+ }
445
+ /**
446
+ * Hugging Face provider setup
447
+ */
448
+ async setupHuggingFace() {
449
+ const answers = await inquirer.prompt([
450
+ {
451
+ type: 'password',
452
+ name: 'apiKey',
453
+ message: 'Hugging Face API Key:'
454
+ },
455
+ {
456
+ type: 'input',
457
+ name: 'model',
458
+ message: 'Model name:',
459
+ default: 'microsoft/DialoGPT-large'
460
+ }
461
+ ]);
462
+ this.config.providers.huggingface = answers;
463
+ }
464
+ /**
465
+ * Get current configuration
466
+ */
467
+ getConfig() {
468
+ return this.config;
469
+ }
470
+ /**
471
+ * Update configuration
472
+ */
473
+ updateConfig(updates) {
474
+ this.config = { ...this.config, ...updates };
475
+ this.saveConfig();
476
+ }
477
+ /**
478
+ * Show current configuration
479
+ */
480
+ showConfig() {
481
+ console.log(chalk.blue('📋 Current NeuroLink Configuration\n'));
482
+ console.log(chalk.cyan('General Settings:'));
483
+ console.log(` Default Provider: ${chalk.white(this.config.defaultProvider)}`);
484
+ console.log(` Output Format: ${chalk.white(this.config.preferences.outputFormat)}`);
485
+ console.log(` Temperature: ${chalk.white(this.config.preferences.temperature)}`);
486
+ console.log(` Max Tokens: ${chalk.white(this.config.preferences.maxTokens)}`);
487
+ console.log(chalk.cyan('\nConfigured Providers:'));
488
+ Object.entries(this.config.providers).forEach(([name, config]) => {
489
+ if (config && Object.keys(config).length > 0) {
490
+ console.log(` ${chalk.green('✅')} ${name.toUpperCase()}`);
491
+ if ('model' in config) {
492
+ console.log(` Model: ${chalk.white(config.model)}`);
493
+ }
494
+ }
495
+ });
496
+ console.log(chalk.cyan('\nConfiguration File:'));
497
+ console.log(` Location: ${chalk.white(this.configFile)}`);
498
+ }
499
+ /**
500
+ * Validate configuration
501
+ */
502
+ validateConfig() {
503
+ const errors = [];
504
+ try {
505
+ ConfigSchema.parse(this.config);
506
+ }
507
+ catch (error) {
508
+ if (error instanceof z.ZodError) {
509
+ errors.push(...error.errors.map(e => `${e.path.join('.')}: ${e.message}`));
510
+ }
511
+ }
512
+ // Check for at least one configured provider
513
+ const hasProvider = Object.values(this.config.providers).some(provider => provider && Object.keys(provider).length > 0);
514
+ if (!hasProvider) {
515
+ errors.push('No providers configured. Run "neurolink config init" to set up providers.');
516
+ }
517
+ return {
518
+ valid: errors.length === 0,
519
+ errors
520
+ };
521
+ }
522
+ /**
523
+ * Reset configuration to defaults
524
+ */
525
+ resetConfig() {
526
+ this.config = ConfigSchema.parse({});
527
+ this.saveConfig();
528
+ console.log(chalk.green('✅ Configuration reset to defaults'));
529
+ }
530
+ }
531
+ // Export for use in other CLI commands
532
+ export const configManager = new ConfigManager();
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * MCP Server Management Commands
4
+ * Real MCP server connectivity and management
5
+ */
6
+ import type { Argv } from 'yargs';
7
+ export declare function addMCPCommands(yargs: Argv): Argv;