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