@juspay/neurolink 1.5.3 → 1.9.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.
Files changed (176) hide show
  1. package/CHANGELOG.md +241 -1
  2. package/README.md +113 -20
  3. package/dist/agent/direct-tools.d.ts +1203 -0
  4. package/dist/agent/direct-tools.js +387 -0
  5. package/dist/cli/commands/agent-generate.d.ts +2 -0
  6. package/dist/cli/commands/agent-generate.js +70 -0
  7. package/dist/cli/commands/config.d.ts +76 -9
  8. package/dist/cli/commands/config.js +358 -233
  9. package/dist/cli/commands/mcp.d.ts +2 -1
  10. package/dist/cli/commands/mcp.js +874 -146
  11. package/dist/cli/commands/ollama.d.ts +8 -0
  12. package/dist/cli/commands/ollama.js +333 -0
  13. package/dist/cli/index.js +591 -327
  14. package/dist/cli/utils/complete-setup.d.ts +19 -0
  15. package/dist/cli/utils/complete-setup.js +81 -0
  16. package/dist/cli/utils/env-manager.d.ts +44 -0
  17. package/dist/cli/utils/env-manager.js +226 -0
  18. package/dist/cli/utils/interactive-setup.d.ts +48 -0
  19. package/dist/cli/utils/interactive-setup.js +302 -0
  20. package/dist/core/dynamic-models.d.ts +208 -0
  21. package/dist/core/dynamic-models.js +250 -0
  22. package/dist/core/factory.d.ts +13 -6
  23. package/dist/core/factory.js +180 -50
  24. package/dist/core/types.d.ts +8 -3
  25. package/dist/core/types.js +7 -4
  26. package/dist/index.d.ts +16 -16
  27. package/dist/index.js +16 -16
  28. package/dist/lib/agent/direct-tools.d.ts +1203 -0
  29. package/dist/lib/agent/direct-tools.js +387 -0
  30. package/dist/lib/core/dynamic-models.d.ts +208 -0
  31. package/dist/lib/core/dynamic-models.js +250 -0
  32. package/dist/lib/core/factory.d.ts +13 -6
  33. package/dist/lib/core/factory.js +180 -50
  34. package/dist/lib/core/types.d.ts +8 -3
  35. package/dist/lib/core/types.js +7 -4
  36. package/dist/lib/index.d.ts +16 -16
  37. package/dist/lib/index.js +16 -16
  38. package/dist/lib/mcp/auto-discovery.d.ts +120 -0
  39. package/dist/lib/mcp/auto-discovery.js +793 -0
  40. package/dist/lib/mcp/client.d.ts +66 -0
  41. package/dist/lib/mcp/client.js +245 -0
  42. package/dist/lib/mcp/config.d.ts +31 -0
  43. package/dist/lib/mcp/config.js +74 -0
  44. package/dist/lib/mcp/context-manager.d.ts +4 -4
  45. package/dist/lib/mcp/context-manager.js +24 -18
  46. package/dist/lib/mcp/factory.d.ts +28 -11
  47. package/dist/lib/mcp/factory.js +36 -29
  48. package/dist/lib/mcp/function-calling.d.ts +51 -0
  49. package/dist/lib/mcp/function-calling.js +510 -0
  50. package/dist/lib/mcp/index.d.ts +190 -0
  51. package/dist/lib/mcp/index.js +156 -0
  52. package/dist/lib/mcp/initialize-tools.d.ts +28 -0
  53. package/dist/lib/mcp/initialize-tools.js +209 -0
  54. package/dist/lib/mcp/initialize.d.ts +17 -0
  55. package/dist/lib/mcp/initialize.js +51 -0
  56. package/dist/lib/mcp/logging.d.ts +71 -0
  57. package/dist/lib/mcp/logging.js +183 -0
  58. package/dist/lib/mcp/manager.d.ts +67 -0
  59. package/dist/lib/mcp/manager.js +176 -0
  60. package/dist/lib/mcp/neurolink-mcp-client.d.ts +96 -0
  61. package/dist/lib/mcp/neurolink-mcp-client.js +417 -0
  62. package/dist/lib/mcp/orchestrator.d.ts +3 -3
  63. package/dist/lib/mcp/orchestrator.js +46 -43
  64. package/dist/lib/mcp/registry.d.ts +2 -2
  65. package/dist/lib/mcp/registry.js +42 -33
  66. package/dist/lib/mcp/servers/ai-providers/ai-analysis-tools.d.ts +1 -1
  67. package/dist/lib/mcp/servers/ai-providers/ai-analysis-tools.js +205 -66
  68. package/dist/lib/mcp/servers/ai-providers/ai-core-server.js +143 -99
  69. package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.d.ts +6 -6
  70. package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.js +404 -251
  71. package/dist/lib/mcp/servers/utilities/utility-server.d.ts +8 -0
  72. package/dist/lib/mcp/servers/utilities/utility-server.js +326 -0
  73. package/dist/lib/mcp/tool-integration.d.ts +67 -0
  74. package/dist/lib/mcp/tool-integration.js +179 -0
  75. package/dist/lib/mcp/unified-registry.d.ts +269 -0
  76. package/dist/lib/mcp/unified-registry.js +1411 -0
  77. package/dist/lib/neurolink.d.ts +68 -6
  78. package/dist/lib/neurolink.js +314 -42
  79. package/dist/lib/providers/agent-enhanced-provider.d.ts +59 -0
  80. package/dist/lib/providers/agent-enhanced-provider.js +242 -0
  81. package/dist/lib/providers/amazonBedrock.d.ts +3 -3
  82. package/dist/lib/providers/amazonBedrock.js +54 -50
  83. package/dist/lib/providers/anthropic.d.ts +2 -2
  84. package/dist/lib/providers/anthropic.js +92 -84
  85. package/dist/lib/providers/azureOpenAI.d.ts +2 -2
  86. package/dist/lib/providers/azureOpenAI.js +97 -86
  87. package/dist/lib/providers/function-calling-provider.d.ts +70 -0
  88. package/dist/lib/providers/function-calling-provider.js +359 -0
  89. package/dist/lib/providers/googleAIStudio.d.ts +10 -5
  90. package/dist/lib/providers/googleAIStudio.js +60 -38
  91. package/dist/lib/providers/googleVertexAI.d.ts +3 -3
  92. package/dist/lib/providers/googleVertexAI.js +96 -86
  93. package/dist/lib/providers/huggingFace.d.ts +31 -0
  94. package/dist/lib/providers/huggingFace.js +362 -0
  95. package/dist/lib/providers/index.d.ts +14 -8
  96. package/dist/lib/providers/index.js +18 -12
  97. package/dist/lib/providers/mcp-provider.d.ts +62 -0
  98. package/dist/lib/providers/mcp-provider.js +183 -0
  99. package/dist/lib/providers/mistralAI.d.ts +32 -0
  100. package/dist/lib/providers/mistralAI.js +223 -0
  101. package/dist/lib/providers/ollama.d.ts +51 -0
  102. package/dist/lib/providers/ollama.js +508 -0
  103. package/dist/lib/providers/openAI.d.ts +7 -3
  104. package/dist/lib/providers/openAI.js +45 -33
  105. package/dist/lib/utils/logger.js +2 -2
  106. package/dist/lib/utils/providerUtils.js +59 -22
  107. package/dist/mcp/auto-discovery.d.ts +120 -0
  108. package/dist/mcp/auto-discovery.js +794 -0
  109. package/dist/mcp/client.d.ts +66 -0
  110. package/dist/mcp/client.js +245 -0
  111. package/dist/mcp/config.d.ts +31 -0
  112. package/dist/mcp/config.js +74 -0
  113. package/dist/mcp/context-manager.d.ts +4 -4
  114. package/dist/mcp/context-manager.js +24 -18
  115. package/dist/mcp/factory.d.ts +28 -11
  116. package/dist/mcp/factory.js +36 -29
  117. package/dist/mcp/function-calling.d.ts +51 -0
  118. package/dist/mcp/function-calling.js +510 -0
  119. package/dist/mcp/index.d.ts +190 -0
  120. package/dist/mcp/index.js +156 -0
  121. package/dist/mcp/initialize-tools.d.ts +28 -0
  122. package/dist/mcp/initialize-tools.js +210 -0
  123. package/dist/mcp/initialize.d.ts +17 -0
  124. package/dist/mcp/initialize.js +51 -0
  125. package/dist/mcp/logging.d.ts +71 -0
  126. package/dist/mcp/logging.js +183 -0
  127. package/dist/mcp/manager.d.ts +67 -0
  128. package/dist/mcp/manager.js +176 -0
  129. package/dist/mcp/neurolink-mcp-client.d.ts +96 -0
  130. package/dist/mcp/neurolink-mcp-client.js +417 -0
  131. package/dist/mcp/orchestrator.d.ts +3 -3
  132. package/dist/mcp/orchestrator.js +46 -43
  133. package/dist/mcp/registry.d.ts +2 -2
  134. package/dist/mcp/registry.js +42 -33
  135. package/dist/mcp/servers/ai-providers/ai-analysis-tools.d.ts +1 -1
  136. package/dist/mcp/servers/ai-providers/ai-analysis-tools.js +205 -66
  137. package/dist/mcp/servers/ai-providers/ai-core-server.js +143 -99
  138. package/dist/mcp/servers/ai-providers/ai-workflow-tools.d.ts +6 -6
  139. package/dist/mcp/servers/ai-providers/ai-workflow-tools.js +404 -253
  140. package/dist/mcp/servers/utilities/utility-server.d.ts +8 -0
  141. package/dist/mcp/servers/utilities/utility-server.js +326 -0
  142. package/dist/mcp/tool-integration.d.ts +67 -0
  143. package/dist/mcp/tool-integration.js +179 -0
  144. package/dist/mcp/unified-registry.d.ts +269 -0
  145. package/dist/mcp/unified-registry.js +1411 -0
  146. package/dist/neurolink.d.ts +68 -6
  147. package/dist/neurolink.js +314 -42
  148. package/dist/providers/agent-enhanced-provider.d.ts +59 -0
  149. package/dist/providers/agent-enhanced-provider.js +242 -0
  150. package/dist/providers/amazonBedrock.d.ts +3 -3
  151. package/dist/providers/amazonBedrock.js +54 -50
  152. package/dist/providers/anthropic.d.ts +2 -2
  153. package/dist/providers/anthropic.js +92 -84
  154. package/dist/providers/azureOpenAI.d.ts +2 -2
  155. package/dist/providers/azureOpenAI.js +97 -86
  156. package/dist/providers/function-calling-provider.d.ts +70 -0
  157. package/dist/providers/function-calling-provider.js +359 -0
  158. package/dist/providers/googleAIStudio.d.ts +10 -5
  159. package/dist/providers/googleAIStudio.js +60 -38
  160. package/dist/providers/googleVertexAI.d.ts +3 -3
  161. package/dist/providers/googleVertexAI.js +96 -86
  162. package/dist/providers/huggingFace.d.ts +31 -0
  163. package/dist/providers/huggingFace.js +362 -0
  164. package/dist/providers/index.d.ts +14 -8
  165. package/dist/providers/index.js +18 -12
  166. package/dist/providers/mcp-provider.d.ts +62 -0
  167. package/dist/providers/mcp-provider.js +183 -0
  168. package/dist/providers/mistralAI.d.ts +32 -0
  169. package/dist/providers/mistralAI.js +223 -0
  170. package/dist/providers/ollama.d.ts +51 -0
  171. package/dist/providers/ollama.js +508 -0
  172. package/dist/providers/openAI.d.ts +7 -3
  173. package/dist/providers/openAI.js +45 -33
  174. package/dist/utils/logger.js +2 -2
  175. package/dist/utils/providerUtils.js +59 -22
  176. package/package.json +28 -4
package/dist/cli/index.js CHANGED
@@ -6,169 +6,144 @@
6
6
  * Features: Spinners, colors, batch processing, provider testing, rich help
7
7
  * Implementation: ~300 lines using simple JS utility functions
8
8
  */
9
- import { NeuroLink } from '../lib/neurolink.js';
10
- import yargs from 'yargs'; // Keep default import
11
- import { hideBin } from 'yargs/helpers';
12
- import ora from 'ora';
13
- import chalk from 'chalk';
14
- import fs from 'fs';
15
- import { fileURLToPath } from 'url';
16
- import { dirname } from 'path';
17
- import { addMCPCommands } from './commands/mcp.js';
9
+ import { NeuroLink } from "../lib/neurolink.js";
10
+ import yargs from "yargs";
11
+ import { hideBin } from "yargs/helpers";
12
+ import ora from "ora";
13
+ import chalk from "chalk";
14
+ import fs from "fs";
15
+ import { addMCPCommands } from "./commands/mcp.js";
16
+ import ollamaCommand from "./commands/ollama.js";
17
+ import { agentGenerateCommand } from "./commands/agent-generate.js";
18
18
  // Load environment variables from .env file
19
19
  try {
20
20
  // Try to import and configure dotenv
21
- const { config } = await import('dotenv');
21
+ const { config } = await import("dotenv");
22
22
  config(); // Load .env from current working directory
23
23
  }
24
24
  catch (error) {
25
25
  // dotenv is not available (dev dependency only) - this is fine for production
26
26
  // Environment variables should be set externally in production
27
27
  }
28
- // Get current directory for ESM
29
- const __filename = fileURLToPath(import.meta.url);
30
- const __dirname = dirname(__filename);
31
28
  // Utility Functions (Simple, Zero Maintenance)
32
- function formatOutput(result, format = 'text') {
33
- if (format === 'json') {
34
- return JSON.stringify(result, null, 2);
35
- }
36
- // Smart text formatting
37
- if (result?.content) {
38
- return result.content;
39
- }
40
- if (typeof result === 'string') {
41
- return result;
42
- }
43
- return JSON.stringify(result, null, 2);
44
- }
45
29
  function handleError(error, context) {
46
- let specificErrorMessage = error.message;
47
- const originalErrorMessageLowerCase = error.message ? error.message.toLowerCase() : '';
30
+ const specificErrorMessage = error.message;
31
+ const originalErrorMessageLowerCase = error.message
32
+ ? error.message.toLowerCase()
33
+ : "";
48
34
  const errorStringLowerCase = String(error).toLowerCase();
49
35
  let isAuthError = false;
50
36
  let genericMessage = specificErrorMessage; // Initialize genericMessage with the specific one
51
- if (originalErrorMessageLowerCase.includes('api_key') ||
52
- originalErrorMessageLowerCase.includes('google_ai_api_key') ||
53
- originalErrorMessageLowerCase.includes('aws_access_key_id') ||
54
- originalErrorMessageLowerCase.includes('aws_secret_access_key') ||
55
- originalErrorMessageLowerCase.includes('aws_session_token') ||
56
- originalErrorMessageLowerCase.includes('google_application_credentials') ||
57
- originalErrorMessageLowerCase.includes('google_service_account_key') ||
58
- originalErrorMessageLowerCase.includes('google_auth_client_email') ||
59
- originalErrorMessageLowerCase.includes('anthropic_api_key') ||
60
- originalErrorMessageLowerCase.includes('azure_openai_api_key')) {
37
+ if (originalErrorMessageLowerCase.includes("api_key") ||
38
+ originalErrorMessageLowerCase.includes("google_ai_api_key") ||
39
+ originalErrorMessageLowerCase.includes("aws_access_key_id") ||
40
+ originalErrorMessageLowerCase.includes("aws_secret_access_key") ||
41
+ originalErrorMessageLowerCase.includes("aws_session_token") ||
42
+ originalErrorMessageLowerCase.includes("google_application_credentials") ||
43
+ originalErrorMessageLowerCase.includes("google_service_account_key") ||
44
+ originalErrorMessageLowerCase.includes("google_auth_client_email") ||
45
+ originalErrorMessageLowerCase.includes("anthropic_api_key") ||
46
+ originalErrorMessageLowerCase.includes("azure_openai_api_key")) {
61
47
  isAuthError = true;
62
48
  }
63
- else if ( // Fallback to checking the full stringified error if direct message didn't match
64
- errorStringLowerCase.includes('api_key') ||
65
- errorStringLowerCase.includes('google_ai_api_key') ||
66
- errorStringLowerCase.includes('aws_access_key_id') ||
67
- errorStringLowerCase.includes('aws_secret_access_key') ||
68
- errorStringLowerCase.includes('aws_session_token') ||
69
- errorStringLowerCase.includes('google_application_credentials') ||
70
- errorStringLowerCase.includes('google_service_account_key') ||
71
- errorStringLowerCase.includes('google_auth_client_email') ||
72
- errorStringLowerCase.includes('anthropic_api_key') ||
73
- errorStringLowerCase.includes('azure_openai_api_key')) {
49
+ else if (
50
+ // Fallback to checking the full stringified error if direct message didn't match
51
+ errorStringLowerCase.includes("api_key") ||
52
+ errorStringLowerCase.includes("google_ai_api_key") ||
53
+ errorStringLowerCase.includes("aws_access_key_id") ||
54
+ errorStringLowerCase.includes("aws_secret_access_key") ||
55
+ errorStringLowerCase.includes("aws_session_token") ||
56
+ errorStringLowerCase.includes("google_application_credentials") ||
57
+ errorStringLowerCase.includes("google_service_account_key") ||
58
+ errorStringLowerCase.includes("google_auth_client_email") ||
59
+ errorStringLowerCase.includes("anthropic_api_key") ||
60
+ errorStringLowerCase.includes("azure_openai_api_key")) {
74
61
  isAuthError = true;
75
62
  }
76
63
  if (isAuthError) {
77
- genericMessage = 'Authentication error: Missing or invalid API key/credentials for the selected provider.';
78
- }
79
- else if (originalErrorMessageLowerCase.includes('enotfound') || // Prefer direct message checks
80
- originalErrorMessageLowerCase.includes('econnrefused') ||
81
- originalErrorMessageLowerCase.includes('invalid-endpoint') ||
82
- originalErrorMessageLowerCase.includes('network error') ||
83
- originalErrorMessageLowerCase.includes('could not connect') ||
84
- originalErrorMessageLowerCase.includes('timeout') ||
85
- errorStringLowerCase.includes('enotfound') || // Fallback to full string
86
- errorStringLowerCase.includes('econnrefused') ||
87
- errorStringLowerCase.includes('invalid-endpoint') ||
88
- errorStringLowerCase.includes('network error') ||
89
- errorStringLowerCase.includes('could not connect') ||
90
- errorStringLowerCase.includes('timeout') // General timeout
64
+ genericMessage =
65
+ "Authentication error: Missing or invalid API key/credentials for the selected provider.";
66
+ }
67
+ else if (originalErrorMessageLowerCase.includes("enotfound") || // Prefer direct message checks
68
+ originalErrorMessageLowerCase.includes("econnrefused") ||
69
+ originalErrorMessageLowerCase.includes("invalid-endpoint") ||
70
+ originalErrorMessageLowerCase.includes("network error") ||
71
+ originalErrorMessageLowerCase.includes("could not connect") ||
72
+ originalErrorMessageLowerCase.includes("timeout") ||
73
+ errorStringLowerCase.includes("enotfound") || // Fallback to full string
74
+ errorStringLowerCase.includes("econnrefused") ||
75
+ errorStringLowerCase.includes("invalid-endpoint") ||
76
+ errorStringLowerCase.includes("network error") ||
77
+ errorStringLowerCase.includes("could not connect") ||
78
+ errorStringLowerCase.includes("timeout") // General timeout
91
79
  ) {
92
- genericMessage = 'Network error: Could not connect to the API endpoint or the request timed out.';
80
+ genericMessage =
81
+ "Network error: Could not connect to the API endpoint or the request timed out.";
93
82
  }
94
- else if (errorStringLowerCase.includes('not authorized') || errorStringLowerCase.includes('permission denied')) {
95
- genericMessage = 'Authorization error: You are not authorized to perform this action or access this resource.';
83
+ else if (errorStringLowerCase.includes("not authorized") ||
84
+ errorStringLowerCase.includes("permission denied")) {
85
+ genericMessage =
86
+ "Authorization error: You are not authorized to perform this action or access this resource.";
96
87
  }
97
88
  // If no specific condition matched, genericMessage remains error.message
98
89
  console.error(chalk.red(`❌ ${context} failed: ${genericMessage}`));
99
90
  // Smart hints for common errors (just string matching!)
100
- if (genericMessage.toLowerCase().includes('api key') || genericMessage.toLowerCase().includes('credential')) {
101
- console.error(chalk.yellow('💡 Set Google AI Studio API key (RECOMMENDED): export GOOGLE_AI_API_KEY=AIza-...'));
102
- console.error(chalk.yellow('💡 Or set OpenAI API key: export OPENAI_API_KEY=sk-...'));
103
- console.error(chalk.yellow('💡 Or set AWS Bedrock credentials: export AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... AWS_REGION=us-east-1'));
104
- console.error(chalk.yellow('💡 Or set Google Vertex AI credentials: export GOOGLE_APPLICATION_CREDENTIALS=/path/to/key.json'));
105
- console.error(chalk.yellow('💡 Or set Anthropic API key: export ANTHROPIC_API_KEY=sk-ant-...'));
106
- console.error(chalk.yellow('💡 Or set Azure OpenAI credentials: export AZURE_OPENAI_API_KEY=... AZURE_OPENAI_ENDPOINT=...'));
107
- }
108
- if (error.message.toLowerCase().includes('rate limit')) {
109
- console.error(chalk.yellow('💡 Try again in a few moments or use --provider vertex'));
110
- }
111
- if (error.message.toLowerCase().includes('not authorized') || error.message.toLowerCase().includes('permission denied')) {
112
- console.error(chalk.yellow('💡 Check your account permissions for the selected model/service.'));
113
- console.error(chalk.yellow('💡 For AWS Bedrock, ensure you have permissions for the specific model and consider using inference profile ARNs.'));
91
+ if (genericMessage.toLowerCase().includes("api key") ||
92
+ genericMessage.toLowerCase().includes("credential")) {
93
+ console.error(chalk.yellow("💡 Set Google AI Studio API key (RECOMMENDED): export GOOGLE_AI_API_KEY=AIza-..."));
94
+ console.error(chalk.yellow("💡 Or set OpenAI API key: export OPENAI_API_KEY=sk-..."));
95
+ console.error(chalk.yellow("💡 Or set AWS Bedrock credentials: export AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... AWS_REGION=us-east-1"));
96
+ console.error(chalk.yellow("💡 Or set Google Vertex AI credentials: export GOOGLE_APPLICATION_CREDENTIALS=/path/to/key.json"));
97
+ console.error(chalk.yellow("💡 Or set Anthropic API key: export ANTHROPIC_API_KEY=sk-ant-..."));
98
+ console.error(chalk.yellow("💡 Or set Azure OpenAI credentials: export AZURE_OPENAI_API_KEY=... AZURE_OPENAI_ENDPOINT=..."));
99
+ }
100
+ if (error.message.toLowerCase().includes("rate limit")) {
101
+ console.error(chalk.yellow("💡 Try again in a few moments or use --provider vertex"));
102
+ }
103
+ if (error.message.toLowerCase().includes("not authorized") ||
104
+ error.message.toLowerCase().includes("permission denied")) {
105
+ console.error(chalk.yellow("💡 Check your account permissions for the selected model/service."));
106
+ console.error(chalk.yellow("💡 For AWS Bedrock, ensure you have permissions for the specific model and consider using inference profile ARNs."));
114
107
  }
115
108
  process.exit(1);
116
109
  }
117
- function validateConfig() {
118
- const hasGoogleAI = !!process.env.GOOGLE_AI_API_KEY;
119
- const hasOpenAI = !!process.env.OPENAI_API_KEY;
120
- const hasAWS = !!(process.env.AWS_REGION || process.env.AWS_ACCESS_KEY_ID);
121
- const hasGoogle = !!(process.env.GOOGLE_APPLICATION_CREDENTIALS || process.env.GOOGLE_SERVICE_ACCOUNT_KEY || process.env.GOOGLE_AUTH_CLIENT_EMAIL);
122
- const hasAnthropic = !!process.env.ANTHROPIC_API_KEY;
123
- const hasAzure = !!(process.env.AZURE_OPENAI_API_KEY && process.env.AZURE_OPENAI_ENDPOINT);
124
- if (!hasGoogleAI && !hasOpenAI && !hasAWS && !hasGoogle && !hasAnthropic && !hasAzure) {
125
- console.error(chalk.red('⚠️ No AI provider credentials found'));
126
- console.error(chalk.yellow('💡 Set one of:'));
127
- console.error(chalk.yellow(' • GOOGLE_AI_API_KEY=AIza-...'));
128
- console.error(chalk.yellow(' • OPENAI_API_KEY=sk-...'));
129
- console.error(chalk.yellow(' • AWS_REGION=us-east-1 (+ AWS credentials)'));
130
- console.error(chalk.yellow(' • GOOGLE_APPLICATION_CREDENTIALS=/path/to/key.json'));
131
- console.error(chalk.yellow(' • ANTHROPIC_API_KEY=sk-ant-...'));
132
- console.error(chalk.yellow(' • AZURE_OPENAI_API_KEY=... (+ AZURE_OPENAI_ENDPOINT)'));
133
- console.error(chalk.blue('\n📚 See: https://github.com/juspay/neurolink#setup'));
134
- process.exit(1);
135
- }
136
- }
137
110
  // Initialize SDK
138
111
  const sdk = new NeuroLink();
139
112
  // Manual pre-validation for unknown flags
140
113
  const args = hideBin(process.argv);
141
114
  // Enhanced CLI with Professional UX
142
115
  const cli = yargs(args)
143
- .scriptName('neurolink')
144
- .usage('Usage: $0 <command> [options]')
116
+ .scriptName("neurolink")
117
+ .usage("Usage: $0 <command> [options]")
145
118
  .version()
146
119
  .help()
147
- .alias('h', 'help')
148
- .alias('V', 'version')
120
+ .alias("h", "help")
121
+ .alias("V", "version")
149
122
  .strictOptions()
150
123
  .strictCommands()
151
- .demandCommand(1, '')
152
- .epilogue('For more info: https://github.com/juspay/neurolink')
153
- .showHelpOnFail(true, 'Specify --help for available options')
124
+ .demandCommand(1, "")
125
+ .epilogue("For more info: https://github.com/juspay/neurolink")
126
+ .showHelpOnFail(true, "Specify --help for available options")
154
127
  .middleware((argv) => {
155
128
  // Control SDK logging based on debug flag
156
129
  if (argv.debug) {
157
- process.env.NEUROLINK_DEBUG = 'true';
130
+ process.env.NEUROLINK_DEBUG = "true";
158
131
  }
159
132
  else {
160
133
  // Always set to false when debug is not enabled (including when not provided)
161
- process.env.NEUROLINK_DEBUG = 'false';
134
+ process.env.NEUROLINK_DEBUG = "false";
162
135
  }
163
136
  // Keep existing quiet middleware
164
- if (process.env.NEUROLINK_QUIET === 'true' && typeof argv.quiet === 'undefined') {
137
+ if (process.env.NEUROLINK_QUIET === "true" &&
138
+ typeof argv.quiet === "undefined") {
165
139
  argv.quiet = true;
166
140
  }
167
141
  })
168
142
  .fail((msg, err, yargsInstance) => {
169
143
  const exitProcess = () => {
170
- if (!process.exitCode)
144
+ if (!process.exitCode) {
171
145
  process.exit(1);
146
+ }
172
147
  };
173
148
  if (err) {
174
149
  // Error likely from an async command handler (e.g., via handleError)
@@ -179,16 +154,19 @@ const cli = yargs(args)
179
154
  // A simple heuristic: if the error message doesn't look like one of our handled generic messages,
180
155
  // it might be a direct yargs parsing error.
181
156
  const isLikelyYargsInternalError = err.message && // Ensure err.message exists
182
- !err.message.includes('Authentication error') &&
183
- !err.message.includes('Network error') &&
184
- !err.message.includes('Authorization error') &&
185
- !err.message.includes('Permission denied') && // from config export
186
- !err.message.includes('Invalid or unparseable JSON'); // from config import
157
+ !err.message.includes("Authentication error") &&
158
+ !err.message.includes("Network error") &&
159
+ !err.message.includes("Authorization error") &&
160
+ !err.message.includes("Permission denied") && // from config export
161
+ !err.message.includes("Invalid or unparseable JSON"); // from config import
187
162
  if (!alreadyExitedByHandleError) {
188
- process.stderr.write(chalk.red(`CLI Error: ${err.message || msg || 'An unexpected error occurred.'}\n`));
163
+ process.stderr.write(chalk.red(`CLI Error: ${err.message || msg || "An unexpected error occurred."}\n`));
189
164
  // If it's a yargs internal parsing error, show help.
190
165
  if (isLikelyYargsInternalError && msg) {
191
- yargsInstance.showHelp(h => { process.stderr.write(h + '\n'); exitProcess(); });
166
+ yargsInstance.showHelp((h) => {
167
+ process.stderr.write(h + "\n");
168
+ exitProcess();
169
+ });
192
170
  return;
193
171
  }
194
172
  exitProcess();
@@ -198,122 +176,225 @@ const cli = yargs(args)
198
176
  // Yargs parsing/validation error (msg is present, err is null)
199
177
  if (msg) {
200
178
  let processedMsg = `Error: ${msg}\n`;
201
- if (msg.includes('Not enough non-option arguments') || msg.includes('Missing required argument') || msg.includes('Unknown command')) {
179
+ if (msg.includes("Not enough non-option arguments") ||
180
+ msg.includes("Missing required argument") ||
181
+ msg.includes("Unknown command")) {
202
182
  process.stderr.write(chalk.red(processedMsg)); // Print error first
203
- yargsInstance.showHelp(h => { process.stderr.write('\n' + h + '\n'); exitProcess(); });
183
+ yargsInstance.showHelp((h) => {
184
+ process.stderr.write("\n" + h + "\n");
185
+ exitProcess();
186
+ });
204
187
  return; // Exit happens in callback
205
188
  }
206
- else if (msg.includes('Unknown argument') || msg.includes('Invalid values')) {
189
+ else if (msg.includes("Unknown argument") ||
190
+ msg.includes("Invalid values")) {
207
191
  processedMsg = `Error: ${msg}\nUse --help to see available options.\n`;
208
192
  }
209
193
  process.stderr.write(chalk.red(processedMsg));
210
194
  }
211
195
  else {
212
196
  // No specific message, but failure occurred (e.g. demandCommand failed silently)
213
- yargsInstance.showHelp(h => { process.stderr.write(h + '\n'); exitProcess(); });
197
+ yargsInstance.showHelp((h) => {
198
+ process.stderr.write(h + "\n");
199
+ exitProcess();
200
+ });
214
201
  return; // Exit happens in callback
215
202
  }
216
203
  exitProcess(); // Default exit
217
204
  })
218
205
  // Generate Text Command
219
- .command(['generate-text <prompt>', 'generate <prompt>'], 'Generate text using AI providers', (yargsInstance) => yargsInstance
220
- .usage('Usage: $0 generate-text <prompt> [options]')
221
- .positional('prompt', {
222
- type: 'string',
223
- description: 'Text prompt for AI generation',
206
+ .command(["generate-text <prompt>", "generate <prompt>"], "Generate text using AI providers", (yargsInstance) => yargsInstance
207
+ .usage("Usage: $0 generate-text <prompt> [options]")
208
+ .positional("prompt", {
209
+ type: "string",
210
+ description: "Text prompt for AI generation",
224
211
  demandOption: true,
225
212
  })
226
- .option('provider', {
227
- choices: ['auto', 'openai', 'bedrock', 'vertex', 'anthropic', 'azure', 'google-ai'],
228
- default: 'auto',
229
- description: 'AI provider to use (auto-selects best available)'
230
- })
231
- .option('temperature', { type: 'number', default: 0.7, description: 'Creativity level (0.0 = focused, 1.0 = creative)' })
232
- .option('max-tokens', { type: 'number', default: 500, description: 'Maximum tokens to generate' })
233
- .option('system', { type: 'string', description: 'System prompt to guide AI behavior' })
234
- .option('format', { choices: ['text', 'json'], default: 'text', alias: 'f', description: 'Output format' })
235
- .option('debug', { type: 'boolean', default: false, description: 'Enable debug mode with verbose output' }) // Kept for potential specific debug logic
236
- .option('timeout', { type: 'number', default: 30000, description: 'Timeout for the request in milliseconds' })
237
- .example('$0 generate-text "Hello world"', 'Basic text generation')
238
- .example('$0 generate-text "Write a story" --provider openai', 'Use specific provider'), async (argv) => {
213
+ .option("provider", {
214
+ choices: [
215
+ "auto",
216
+ "openai",
217
+ "bedrock",
218
+ "vertex",
219
+ "anthropic",
220
+ "azure",
221
+ "google-ai",
222
+ "huggingface",
223
+ "ollama",
224
+ "mistral",
225
+ ],
226
+ default: "auto",
227
+ description: "AI provider to use (auto-selects best available)",
228
+ })
229
+ .option("temperature", {
230
+ type: "number",
231
+ default: 0.7,
232
+ description: "Creativity level (0.0 = focused, 1.0 = creative)",
233
+ })
234
+ .option("max-tokens", {
235
+ type: "number",
236
+ default: 500,
237
+ description: "Maximum tokens to generate",
238
+ })
239
+ .option("system", {
240
+ type: "string",
241
+ description: "System prompt to guide AI behavior",
242
+ })
243
+ .option("format", {
244
+ choices: ["text", "json"],
245
+ default: "text",
246
+ alias: "f",
247
+ description: "Output format",
248
+ })
249
+ .option("debug", {
250
+ type: "boolean",
251
+ default: false,
252
+ description: "Enable debug mode with verbose output",
253
+ }) // Kept for potential specific debug logic
254
+ .option("timeout", {
255
+ type: "number",
256
+ default: 30000,
257
+ description: "Timeout for the request in milliseconds",
258
+ })
259
+ .option("disable-tools", {
260
+ type: "boolean",
261
+ default: false,
262
+ description: "Disable MCP tool integration (tools enabled by default)",
263
+ })
264
+ .example('$0 generate-text "Hello world"', "Basic text generation")
265
+ .example('$0 generate-text "Write a story" --provider openai', "Use specific provider")
266
+ .example('$0 generate-text "What time is it?"', "Use with natural tool integration (default)")
267
+ .example('$0 generate-text "Hello world" --disable-tools', "Use without tool integration"), async (argv) => {
239
268
  let originalConsole = {};
240
- if (argv.format === 'json' && !argv.quiet) { // Suppress only if not quiet, as quiet implies no spinners anyway
269
+ if (argv.format === "json" && !argv.quiet) {
270
+ // Suppress only if not quiet, as quiet implies no spinners anyway
241
271
  originalConsole = { ...console };
242
272
  Object.keys(originalConsole).forEach((key) => {
243
- if (typeof console[key] === 'function') {
273
+ if (typeof console[key] === "function") {
244
274
  console[key] = () => { };
245
275
  }
246
276
  });
247
277
  }
248
- const spinner = argv.format === 'json' || argv.quiet ? null : ora('🤖 Generating text...').start();
278
+ const spinner = argv.format === "json" || argv.quiet
279
+ ? null
280
+ : ora("🤖 Generating text...").start();
249
281
  try {
250
282
  const timeoutPromise = new Promise((_, reject) => {
251
283
  setTimeout(() => reject(new Error(`Request timeout (${argv.timeout}ms)`)), argv.timeout);
252
284
  });
285
+ // Use enhanced NeuroLink SDK with Lighthouse-style natural tool access
253
286
  const generatePromise = sdk.generateText({
254
- prompt: argv.prompt, // Cast because demandOption is true
255
- provider: argv.provider === 'auto' ? undefined : argv.provider,
287
+ prompt: argv.prompt,
288
+ provider: argv.provider === "auto"
289
+ ? undefined
290
+ : argv.provider,
256
291
  temperature: argv.temperature,
257
292
  maxTokens: argv.maxTokens,
258
- systemPrompt: argv.system
293
+ systemPrompt: argv.system,
294
+ // Lighthouse-style: Tools enabled by default, disable only if explicitly requested
295
+ disableTools: argv.disableTools === true, // Default true, can be disabled with --no-enable-tools
259
296
  });
260
- const result = await Promise.race([generatePromise, timeoutPromise]);
261
- if (argv.format === 'json' && originalConsole.log) {
297
+ const result = (await Promise.race([
298
+ generatePromise,
299
+ timeoutPromise,
300
+ ]));
301
+ if (argv.format === "json" && originalConsole.log) {
262
302
  Object.assign(console, originalConsole);
263
303
  }
264
- if (spinner)
265
- spinner.succeed(chalk.green('✅ Text generated successfully!'));
266
- if (argv.format === 'json') {
304
+ if (spinner) {
305
+ spinner.succeed(chalk.green("✅ Text generated successfully!"));
306
+ }
307
+ if (argv.format === "json") {
267
308
  const jsonOutput = {
268
- content: result.content || '', provider: result.provider,
269
- usage: result.usage || { promptTokens: 0, completionTokens: 0, totalTokens: 0 },
270
- responseTime: result.responseTime || 0
309
+ content: result.content || "",
310
+ provider: result.provider,
311
+ usage: result.usage || {
312
+ promptTokens: 0,
313
+ completionTokens: 0,
314
+ totalTokens: 0,
315
+ },
316
+ responseTime: result.responseTime || 0,
271
317
  };
272
- process.stdout.write(JSON.stringify(jsonOutput, null, 2) + '\n');
318
+ process.stdout.write(JSON.stringify(jsonOutput, null, 2) + "\n");
273
319
  }
274
320
  else if (argv.debug) {
275
321
  // Debug mode: Show AI response + full metadata
276
- if (result.content)
277
- console.log('\n' + result.content + '\n');
278
- console.log(JSON.stringify({ provider: result.provider, usage: result.usage, responseTime: result.responseTime }, null, 2));
279
- if (result.usage)
322
+ if (result.content) {
323
+ console.log("\n" + result.content + "\n");
324
+ }
325
+ console.log(JSON.stringify({
326
+ provider: result.provider,
327
+ usage: result.usage,
328
+ responseTime: result.responseTime,
329
+ }, null, 2));
330
+ if (result.usage) {
280
331
  console.log(chalk.blue(`ℹ️ ${result.usage.totalTokens} tokens used`));
332
+ }
281
333
  }
282
334
  else {
283
335
  // Default mode: Clean AI response only
284
- if (result.content)
336
+ if (result.content) {
285
337
  console.log(result.content);
338
+ }
286
339
  }
287
340
  // Explicitly exit to prevent hanging, especially with Google AI Studio
288
341
  process.exit(0);
289
342
  }
290
343
  catch (error) {
291
- if (argv.format === 'json' && originalConsole.log) {
344
+ if (argv.format === "json" && originalConsole.log) {
292
345
  Object.assign(console, originalConsole);
293
346
  }
294
- if (spinner)
347
+ if (spinner) {
295
348
  spinner.fail();
296
- if (argv.format === 'json') {
297
- process.stdout.write(JSON.stringify({ error: error.message, success: false }, null, 2) + '\n');
349
+ }
350
+ if (argv.format === "json") {
351
+ process.stdout.write(JSON.stringify({ error: error.message, success: false }, null, 2) + "\n");
298
352
  process.exit(1);
299
353
  }
300
354
  else {
301
- handleError(error, 'Text generation');
355
+ handleError(error, "Text generation");
302
356
  }
303
357
  }
304
358
  })
305
359
  // Stream Text Command
306
- .command('stream <prompt>', 'Stream text generation in real-time', (yargsInstance) => yargsInstance
307
- .usage('Usage: $0 stream <prompt> [options]')
308
- .positional('prompt', { type: 'string', description: 'Text prompt for streaming', demandOption: true })
309
- .option('provider', { choices: ['auto', 'openai', 'bedrock', 'vertex', 'anthropic', 'azure', 'google-ai'], default: 'auto', description: 'AI provider to use' })
310
- .option('temperature', { type: 'number', default: 0.7, description: 'Creativity level' })
311
- .option('debug', { type: 'boolean', default: false, description: 'Enable debug mode with interleaved logging' })
312
- .example('$0 stream "Tell me a story"', 'Stream a story in real-time'), async (argv) => {
360
+ .command("stream <prompt>", "Stream text generation in real-time", (yargsInstance) => yargsInstance
361
+ .usage("Usage: $0 stream <prompt> [options]")
362
+ .positional("prompt", {
363
+ type: "string",
364
+ description: "Text prompt for streaming",
365
+ demandOption: true,
366
+ })
367
+ .option("provider", {
368
+ choices: [
369
+ "auto",
370
+ "openai",
371
+ "bedrock",
372
+ "vertex",
373
+ "anthropic",
374
+ "azure",
375
+ "google-ai",
376
+ "huggingface",
377
+ "ollama",
378
+ "mistral",
379
+ ],
380
+ default: "auto",
381
+ description: "AI provider to use",
382
+ })
383
+ .option("temperature", {
384
+ type: "number",
385
+ default: 0.7,
386
+ description: "Creativity level",
387
+ })
388
+ .option("debug", {
389
+ type: "boolean",
390
+ default: false,
391
+ description: "Enable debug mode with interleaved logging",
392
+ })
393
+ .example('$0 stream "Tell me a story"', "Stream a story in real-time"), async (argv) => {
313
394
  // Default mode: Simple streaming message
314
395
  // Debug mode: More detailed information
315
396
  if (!argv.quiet && !argv.debug) {
316
- console.log(chalk.blue('🔄 Streaming...'));
397
+ console.log(chalk.blue("🔄 Streaming..."));
317
398
  }
318
399
  else if (!argv.quiet && argv.debug) {
319
400
  console.log(chalk.blue(`🔄 Streaming from ${argv.provider} provider with debug logging...\n`));
@@ -321,271 +402,449 @@ const cli = yargs(args)
321
402
  try {
322
403
  const stream = await sdk.generateTextStream({
323
404
  prompt: argv.prompt,
324
- provider: argv.provider === 'auto' ? undefined : argv.provider,
325
- temperature: argv.temperature
405
+ provider: argv.provider === "auto"
406
+ ? undefined
407
+ : argv.provider,
408
+ temperature: argv.temperature,
326
409
  });
327
410
  for await (const chunk of stream) {
328
411
  process.stdout.write(chunk.content);
329
412
  // In debug mode, interleaved logging would appear here
330
413
  // (SDK logs are controlled by NEUROLINK_DEBUG set in middleware)
331
414
  }
332
- if (!argv.quiet)
333
- process.stdout.write('\n'); // Ensure newline after stream
415
+ if (!argv.quiet) {
416
+ process.stdout.write("\n");
417
+ } // Ensure newline after stream
334
418
  }
335
419
  catch (error) {
336
- handleError(error, 'Text streaming');
420
+ handleError(error, "Text streaming");
337
421
  }
338
422
  })
339
423
  // Batch Processing Command
340
- .command('batch <file>', 'Process multiple prompts from a file', (yargsInstance) => yargsInstance
341
- .usage('Usage: $0 batch <file> [options]')
342
- .positional('file', { type: 'string', description: 'File with prompts (one per line)', demandOption: true })
343
- .option('output', { type: 'string', description: 'Output file for results (default: stdout)' })
344
- .option('delay', { type: 'number', default: 1000, description: 'Delay between requests in milliseconds' })
345
- .option('provider', { choices: ['auto', 'openai', 'bedrock', 'vertex', 'anthropic', 'azure', 'google-ai'], default: 'auto', description: 'AI provider to use' })
346
- .option('timeout', { type: 'number', default: 30000, description: 'Timeout for each request in milliseconds' })
347
- .option('temperature', { type: 'number', description: 'Global temperature for batch jobs' })
348
- .option('max-tokens', { type: 'number', description: 'Global max tokens for batch jobs' })
349
- .option('system', { type: 'string', description: 'Global system prompt for batch jobs' })
350
- .option('debug', { type: 'boolean', default: false, description: 'Enable debug mode with detailed per-item logging' })
351
- .example('$0 batch prompts.txt --output results.json', 'Process and save to file'), async (argv) => {
424
+ .command("batch <file>", "Process multiple prompts from a file", (yargsInstance) => yargsInstance
425
+ .usage("Usage: $0 batch <file> [options]")
426
+ .positional("file", {
427
+ type: "string",
428
+ description: "File with prompts (one per line)",
429
+ demandOption: true,
430
+ })
431
+ .option("output", {
432
+ type: "string",
433
+ description: "Output file for results (default: stdout)",
434
+ })
435
+ .option("delay", {
436
+ type: "number",
437
+ default: 1000,
438
+ description: "Delay between requests in milliseconds",
439
+ })
440
+ .option("provider", {
441
+ choices: [
442
+ "auto",
443
+ "openai",
444
+ "bedrock",
445
+ "vertex",
446
+ "anthropic",
447
+ "azure",
448
+ "google-ai",
449
+ "huggingface",
450
+ "ollama",
451
+ "mistral",
452
+ ],
453
+ default: "auto",
454
+ description: "AI provider to use",
455
+ })
456
+ .option("timeout", {
457
+ type: "number",
458
+ default: 30000,
459
+ description: "Timeout for each request in milliseconds",
460
+ })
461
+ .option("temperature", {
462
+ type: "number",
463
+ description: "Global temperature for batch jobs",
464
+ })
465
+ .option("max-tokens", {
466
+ type: "number",
467
+ description: "Global max tokens for batch jobs",
468
+ })
469
+ .option("system", {
470
+ type: "string",
471
+ description: "Global system prompt for batch jobs",
472
+ })
473
+ .option("debug", {
474
+ type: "boolean",
475
+ default: false,
476
+ description: "Enable debug mode with detailed per-item logging",
477
+ })
478
+ .example("$0 batch prompts.txt --output results.json", "Process and save to file"), async (argv) => {
352
479
  const spinner = argv.quiet ? null : ora().start();
353
480
  try {
354
- if (!fs.existsSync(argv.file))
481
+ if (!fs.existsSync(argv.file)) {
355
482
  throw new Error(`File not found: ${argv.file}`);
483
+ }
356
484
  const buffer = fs.readFileSync(argv.file);
357
485
  const isLikelyBinary = buffer.includes(0) ||
358
- buffer.toString('hex', 0, 100).includes('0000') ||
359
- (!buffer.toString('utf8', 0, 1024).includes('\n') && buffer.length > 512);
360
- if (isLikelyBinary)
486
+ buffer.toString("hex", 0, 100).includes("0000") ||
487
+ (!buffer.toString("utf8", 0, 1024).includes("\n") &&
488
+ buffer.length > 512);
489
+ if (isLikelyBinary) {
361
490
  throw new Error(`Invalid file format: Binary file detected at "${argv.file}". Batch processing requires a plain text file.`);
362
- const prompts = buffer.toString('utf8').split('\n').map(line => line.trim()).filter(Boolean);
363
- if (prompts.length === 0)
364
- throw new Error('No prompts found in file');
365
- if (spinner)
491
+ }
492
+ const prompts = buffer
493
+ .toString("utf8")
494
+ .split("\n")
495
+ .map((line) => line.trim())
496
+ .filter(Boolean);
497
+ if (prompts.length === 0) {
498
+ throw new Error("No prompts found in file");
499
+ }
500
+ if (spinner) {
366
501
  spinner.text = `📦 Processing ${prompts.length} prompts...`;
367
- else if (!argv.quiet)
502
+ }
503
+ else if (!argv.quiet) {
368
504
  console.log(chalk.blue(`📦 Processing ${prompts.length} prompts...\n`));
505
+ }
369
506
  const results = [];
370
507
  for (let i = 0; i < prompts.length; i++) {
371
- if (spinner)
508
+ if (spinner) {
372
509
  spinner.text = `Processing ${i + 1}/${prompts.length}: ${prompts[i].substring(0, 30)}...`;
510
+ }
373
511
  try {
374
- const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('Request timeout')), argv.timeout));
512
+ const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error("Request timeout")), argv.timeout));
375
513
  const generatePromise = sdk.generateText({
376
514
  prompt: prompts[i],
377
- provider: argv.provider === 'auto' ? undefined : argv.provider,
378
- temperature: argv.temperature, maxTokens: argv.maxTokens, systemPrompt: argv.system
515
+ provider: argv.provider === "auto"
516
+ ? undefined
517
+ : argv.provider,
518
+ temperature: argv.temperature,
519
+ maxTokens: argv.maxTokens,
520
+ systemPrompt: argv.system,
379
521
  });
380
- const result = await Promise.race([generatePromise, timeoutPromise]);
522
+ const result = (await Promise.race([
523
+ generatePromise,
524
+ timeoutPromise,
525
+ ]));
381
526
  results.push({ prompt: prompts[i], response: result.content });
382
- if (spinner)
383
- spinner.render(); // Update spinner without changing text
527
+ if (spinner) {
528
+ spinner.render();
529
+ } // Update spinner without changing text
384
530
  }
385
531
  catch (error) {
386
- results.push({ prompt: prompts[i], error: error.message });
387
- if (spinner)
532
+ results.push({
533
+ prompt: prompts[i],
534
+ error: error.message,
535
+ });
536
+ if (spinner) {
388
537
  spinner.render();
538
+ }
389
539
  }
390
- if (argv.delay && i < prompts.length - 1)
391
- await new Promise(resolve => setTimeout(resolve, argv.delay));
540
+ if (argv.delay && i < prompts.length - 1) {
541
+ await new Promise((resolve) => setTimeout(resolve, argv.delay));
542
+ }
543
+ }
544
+ if (spinner) {
545
+ spinner.succeed(chalk.green("✅ Batch processing complete!"));
392
546
  }
393
- if (spinner)
394
- spinner.succeed(chalk.green('✅ Batch processing complete!'));
395
547
  const outputData = JSON.stringify(results, null, 2);
396
548
  if (argv.output) {
397
549
  fs.writeFileSync(argv.output, outputData);
398
- if (!argv.quiet)
550
+ if (!argv.quiet) {
399
551
  console.log(chalk.green(`\n✅ Results saved to ${argv.output}`));
552
+ }
400
553
  }
401
554
  else {
402
- process.stdout.write(outputData + '\n');
555
+ process.stdout.write(outputData + "\n");
403
556
  }
404
557
  }
405
558
  catch (error) {
406
- if (spinner)
559
+ if (spinner) {
407
560
  spinner.fail();
408
- handleError(error, 'Batch processing');
561
+ }
562
+ handleError(error, "Batch processing");
409
563
  }
410
564
  })
411
565
  // Provider Command Group (Corrected Structure)
412
- .command('provider <subcommand>', 'Manage AI provider configurations and status', (yargsProvider) => {
566
+ .command("provider <subcommand>", "Manage AI provider configurations and status", (yargsProvider) => {
567
+ // Builder for the main 'provider' command
413
568
  yargsProvider
414
- .usage('Usage: $0 provider <subcommand> [options]') // Add usage here
415
- .command('status', 'Check status of all configured AI providers', (y) => y
416
- .usage('Usage: $0 provider status [options]')
417
- .option('verbose', { type: 'boolean', alias: 'v', description: 'Show detailed information' }) // Default is handled by middleware if NEUROLINK_DEBUG is set
418
- .example('$0 provider status', 'Check all providers')
419
- .example('$0 provider status --verbose', 'Show detailed status information'), async (argv) => {
569
+ .usage("Usage: $0 provider <subcommand> [options]") // Add usage here
570
+ .command("status", "Check status of all configured AI providers", (y) => y
571
+ .usage("Usage: $0 provider status [options]")
572
+ .option("verbose", {
573
+ type: "boolean",
574
+ alias: "v",
575
+ description: "Show detailed information",
576
+ }) // Default is handled by middleware if NEUROLINK_DEBUG is set
577
+ .example("$0 provider status", "Check all providers")
578
+ .example("$0 provider status --verbose", "Show detailed status information"), async (argv) => {
420
579
  if (argv.verbose && !argv.quiet) {
421
- console.log(chalk.yellow('ℹ️ Verbose mode enabled. Displaying detailed status.\n')); // Added newline
580
+ console.log(chalk.yellow("ℹ️ Verbose mode enabled. Displaying detailed status.\n")); // Added newline
422
581
  }
423
- const spinner = argv.quiet ? null : ora('🔍 Checking AI provider status...\n').start();
582
+ const spinner = argv.quiet
583
+ ? null
584
+ : ora("🔍 Checking AI provider status...\n").start();
424
585
  // Middleware sets argv.verbose if NEUROLINK_DEBUG is true and --verbose is not specified
425
586
  // Removed the spinner.stopAndPersist logic from here as it's handled before spinner start
426
- const providers = ['openai', 'bedrock', 'vertex', 'anthropic', 'azure', 'google-ai'];
587
+ const providers = [
588
+ "openai",
589
+ "bedrock",
590
+ "vertex",
591
+ "anthropic",
592
+ "azure",
593
+ "google-ai",
594
+ "huggingface",
595
+ "ollama",
596
+ "mistral",
597
+ ];
427
598
  const results = [];
428
599
  for (const p of providers) {
429
- if (spinner)
600
+ if (spinner) {
430
601
  spinner.text = `Testing ${p}...`;
602
+ }
431
603
  try {
432
604
  const start = Date.now();
433
- await sdk.generateText({ prompt: 'test', provider: p, maxTokens: 1 });
605
+ await sdk.generateText({
606
+ prompt: "test",
607
+ provider: p,
608
+ maxTokens: 1,
609
+ });
434
610
  const duration = Date.now() - start;
435
- results.push({ provider: p, status: 'working', responseTime: duration });
436
- if (spinner)
437
- spinner.succeed(`${p}: ${chalk.green('✅ Working')} (${duration}ms)`);
438
- else if (!argv.quiet)
439
- console.log(`${p}: ${chalk.green('✅ Working')} (${duration}ms)`);
611
+ results.push({
612
+ provider: p,
613
+ status: "working",
614
+ responseTime: duration,
615
+ });
616
+ if (spinner) {
617
+ spinner.succeed(`${p}: ${chalk.green("✅ Working")} (${duration}ms)`);
618
+ }
619
+ else if (!argv.quiet) {
620
+ console.log(`${p}: ${chalk.green("✅ Working")} (${duration}ms)`);
621
+ }
440
622
  }
441
623
  catch (error) {
442
- results.push({ provider: p, status: 'failed', error: error.message });
443
- if (spinner)
444
- spinner.fail(`${p}: ${chalk.red('❌ Failed')} - ${error.message.split('\n')[0]}`);
445
- else if (!argv.quiet)
446
- console.error(`${p}: ${chalk.red('❌ Failed')} - ${error.message.split('\n')[0]}`);
624
+ results.push({
625
+ provider: p,
626
+ status: "failed",
627
+ error: error.message,
628
+ });
629
+ if (spinner) {
630
+ spinner.fail(`${p}: ${chalk.red("❌ Failed")} - ${error.message.split("\n")[0]}`);
631
+ }
632
+ else if (!argv.quiet) {
633
+ console.error(`${p}: ${chalk.red("❌ Failed")} - ${error.message.split("\n")[0]}`);
634
+ }
447
635
  }
448
636
  }
449
- const working = results.filter(r => r.status === 'working').length;
450
- if (spinner)
637
+ const working = results.filter((r) => r.status === "working").length;
638
+ if (spinner) {
451
639
  spinner.info(chalk.blue(`\n📊 Summary: ${working}/${results.length} providers working`));
452
- else if (!argv.quiet)
640
+ }
641
+ else if (!argv.quiet) {
453
642
  console.log(chalk.blue(`\n📊 Summary: ${working}/${results.length} providers working`));
643
+ }
454
644
  if (argv.verbose && !argv.quiet) {
455
- console.log(chalk.blue('\n📋 Detailed Results:'));
645
+ console.log(chalk.blue("\n📋 Detailed Results:"));
456
646
  console.log(JSON.stringify(results, null, 2));
457
647
  }
458
648
  })
459
- .command('list', 'List available AI providers', (y) => y.usage('Usage: $0 provider list'), async () => {
460
- console.log('Available providers: openai, bedrock, vertex, anthropic, azure, google-ai');
649
+ .command("list", "List available AI providers", (y) => y.usage("Usage: $0 provider list"), async () => {
650
+ console.log("Available providers: openai, bedrock, vertex, anthropic, azure, google-ai, huggingface, ollama, mistral");
461
651
  })
462
- .command('configure <providerName>', 'Display configuration guidance for a provider', (y) => y
463
- .usage('Usage: $0 provider configure <providerName>')
464
- .positional('providerName', {
465
- type: 'string',
466
- choices: ['openai', 'bedrock', 'vertex', 'anthropic', 'azure', 'google-ai'],
467
- description: 'Name of the provider to configure',
652
+ .command("configure <providerName>", "Display configuration guidance for a provider", (y) => y
653
+ .usage("Usage: $0 provider configure <providerName>")
654
+ .positional("providerName", {
655
+ type: "string",
656
+ choices: [
657
+ "openai",
658
+ "bedrock",
659
+ "vertex",
660
+ "anthropic",
661
+ "azure",
662
+ "google-ai",
663
+ "huggingface",
664
+ "ollama",
665
+ "mistral",
666
+ ],
667
+ description: "Name of the provider to configure",
468
668
  demandOption: true,
469
669
  })
470
- .example('$0 provider configure openai', 'Show OpenAI configuration help'), async (argv) => {
670
+ .example("$0 provider configure openai", "Show OpenAI configuration help"), async (argv) => {
471
671
  console.log(chalk.blue(`\n🔧 Configuration guidance for ${chalk.bold(argv.providerName)}:`));
472
- console.log(chalk.yellow('💡 Set relevant environment variables for API keys and other settings.'));
473
- console.log(chalk.gray(' Refer to the documentation for details: https://github.com/juspay/neurolink#configuration'));
672
+ console.log(chalk.yellow("💡 Set relevant environment variables for API keys and other settings."));
673
+ console.log(chalk.gray(" Refer to the documentation for details: https://github.com/juspay/neurolink#configuration"));
474
674
  })
475
- .demandCommand(1, 'Please specify a provider subcommand (status, list, or configure).');
476
- }
477
- // Base handler for 'provider' removed.
478
- // If no subcommand is provided, yargsProvider.demandCommand should trigger an error,
479
- // which will be caught by the main .fail() handler.
480
- )
675
+ .demandCommand(1, "Please specify a provider subcommand (status, list, or configure).");
676
+ })
481
677
  // Status Command (Standalone, for backward compatibility or direct access)
482
- .command('status', 'Check AI provider connectivity and performance (alias for provider status)', (yargsInstance) => yargsInstance
483
- .usage('Usage: $0 status [options]')
484
- .option('verbose', {
485
- type: 'boolean',
486
- alias: 'v', // Default is handled by middleware if NEUROLINK_DEBUG is set
487
- description: 'Show detailed information'
488
- })
489
- .example('$0 status', 'Check all providers')
490
- .example('$0 status --verbose', 'Show detailed status information'), async (argv) => {
678
+ .command("status", "Check AI provider connectivity and performance (alias for provider status)", (yargsInstance) => yargsInstance
679
+ .usage("Usage: $0 status [options]")
680
+ .option("verbose", {
681
+ // Ensure status alias also defines verbose
682
+ type: "boolean",
683
+ alias: "v", // Default is handled by middleware if NEUROLINK_DEBUG is set
684
+ description: "Show detailed information",
685
+ })
686
+ .example("$0 status", "Check all providers")
687
+ .example("$0 status --verbose", "Show detailed status information"), async (argv) => {
491
688
  // This logic is duplicated from 'provider status' for the alias
492
689
  if (argv.verbose && !argv.quiet) {
493
- console.log(chalk.yellow('ℹ️ Verbose mode enabled. Displaying detailed status.\n')); // Added newline
690
+ console.log(chalk.yellow("ℹ️ Verbose mode enabled. Displaying detailed status.\n")); // Added newline
494
691
  }
495
- const spinner = argv.quiet ? null : ora('🔍 Checking AI provider status...\n').start();
692
+ const spinner = argv.quiet
693
+ ? null
694
+ : ora("🔍 Checking AI provider status...\n").start();
496
695
  // Middleware sets argv.verbose if NEUROLINK_DEBUG is true and --verbose is not specified
497
696
  // Removed the spinner.stopAndPersist logic from here as it's handled before spinner start
498
- const providers = ['openai', 'bedrock', 'vertex', 'anthropic', 'azure', 'google-ai'];
697
+ const providers = [
698
+ "openai",
699
+ "bedrock",
700
+ "vertex",
701
+ "anthropic",
702
+ "azure",
703
+ "google-ai",
704
+ "huggingface",
705
+ "ollama",
706
+ "mistral",
707
+ ];
499
708
  const results = [];
500
709
  for (const p of providers) {
501
- if (spinner)
710
+ if (spinner) {
502
711
  spinner.text = `Testing ${p}...`;
712
+ }
503
713
  try {
504
714
  const start = Date.now();
505
- await sdk.generateText({ prompt: 'test', provider: p, maxTokens: 1 });
715
+ await sdk.generateText({ prompt: "test", provider: p, maxTokens: 1 });
506
716
  const duration = Date.now() - start;
507
- results.push({ provider: p, status: 'working', responseTime: duration });
508
- if (spinner)
509
- spinner.succeed(`${p}: ${chalk.green('✅ Working')} (${duration}ms)`);
510
- else if (!argv.quiet)
511
- console.log(`${p}: ${chalk.green('✅ Working')} (${duration}ms)`);
717
+ results.push({
718
+ provider: p,
719
+ status: "working",
720
+ responseTime: duration,
721
+ });
722
+ if (spinner) {
723
+ spinner.succeed(`${p}: ${chalk.green("✅ Working")} (${duration}ms)`);
724
+ }
725
+ else if (!argv.quiet) {
726
+ console.log(`${p}: ${chalk.green("✅ Working")} (${duration}ms)`);
727
+ }
512
728
  }
513
729
  catch (error) {
514
- results.push({ provider: p, status: 'failed', error: error.message });
515
- if (spinner)
516
- spinner.fail(`${p}: ${chalk.red('❌ Failed')} - ${error.message.split('\n')[0]}`);
517
- else if (!argv.quiet)
518
- console.error(`${p}: ${chalk.red('❌ Failed')} - ${error.message.split('\n')[0]}`);
730
+ results.push({
731
+ provider: p,
732
+ status: "failed",
733
+ error: error.message,
734
+ });
735
+ if (spinner) {
736
+ spinner.fail(`${p}: ${chalk.red("❌ Failed")} - ${error.message.split("\n")[0]}`);
737
+ }
738
+ else if (!argv.quiet) {
739
+ console.error(`${p}: ${chalk.red("❌ Failed")} - ${error.message.split("\n")[0]}`);
740
+ }
519
741
  }
520
742
  }
521
- const working = results.filter(r => r.status === 'working').length;
522
- if (spinner)
743
+ const working = results.filter((r) => r.status === "working").length;
744
+ if (spinner) {
523
745
  spinner.info(chalk.blue(`\n📊 Summary: ${working}/${results.length} providers working`));
524
- else if (!argv.quiet)
746
+ }
747
+ else if (!argv.quiet) {
525
748
  console.log(chalk.blue(`\n📊 Summary: ${working}/${results.length} providers working`));
749
+ }
526
750
  if (argv.verbose && !argv.quiet) {
527
- console.log(chalk.blue('\n📋 Detailed Results:'));
751
+ console.log(chalk.blue("\n📋 Detailed Results:"));
528
752
  console.log(JSON.stringify(results, null, 2));
529
753
  }
530
754
  })
531
755
  // Configuration Commands Refactored
532
- .command('config <subcommand>', 'Manage NeuroLink configuration', (yargsConfig) => {
756
+ .command("config <subcommand>", "Manage NeuroLink configuration", (yargsConfig) => {
533
757
  yargsConfig
534
- .usage('Usage: $0 config <subcommand> [options]') // Add usage here
535
- .command('setup', 'Interactive setup for NeuroLink configuration', () => { }, // No specific builder options for setup
536
- async (argv) => {
537
- console.log('Config setup: Use interactive prompts. Error: Invalid input, please try again with valid provider names.');
758
+ .usage("Usage: $0 config <subcommand> [options]") // Add usage here
759
+ .command("setup", "Interactive setup for NeuroLink configuration", (y) => y
760
+ .usage("Usage: $0 config setup [options]")
761
+ .option("quiet", {
762
+ type: "boolean",
763
+ alias: "q",
764
+ description: "Suppress progress messages and interactive prompts",
538
765
  })
539
- .command('init', 'Alias for setup: Interactive setup for NeuroLink configuration', () => { }, async (argv) => {
540
- console.log('Config init (setup): Use interactive prompts. Error: Invalid input, please try again with valid provider names.');
766
+ .example("$0 config setup", "Run interactive setup wizard")
767
+ .example("$0 config setup --quiet", "Run setup with minimal output"), async (argv) => {
768
+ const { configSetup } = await import("./utils/complete-setup.js");
769
+ await configSetup(argv.quiet);
541
770
  })
542
- .command('show', 'Show current NeuroLink configuration', () => { }, async (argv) => {
543
- console.log('Config show: Displaying current configuration...');
771
+ .command("init", "Alias for setup: Interactive setup for NeuroLink configuration", (y) => y
772
+ .usage("Usage: $0 config init [options]")
773
+ .option("quiet", {
774
+ type: "boolean",
775
+ alias: "q",
776
+ description: "Suppress progress messages and interactive prompts",
777
+ })
778
+ .example("$0 config init", "Run interactive setup wizard (alias for setup)")
779
+ .example("$0 config init --quiet", "Run setup with minimal output"), async (argv) => {
780
+ const { configInit } = await import("./utils/complete-setup.js");
781
+ await configInit(argv.quiet);
782
+ })
783
+ .command("show", "Show current NeuroLink configuration", () => { }, async (argv) => {
784
+ console.log("Config show: Displaying current configuration...");
544
785
  // Actual show logic here
545
786
  })
546
- .command('set <key> <value>', 'Set a configuration key-value pair', (y) => y
547
- .positional('key', { type: 'string', description: 'Configuration key to set', demandOption: true })
548
- .positional('value', { type: 'string', description: 'Value to set for the key', demandOption: true }), async (argv) => {
787
+ .command("set <key> <value>", "Set a configuration key-value pair", (y) => y
788
+ .positional("key", {
789
+ type: "string",
790
+ description: "Configuration key to set",
791
+ demandOption: true,
792
+ })
793
+ .positional("value", {
794
+ type: "string",
795
+ description: "Value to set for the key",
796
+ demandOption: true,
797
+ }), async (argv) => {
549
798
  console.log(`Config set: Key: ${argv.key}, Value: ${argv.value}`);
550
799
  // Actual set logic here
551
800
  })
552
- .command('import <file>', 'Import configuration from a file', (y) => y.positional('file', { type: 'string', description: 'File path to import from', demandOption: true }), async (argv) => {
801
+ .command("import <file>", "Import configuration from a file", (y) => y.positional("file", {
802
+ type: "string",
803
+ description: "File path to import from",
804
+ demandOption: true,
805
+ }), async (argv) => {
553
806
  console.log(`Config import: Importing from ${argv.file}`);
554
- if (argv.file.includes('invalid-config.json')) {
555
- handleError(new Error('Invalid or unparseable JSON in config file.'), 'Config import');
807
+ if (argv.file.includes("invalid-config.json")) {
808
+ handleError(new Error("Invalid or unparseable JSON in config file."), "Config import");
556
809
  }
557
810
  // Actual import logic here
558
811
  })
559
- .command('export <file>', 'Export current configuration to a file', (y) => y.positional('file', { type: 'string', description: 'File path to export to', demandOption: true }), async (argv) => {
812
+ .command("export <file>", "Export current configuration to a file", (y) => y.positional("file", {
813
+ type: "string",
814
+ description: "File path to export to",
815
+ demandOption: true,
816
+ }), async (argv) => {
560
817
  console.log(`Config export: Exporting to ${argv.file}`);
561
- if (argv.file.includes('read-only-dir')) {
562
- handleError(new Error('Permission denied. Cannot write to read-only directory.'), 'Config export');
818
+ if (argv.file.includes("read-only-dir")) {
819
+ handleError(new Error("Permission denied. Cannot write to read-only directory."), "Config export");
563
820
  }
564
821
  // Actual export logic here
565
822
  })
566
- .command('validate', 'Validate the current configuration', () => { }, async (argv) => {
567
- console.log('Config validate: Validating configuration...');
823
+ .command("validate", "Validate the current configuration", () => { }, async (argv) => {
824
+ console.log("Config validate: Validating configuration...");
568
825
  // Actual validation logic here
569
826
  })
570
- .command('reset', 'Reset NeuroLink configuration to defaults', () => { }, async (argv) => {
571
- console.log('Config reset: Resetting configuration...');
827
+ .command("reset", "Reset NeuroLink configuration to defaults", () => { }, async (argv) => {
828
+ console.log("Config reset: Resetting configuration...");
572
829
  // Actual reset logic here
573
830
  })
574
- .demandCommand(1, 'Please specify a config subcommand (e.g., setup, show, set).')
575
- .example('$0 config setup', 'Run interactive setup')
576
- .example('$0 config set provider openai', 'Set default provider (using key/value)');
577
- }
578
- // Base handler for 'config' removed.
579
- // If no subcommand is provided, yargsConfig.demandCommand should trigger an error,
580
- // which will be caught by the main .fail() handler.
581
- )
831
+ .demandCommand(1, "Please specify a config subcommand (e.g., setup, show, set).")
832
+ .example("$0 config setup", "Run interactive setup")
833
+ .example("$0 config set provider openai", "Set default provider (using key/value)");
834
+ })
582
835
  // Get Best Provider Command
583
- .command('get-best-provider', 'Show the best available AI provider', (yargsInstance) => yargsInstance
584
- .usage('Usage: $0 get-best-provider [options]')
585
- .option('debug', { type: 'boolean', default: false, description: 'Enable debug mode with selection reasoning' })
586
- .example('$0 get-best-provider', 'Get best provider')
587
- .example('$0 get-best-provider --debug', 'Show selection logic'), async (argv) => {
588
- const spinner = argv.quiet ? null : ora('🎯 Finding best provider...').start();
836
+ .command("get-best-provider", "Show the best available AI provider", (yargsInstance) => yargsInstance
837
+ .usage("Usage: $0 get-best-provider [options]")
838
+ .option("debug", {
839
+ type: "boolean",
840
+ default: false,
841
+ description: "Enable debug mode with selection reasoning",
842
+ })
843
+ .example("$0 get-best-provider", "Get best provider")
844
+ .example("$0 get-best-provider --debug", "Show selection logic"), async (argv) => {
845
+ const spinner = argv.quiet
846
+ ? null
847
+ : ora("🎯 Finding best provider...").start();
589
848
  try {
590
849
  const provider = await sdk.getBestProvider();
591
850
  if (spinner) {
@@ -593,7 +852,7 @@ const cli = yargs(args)
593
852
  spinner.succeed(chalk.green(`✅ Best provider selected: ${provider}`));
594
853
  }
595
854
  else {
596
- spinner.succeed(chalk.green('✅ Provider found'));
855
+ spinner.succeed(chalk.green("✅ Provider found"));
597
856
  }
598
857
  }
599
858
  if (argv.debug) {
@@ -607,14 +866,19 @@ const cli = yargs(args)
607
866
  }
608
867
  }
609
868
  catch (error) {
610
- if (spinner && spinner.isSpinning)
869
+ if (spinner && spinner.isSpinning) {
611
870
  spinner.fail();
612
- handleError(error, 'Provider selection');
871
+ }
872
+ handleError(error, "Provider selection");
613
873
  }
614
874
  })
615
- .completion('completion', 'Generate shell completion script');
875
+ .completion("completion", "Generate shell completion script");
616
876
  // Add MCP commands
617
877
  addMCPCommands(cli);
878
+ // Add Ollama command
879
+ cli.command(ollamaCommand);
880
+ // Add Agent-Generate command
881
+ cli.command(agentGenerateCommand);
618
882
  // Use an async IIFE to allow top-level await for parseAsync
619
883
  (async () => {
620
884
  try {