@juspay/neurolink 1.9.0 → 1.11.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 (156) hide show
  1. package/CHANGELOG.md +41 -31
  2. package/README.md +17 -1
  3. package/dist/agent/direct-tools.d.ts +9 -9
  4. package/dist/cli/commands/agent-generate.d.ts +1 -2
  5. package/dist/cli/commands/agent-generate.js +5 -8
  6. package/dist/cli/commands/config.d.ts +2 -2
  7. package/dist/cli/commands/config.js +1 -1
  8. package/dist/cli/commands/mcp.js +91 -100
  9. package/dist/cli/commands/ollama.d.ts +2 -7
  10. package/dist/cli/commands/ollama.js +5 -8
  11. package/dist/cli/index.js +263 -258
  12. package/dist/core/factory.js +11 -12
  13. package/dist/index.d.ts +24 -1
  14. package/dist/index.js +36 -1
  15. package/dist/lib/agent/direct-tools.d.ts +9 -9
  16. package/dist/lib/core/factory.js +11 -12
  17. package/dist/lib/index.d.ts +24 -1
  18. package/dist/lib/index.js +36 -1
  19. package/dist/lib/mcp/adapters/plugin-bridge.d.ts +39 -0
  20. package/dist/lib/mcp/adapters/plugin-bridge.js +82 -0
  21. package/dist/lib/mcp/auto-discovery.d.ts +38 -96
  22. package/dist/lib/mcp/auto-discovery.js +100 -744
  23. package/dist/lib/mcp/client.js +4 -4
  24. package/dist/lib/mcp/context-manager.js +72 -1
  25. package/dist/lib/mcp/contracts/mcp-contract.d.ts +162 -0
  26. package/dist/lib/mcp/contracts/mcp-contract.js +58 -0
  27. package/dist/lib/mcp/core/plugin-manager.d.ts +45 -0
  28. package/dist/lib/mcp/core/plugin-manager.js +110 -0
  29. package/dist/lib/mcp/demo/plugin-demo.d.ts +20 -0
  30. package/dist/lib/mcp/demo/plugin-demo.js +116 -0
  31. package/dist/lib/mcp/ecosystem.d.ts +75 -0
  32. package/dist/lib/mcp/ecosystem.js +161 -0
  33. package/dist/lib/mcp/external-client.d.ts +88 -0
  34. package/dist/lib/mcp/external-client.js +323 -0
  35. package/dist/lib/mcp/external-manager.d.ts +112 -0
  36. package/dist/lib/mcp/external-manager.js +302 -0
  37. package/dist/lib/mcp/factory.d.ts +4 -4
  38. package/dist/lib/mcp/function-calling.js +59 -34
  39. package/dist/lib/mcp/index.d.ts +39 -184
  40. package/dist/lib/mcp/index.js +72 -150
  41. package/dist/lib/mcp/initialize.js +5 -5
  42. package/dist/lib/mcp/logging.d.ts +27 -60
  43. package/dist/lib/mcp/logging.js +77 -165
  44. package/dist/lib/mcp/neurolink-mcp-client.js +31 -3
  45. package/dist/lib/mcp/orchestrator.d.ts +1 -1
  46. package/dist/lib/mcp/orchestrator.js +13 -12
  47. package/dist/lib/mcp/plugin-manager.d.ts +98 -0
  48. package/dist/lib/mcp/plugin-manager.js +294 -0
  49. package/dist/lib/mcp/plugins/core/filesystem-mcp.d.ts +35 -0
  50. package/dist/lib/mcp/plugins/core/filesystem-mcp.js +139 -0
  51. package/dist/lib/mcp/plugins/filesystem-mcp.d.ts +36 -0
  52. package/dist/lib/mcp/plugins/filesystem-mcp.js +54 -0
  53. package/dist/lib/mcp/registry.d.ts +26 -167
  54. package/dist/lib/mcp/registry.js +31 -354
  55. package/dist/lib/mcp/security-manager.d.ts +85 -0
  56. package/dist/lib/mcp/security-manager.js +344 -0
  57. package/dist/lib/mcp/servers/ai-providers/ai-analysis-tools.js +1 -1
  58. package/dist/lib/mcp/servers/ai-providers/ai-core-server.js +1 -1
  59. package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.d.ts +2 -2
  60. package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.js +1 -1
  61. package/dist/lib/mcp/tool-integration.d.ts +4 -14
  62. package/dist/lib/mcp/tool-integration.js +43 -21
  63. package/dist/lib/mcp/tool-registry.d.ts +66 -0
  64. package/dist/lib/mcp/tool-registry.js +160 -0
  65. package/dist/lib/mcp/unified-mcp.d.ts +123 -0
  66. package/dist/lib/mcp/unified-mcp.js +246 -0
  67. package/dist/lib/mcp/unified-registry.d.ts +42 -229
  68. package/dist/lib/mcp/unified-registry.js +96 -1346
  69. package/dist/lib/neurolink.d.ts +3 -4
  70. package/dist/lib/neurolink.js +18 -19
  71. package/dist/lib/providers/agent-enhanced-provider.js +2 -2
  72. package/dist/lib/providers/amazonBedrock.js +2 -2
  73. package/dist/lib/providers/anthropic.js +3 -3
  74. package/dist/lib/providers/azureOpenAI.js +3 -3
  75. package/dist/lib/providers/function-calling-provider.js +34 -25
  76. package/dist/lib/providers/googleAIStudio.js +3 -3
  77. package/dist/lib/providers/googleVertexAI.js +2 -2
  78. package/dist/lib/providers/huggingFace.js +2 -2
  79. package/dist/lib/providers/mcp-provider.js +33 -5
  80. package/dist/lib/providers/mistralAI.js +2 -2
  81. package/dist/lib/providers/ollama.js +17 -2
  82. package/dist/lib/providers/openAI.js +2 -2
  83. package/dist/lib/utils/providerUtils-fixed.d.ts +8 -0
  84. package/dist/lib/utils/providerUtils-fixed.js +75 -0
  85. package/dist/lib/utils/providerUtils.d.ts +8 -1
  86. package/dist/lib/utils/providerUtils.js +10 -1
  87. package/dist/mcp/adapters/plugin-bridge.d.ts +39 -0
  88. package/dist/mcp/adapters/plugin-bridge.js +82 -0
  89. package/dist/mcp/auto-discovery.d.ts +38 -96
  90. package/dist/mcp/auto-discovery.js +100 -745
  91. package/dist/mcp/client.js +4 -4
  92. package/dist/mcp/context-manager.js +72 -1
  93. package/dist/mcp/contracts/mcp-contract.d.ts +162 -0
  94. package/dist/mcp/contracts/mcp-contract.js +58 -0
  95. package/dist/mcp/core/plugin-manager.d.ts +45 -0
  96. package/dist/mcp/core/plugin-manager.js +110 -0
  97. package/dist/mcp/demo/plugin-demo.d.ts +20 -0
  98. package/dist/mcp/demo/plugin-demo.js +116 -0
  99. package/dist/mcp/ecosystem.d.ts +75 -0
  100. package/dist/mcp/ecosystem.js +162 -0
  101. package/dist/mcp/external-client.d.ts +88 -0
  102. package/dist/mcp/external-client.js +323 -0
  103. package/dist/mcp/external-manager.d.ts +112 -0
  104. package/dist/mcp/external-manager.js +302 -0
  105. package/dist/mcp/factory.d.ts +4 -4
  106. package/dist/mcp/function-calling.js +59 -34
  107. package/dist/mcp/index.d.ts +39 -184
  108. package/dist/mcp/index.js +72 -150
  109. package/dist/mcp/initialize.js +5 -5
  110. package/dist/mcp/logging.d.ts +27 -60
  111. package/dist/mcp/logging.js +77 -165
  112. package/dist/mcp/neurolink-mcp-client.js +31 -3
  113. package/dist/mcp/orchestrator.d.ts +1 -1
  114. package/dist/mcp/orchestrator.js +13 -12
  115. package/dist/mcp/plugin-manager.d.ts +98 -0
  116. package/dist/mcp/plugin-manager.js +295 -0
  117. package/dist/mcp/plugins/core/filesystem-mcp.d.ts +35 -0
  118. package/dist/mcp/plugins/core/filesystem-mcp.js +139 -0
  119. package/dist/mcp/plugins/core/neurolink-mcp.json +17 -0
  120. package/dist/mcp/plugins/filesystem-mcp.d.ts +36 -0
  121. package/dist/mcp/plugins/filesystem-mcp.js +54 -0
  122. package/dist/mcp/registry.d.ts +26 -167
  123. package/dist/mcp/registry.js +31 -354
  124. package/dist/mcp/security-manager.d.ts +85 -0
  125. package/dist/mcp/security-manager.js +344 -0
  126. package/dist/mcp/servers/ai-providers/ai-analysis-tools.js +1 -1
  127. package/dist/mcp/servers/ai-providers/ai-core-server.js +1 -1
  128. package/dist/mcp/servers/ai-providers/ai-workflow-tools.d.ts +2 -2
  129. package/dist/mcp/servers/ai-providers/ai-workflow-tools.js +1 -1
  130. package/dist/mcp/tool-integration.d.ts +4 -14
  131. package/dist/mcp/tool-integration.js +43 -21
  132. package/dist/mcp/tool-registry.d.ts +66 -0
  133. package/dist/mcp/tool-registry.js +160 -0
  134. package/dist/mcp/unified-mcp.d.ts +123 -0
  135. package/dist/mcp/unified-mcp.js +246 -0
  136. package/dist/mcp/unified-registry.d.ts +42 -229
  137. package/dist/mcp/unified-registry.js +96 -1345
  138. package/dist/neurolink.d.ts +3 -4
  139. package/dist/neurolink.js +18 -19
  140. package/dist/providers/agent-enhanced-provider.js +2 -2
  141. package/dist/providers/amazonBedrock.js +2 -2
  142. package/dist/providers/anthropic.js +3 -3
  143. package/dist/providers/azureOpenAI.js +3 -3
  144. package/dist/providers/function-calling-provider.js +34 -25
  145. package/dist/providers/googleAIStudio.js +3 -3
  146. package/dist/providers/googleVertexAI.js +2 -2
  147. package/dist/providers/huggingFace.js +2 -2
  148. package/dist/providers/mcp-provider.js +33 -5
  149. package/dist/providers/mistralAI.js +2 -2
  150. package/dist/providers/ollama.js +17 -2
  151. package/dist/providers/openAI.js +2 -2
  152. package/dist/utils/providerUtils-fixed.d.ts +8 -0
  153. package/dist/utils/providerUtils-fixed.js +75 -0
  154. package/dist/utils/providerUtils.d.ts +8 -1
  155. package/dist/utils/providerUtils.js +10 -1
  156. package/package.json +28 -20
package/dist/cli/index.js CHANGED
@@ -13,8 +13,9 @@ import ora from "ora";
13
13
  import chalk from "chalk";
14
14
  import fs from "fs";
15
15
  import { addMCPCommands } from "./commands/mcp.js";
16
- import ollamaCommand from "./commands/ollama.js";
16
+ import { addOllamaCommands } from "./commands/ollama.js";
17
17
  import { agentGenerateCommand } from "./commands/agent-generate.js";
18
+ import { AgentEnhancedProvider } from "../lib/providers/agent-enhanced-provider.js";
18
19
  // Load environment variables from .env file
19
20
  try {
20
21
  // Try to import and configure dotenv
@@ -233,7 +234,7 @@ const cli = yargs(args)
233
234
  })
234
235
  .option("max-tokens", {
235
236
  type: "number",
236
- default: 500,
237
+ default: 1000,
237
238
  description: "Maximum tokens to generate",
238
239
  })
239
240
  .option("system", {
@@ -282,18 +283,41 @@ const cli = yargs(args)
282
283
  const timeoutPromise = new Promise((_, reject) => {
283
284
  setTimeout(() => reject(new Error(`Request timeout (${argv.timeout}ms)`)), argv.timeout);
284
285
  });
285
- // Use enhanced NeuroLink SDK with Lighthouse-style natural tool access
286
- const generatePromise = sdk.generateText({
287
- prompt: argv.prompt,
288
- provider: argv.provider === "auto"
289
- ? undefined
290
- : argv.provider,
291
- temperature: argv.temperature,
292
- maxTokens: argv.maxTokens,
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
296
- });
286
+ // Use AgentEnhancedProvider when tools are enabled, otherwise use standard SDK
287
+ let generatePromise;
288
+ if (argv.disableTools === true) {
289
+ // Tools disabled - use standard SDK
290
+ generatePromise = sdk.generateText({
291
+ prompt: argv.prompt,
292
+ provider: argv.provider === "auto"
293
+ ? undefined
294
+ : argv.provider,
295
+ temperature: argv.temperature,
296
+ maxTokens: argv.maxTokens,
297
+ systemPrompt: argv.system,
298
+ });
299
+ }
300
+ else {
301
+ // Tools enabled - use AgentEnhancedProvider for tool calling capabilities
302
+ // Map provider to supported AgentEnhancedProvider types
303
+ const supportedProvider = (() => {
304
+ switch (argv.provider) {
305
+ case "openai":
306
+ case "anthropic":
307
+ case "google-ai":
308
+ return argv.provider;
309
+ case "auto":
310
+ default:
311
+ return "google-ai"; // Default to google-ai for best tool support
312
+ }
313
+ })();
314
+ const agentProvider = new AgentEnhancedProvider({
315
+ provider: supportedProvider,
316
+ model: undefined, // Use default model for provider
317
+ toolCategory: "all", // Enable all tool categories
318
+ });
319
+ generatePromise = agentProvider.generateText(argv.prompt);
320
+ }
297
321
  const result = (await Promise.race([
298
322
  generatePromise,
299
323
  timeoutPromise,
@@ -304,37 +328,60 @@ const cli = yargs(args)
304
328
  if (spinner) {
305
329
  spinner.succeed(chalk.green("✅ Text generated successfully!"));
306
330
  }
331
+ // Handle both AgentEnhancedProvider (AI SDK) and standard NeuroLink SDK responses
332
+ const responseText = result.text || result.content || "";
333
+ const responseUsage = result.usage || {
334
+ promptTokens: 0,
335
+ completionTokens: 0,
336
+ totalTokens: 0,
337
+ };
307
338
  if (argv.format === "json") {
308
339
  const jsonOutput = {
309
- content: result.content || "",
310
- provider: result.provider,
311
- usage: result.usage || {
312
- promptTokens: 0,
313
- completionTokens: 0,
314
- totalTokens: 0,
315
- },
340
+ content: responseText,
341
+ provider: result.provider || argv.provider,
342
+ usage: responseUsage,
316
343
  responseTime: result.responseTime || 0,
344
+ toolCalls: result.toolCalls || [],
345
+ toolResults: result.toolResults || [],
317
346
  };
318
347
  process.stdout.write(JSON.stringify(jsonOutput, null, 2) + "\n");
319
348
  }
320
349
  else if (argv.debug) {
321
350
  // Debug mode: Show AI response + full metadata
322
- if (result.content) {
323
- console.log("\n" + result.content + "\n");
351
+ if (responseText) {
352
+ console.log("\n" + responseText + "\n");
353
+ }
354
+ // Show tool calls if any
355
+ if (result.toolCalls && result.toolCalls.length > 0) {
356
+ console.log(chalk.blue("🔧 Tools Called:"));
357
+ for (const toolCall of result.toolCalls) {
358
+ console.log(`- ${toolCall.toolName}`);
359
+ console.log(` Args: ${JSON.stringify(toolCall.args)}`);
360
+ }
361
+ console.log();
362
+ }
363
+ // Show tool results if any
364
+ if (result.toolResults && result.toolResults.length > 0) {
365
+ console.log(chalk.blue("📋 Tool Results:"));
366
+ for (const toolResult of result.toolResults) {
367
+ console.log(`- ${toolResult.toolCallId}`);
368
+ console.log(` Result: ${JSON.stringify(toolResult.result).substring(0, 200)}...`);
369
+ }
370
+ console.log();
324
371
  }
325
372
  console.log(JSON.stringify({
326
- provider: result.provider,
327
- usage: result.usage,
328
- responseTime: result.responseTime,
373
+ provider: result.provider || argv.provider,
374
+ usage: responseUsage,
375
+ responseTime: result.responseTime || 0,
329
376
  }, null, 2));
330
- if (result.usage) {
331
- console.log(chalk.blue(`ℹ️ ${result.usage.totalTokens} tokens used`));
377
+ if (responseUsage.totalTokens) {
378
+ console.log(chalk.blue(`ℹ️ ${responseUsage.totalTokens} tokens used`));
332
379
  }
333
380
  }
334
381
  else {
335
382
  // Default mode: Clean AI response only
336
- if (result.content) {
337
- console.log(result.content);
383
+ if (responseText) {
384
+ console.log(responseText);
338
385
  }
339
386
  }
340
387
  // Explicitly exit to prevent hanging, especially with Google AI Studio
@@ -582,8 +629,6 @@ const cli = yargs(args)
582
629
  const spinner = argv.quiet
583
630
  ? null
584
631
  : ora("🔍 Checking AI provider status...\n").start();
585
- // Middleware sets argv.verbose if NEUROLINK_DEBUG is true and --verbose is not specified
586
- // Removed the spinner.stopAndPersist logic from here as it's handled before spinner start
587
632
  const providers = [
588
633
  "openai",
589
634
  "bedrock",
@@ -595,22 +640,105 @@ const cli = yargs(args)
595
640
  "ollama",
596
641
  "mistral",
597
642
  ];
643
+ // Import hasProviderEnvVars to check environment variables
644
+ const { hasProviderEnvVars } = await import("../lib/utils/providerUtils.js");
598
645
  const results = [];
599
646
  for (const p of providers) {
600
647
  if (spinner) {
601
648
  spinner.text = `Testing ${p}...`;
602
649
  }
650
+ // First check if provider has env vars configured
651
+ const hasEnvVars = hasProviderEnvVars(p);
652
+ if (!hasEnvVars && p !== "ollama") {
653
+ // No env vars, don't even try to test
654
+ results.push({
655
+ provider: p,
656
+ status: "not-configured",
657
+ configured: false,
658
+ error: "Missing required environment variables",
659
+ });
660
+ if (spinner) {
661
+ spinner.fail(`${p}: ${chalk.gray("⚪ Not configured")} - Missing environment variables`);
662
+ }
663
+ else if (!argv.quiet) {
664
+ console.log(`${p}: ${chalk.gray("⚪ Not configured")} - Missing environment variables`);
665
+ }
666
+ continue;
667
+ }
668
+ // Special handling for Ollama
669
+ if (p === "ollama") {
670
+ try {
671
+ // First, check if the service is running
672
+ const serviceResponse = await fetch("http://localhost:11434/api/tags", {
673
+ method: "GET",
674
+ signal: AbortSignal.timeout(2000),
675
+ });
676
+ if (!serviceResponse.ok) {
677
+ throw new Error("Ollama service not responding");
678
+ }
679
+ // Service is running, now check if the default model is available
680
+ const { models } = await serviceResponse.json();
681
+ const defaultOllamaModel = "llama3.2:latest";
682
+ const modelIsAvailable = models.some((m) => m.name === defaultOllamaModel);
683
+ if (modelIsAvailable) {
684
+ results.push({
685
+ provider: p,
686
+ status: "working",
687
+ configured: true,
688
+ authenticated: true,
689
+ responseTime: 0,
690
+ });
691
+ if (spinner) {
692
+ spinner.succeed(`${p}: ${chalk.green("✅ Working")} - Service running and model '${defaultOllamaModel}' is available.`);
693
+ }
694
+ }
695
+ else {
696
+ results.push({
697
+ provider: p,
698
+ status: "failed",
699
+ configured: true,
700
+ authenticated: false,
701
+ error: `Ollama service is running, but model '${defaultOllamaModel}' is not found. Please run 'ollama pull ${defaultOllamaModel}'.`,
702
+ });
703
+ if (spinner) {
704
+ spinner.fail(`${p}: ${chalk.red("❌ Model Not Found")} - Run 'ollama pull ${defaultOllamaModel}'`);
705
+ }
706
+ }
707
+ }
708
+ catch (error) {
709
+ results.push({
710
+ provider: p,
711
+ status: "failed",
712
+ configured: false,
713
+ authenticated: false,
714
+ error: "Ollama is not running. Please start with: ollama serve",
715
+ });
716
+ if (spinner) {
717
+ spinner.fail(`${p}: ${chalk.red("❌ Failed")} - Service not running`);
718
+ }
719
+ }
720
+ continue;
721
+ }
722
+ // Provider has env vars, now test authentication
603
723
  try {
604
724
  const start = Date.now();
605
- await sdk.generateText({
725
+ // Add timeout to prevent hanging
726
+ const testPromise = sdk.generateText({
606
727
  prompt: "test",
607
728
  provider: p,
608
729
  maxTokens: 1,
730
+ disableTools: true, // Disable tools for faster status check
609
731
  });
732
+ const timeoutPromise = new Promise((_, reject) => {
733
+ setTimeout(() => reject(new Error("Provider test timeout (5s)")), 5000);
734
+ });
735
+ await Promise.race([testPromise, timeoutPromise]);
610
736
  const duration = Date.now() - start;
611
737
  results.push({
612
738
  provider: p,
613
739
  status: "working",
740
+ configured: true,
741
+ authenticated: true,
614
742
  responseTime: duration,
615
743
  });
616
744
  if (spinner) {
@@ -621,280 +749,157 @@ const cli = yargs(args)
621
749
  }
622
750
  }
623
751
  catch (error) {
752
+ const errorMsg = error.message.includes("timeout")
753
+ ? "Connection timeout"
754
+ : error.message.split("\n")[0];
624
755
  results.push({
625
756
  provider: p,
626
757
  status: "failed",
627
- error: error.message,
758
+ configured: true,
759
+ authenticated: false,
760
+ error: errorMsg,
628
761
  });
629
762
  if (spinner) {
630
- spinner.fail(`${p}: ${chalk.red("❌ Failed")} - ${error.message.split("\n")[0]}`);
763
+ spinner.fail(`${p}: ${chalk.red("❌ Failed")} - ${errorMsg}`);
631
764
  }
632
765
  else if (!argv.quiet) {
633
- console.error(`${p}: ${chalk.red("❌ Failed")} - ${error.message.split("\n")[0]}`);
766
+ console.error(`${p}: ${chalk.red("❌ Failed")} - ${errorMsg}`);
634
767
  }
635
768
  }
636
769
  }
637
770
  const working = results.filter((r) => r.status === "working").length;
771
+ const configured = results.filter((r) => r.configured).length;
638
772
  if (spinner) {
639
- spinner.info(chalk.blue(`\n📊 Summary: ${working}/${results.length} providers working`));
773
+ spinner.info(chalk.blue(`\n📊 Summary: ${working}/${results.length} providers working, ${configured}/${results.length} configured`));
640
774
  }
641
775
  else if (!argv.quiet) {
642
- console.log(chalk.blue(`\n📊 Summary: ${working}/${results.length} providers working`));
776
+ console.log(chalk.blue(`\n📊 Summary: ${working}/${results.length} providers working, ${configured}/${results.length} configured`));
643
777
  }
644
778
  if (argv.verbose && !argv.quiet) {
645
779
  console.log(chalk.blue("\n📋 Detailed Results:"));
646
780
  console.log(JSON.stringify(results, null, 2));
647
781
  }
648
782
  })
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");
651
- })
652
- .command("configure <providerName>", "Display configuration guidance for a provider", (y) => y
653
- .usage("Usage: $0 provider configure <providerName>")
654
- .positional("providerName", {
783
+ .demandCommand(1, "")
784
+ .example("$0 provider status", "Check all providers");
785
+ })
786
+ // Status command alias
787
+ .command("status", "Check AI provider connectivity and performance (alias for provider status)", (yargsConfig) => yargsConfig.example("$0 status", "Quick provider status check"), async (argv) => {
788
+ // Simply redirect to provider status
789
+ process.argv = [
790
+ process.argv[0],
791
+ process.argv[1],
792
+ "provider",
793
+ "status",
794
+ ...process.argv.slice(3),
795
+ ];
796
+ const { hideBin } = await import("yargs/helpers");
797
+ const redirectedCli = yargs(hideBin(process.argv));
798
+ // Re-run with provider status
799
+ await cli.parse("provider status");
800
+ })
801
+ // Configuration Command Group
802
+ .command("config <subcommand>", "Manage NeuroLink configuration", (yargsConfig) => {
803
+ yargsConfig
804
+ .usage("Usage: $0 config <subcommand> [options]")
805
+ .command("export", "Export current configuration", (y) => y
806
+ .usage("Usage: $0 config export [options]")
807
+ .option("output", {
655
808
  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",
668
- demandOption: true,
669
- })
670
- .example("$0 provider configure openai", "Show OpenAI configuration help"), async (argv) => {
671
- console.log(chalk.blue(`\n🔧 Configuration guidance for ${chalk.bold(argv.providerName)}:`));
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"));
809
+ alias: "o",
810
+ description: "Output file for configuration",
674
811
  })
675
- .demandCommand(1, "Please specify a provider subcommand (status, list, or configure).");
676
- })
677
- // Status Command (Standalone, for backward compatibility or direct access)
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) => {
688
- // This logic is duplicated from 'provider status' for the alias
689
- if (argv.verbose && !argv.quiet) {
690
- console.log(chalk.yellow("ℹ️ Verbose mode enabled. Displaying detailed status.\n")); // Added newline
691
- }
692
- const spinner = argv.quiet
693
- ? null
694
- : ora("🔍 Checking AI provider status...\n").start();
695
- // Middleware sets argv.verbose if NEUROLINK_DEBUG is true and --verbose is not specified
696
- // Removed the spinner.stopAndPersist logic from here as it's handled before spinner start
697
- const providers = [
698
- "openai",
699
- "bedrock",
700
- "vertex",
701
- "anthropic",
702
- "azure",
703
- "google-ai",
704
- "huggingface",
705
- "ollama",
706
- "mistral",
707
- ];
708
- const results = [];
709
- for (const p of providers) {
710
- if (spinner) {
711
- spinner.text = `Testing ${p}...`;
712
- }
812
+ .example("$0 config export", "Export to stdout")
813
+ .example("$0 config export -o config.json", "Export to file"), async (argv) => {
713
814
  try {
714
- const start = Date.now();
715
- await sdk.generateText({ prompt: "test", provider: p, maxTokens: 1 });
716
- const duration = Date.now() - start;
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)`);
815
+ const config = {
816
+ providers: {
817
+ openai: !!process.env.OPENAI_API_KEY,
818
+ bedrock: !!(process.env.AWS_ACCESS_KEY_ID &&
819
+ process.env.AWS_SECRET_ACCESS_KEY),
820
+ vertex: !!(process.env.GOOGLE_APPLICATION_CREDENTIALS ||
821
+ process.env.GOOGLE_SERVICE_ACCOUNT_KEY ||
822
+ (process.env.GOOGLE_AUTH_CLIENT_EMAIL &&
823
+ process.env.GOOGLE_AUTH_PRIVATE_KEY)),
824
+ anthropic: !!process.env.ANTHROPIC_API_KEY,
825
+ azure: !!(process.env.AZURE_OPENAI_API_KEY &&
826
+ process.env.AZURE_OPENAI_ENDPOINT),
827
+ "google-ai": !!process.env.GOOGLE_AI_API_KEY,
828
+ },
829
+ defaults: {
830
+ temperature: 0.7,
831
+ maxTokens: 500,
832
+ },
833
+ timestamp: new Date().toISOString(),
834
+ };
835
+ const output = JSON.stringify(config, null, 2);
836
+ if (argv.output) {
837
+ fs.writeFileSync(argv.output, output);
838
+ if (!argv.quiet) {
839
+ console.log(chalk.green(`✅ Configuration exported to ${argv.output}`));
840
+ }
724
841
  }
725
- else if (!argv.quiet) {
726
- console.log(`${p}: ${chalk.green("✅ Working")} (${duration}ms)`);
842
+ else {
843
+ process.stdout.write(output + "\n");
727
844
  }
728
845
  }
729
846
  catch (error) {
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
- }
847
+ handleError(error, "Configuration export");
741
848
  }
742
- }
743
- const working = results.filter((r) => r.status === "working").length;
744
- if (spinner) {
745
- spinner.info(chalk.blue(`\n📊 Summary: ${working}/${results.length} providers working`));
746
- }
747
- else if (!argv.quiet) {
748
- console.log(chalk.blue(`\n📊 Summary: ${working}/${results.length} providers working`));
749
- }
750
- if (argv.verbose && !argv.quiet) {
751
- console.log(chalk.blue("\n📋 Detailed Results:"));
752
- console.log(JSON.stringify(results, null, 2));
753
- }
754
- })
755
- // Configuration Commands Refactored
756
- .command("config <subcommand>", "Manage NeuroLink configuration", (yargsConfig) => {
757
- yargsConfig
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",
765
- })
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);
770
- })
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...");
785
- // Actual show logic here
786
- })
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
849
  })
793
- .positional("value", {
794
- type: "string",
795
- description: "Value to set for the key",
796
- demandOption: true,
797
- }), async (argv) => {
798
- console.log(`Config set: Key: ${argv.key}, Value: ${argv.value}`);
799
- // Actual set logic here
800
- })
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) => {
806
- console.log(`Config import: Importing from ${argv.file}`);
807
- if (argv.file.includes("invalid-config.json")) {
808
- handleError(new Error("Invalid or unparseable JSON in config file."), "Config import");
809
- }
810
- // Actual import logic here
811
- })
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) => {
817
- console.log(`Config export: Exporting to ${argv.file}`);
818
- if (argv.file.includes("read-only-dir")) {
819
- handleError(new Error("Permission denied. Cannot write to read-only directory."), "Config export");
820
- }
821
- // Actual export logic here
822
- })
823
- .command("validate", "Validate the current configuration", () => { }, async (argv) => {
824
- console.log("Config validate: Validating configuration...");
825
- // Actual validation logic here
826
- })
827
- .command("reset", "Reset NeuroLink configuration to defaults", () => { }, async (argv) => {
828
- console.log("Config reset: Resetting configuration...");
829
- // Actual reset logic here
830
- })
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)");
850
+ .demandCommand(1, "")
851
+ .example("$0 config export", "Export configuration");
834
852
  })
835
853
  // Get Best Provider Command
836
854
  .command("get-best-provider", "Show the best available AI provider", (yargsInstance) => yargsInstance
837
855
  .usage("Usage: $0 get-best-provider [options]")
838
- .option("debug", {
839
- type: "boolean",
840
- default: false,
841
- description: "Enable debug mode with selection reasoning",
856
+ .option("format", {
857
+ choices: ["text", "json"],
858
+ default: "text",
859
+ description: "Output format",
842
860
  })
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();
861
+ .example("$0 get-best-provider", "Show best provider")
862
+ .example("$0 get-best-provider --format json", "Show in JSON format"), async (argv) => {
848
863
  try {
849
- const provider = await sdk.getBestProvider();
850
- if (spinner) {
851
- if (argv.debug) {
852
- spinner.succeed(chalk.green(`✅ Best provider selected: ${provider}`));
864
+ const { getBestProvider } = await import("../lib/utils/providerUtils-fixed.js");
865
+ const bestProvider = getBestProvider();
866
+ if (argv.format === "json") {
867
+ process.stdout.write(JSON.stringify({ provider: bestProvider }, null, 2) + "\n");
868
+ }
869
+ else {
870
+ if (!argv.quiet) {
871
+ console.log(chalk.green(`🎯 Best available provider: ${bestProvider}`));
853
872
  }
854
873
  else {
855
- spinner.succeed(chalk.green("✅ Provider found"));
874
+ process.stdout.write(bestProvider + "\n");
856
875
  }
857
876
  }
858
- if (argv.debug) {
859
- // Debug mode: Show selection reasoning and metadata
860
- console.log(`\nBest available provider: ${provider}`);
861
- console.log(`Selection based on: availability, performance, and configuration`);
862
- }
863
- else {
864
- // Default mode: Clean provider name only
865
- console.log(provider);
866
- }
867
877
  }
868
878
  catch (error) {
869
- if (spinner && spinner.isSpinning) {
870
- spinner.fail();
871
- }
872
879
  handleError(error, "Provider selection");
873
880
  }
874
881
  })
875
- .completion("completion", "Generate shell completion script");
876
- // Add MCP commands
882
+ // Completion Command
883
+ .command("completion", "Generate shell completion script", (yargsInstance) => yargsInstance
884
+ .usage("Usage: $0 completion")
885
+ .example("$0 completion >> ~/.bashrc", "Add to bash")
886
+ .example("$0 completion >> ~/.zshrc", "Add to zsh"), async (argv) => {
887
+ cli.showCompletionScript();
888
+ });
889
+ // Add MCP Commands
877
890
  addMCPCommands(cli);
878
- // Add Ollama command
879
- cli.command(ollamaCommand);
880
- // Add Agent-Generate command
881
- cli.command(agentGenerateCommand);
882
- // Use an async IIFE to allow top-level await for parseAsync
891
+ // Add Ollama Commands
892
+ addOllamaCommands(cli);
893
+ // Add Agent Generate Command
894
+ agentGenerateCommand(cli);
895
+ // Execute CLI
883
896
  (async () => {
884
897
  try {
885
- await cli.parseAsync();
898
+ await cli.parse();
886
899
  }
887
900
  catch (error) {
888
- // Yargs .fail() should handle most errors and exit,
889
- // but catch any other unhandled promise rejections from async handlers.
890
- // handleError is not called here because .fail() or command handlers should have already done so.
891
- // If an error reaches here, it's likely an unhandled exception not caught by yargs.
892
- if (error instanceof Error) {
893
- console.error(chalk.red(`Unhandled CLI Error: ${error.message}`));
894
- }
895
- else {
896
- console.error(chalk.red(`Unhandled CLI Error: ${String(error)}`));
897
- }
901
+ // Global error handler - should not reach here due to fail() handler
902
+ process.stderr.write(chalk.red(`Unexpected CLI error: ${error.message}\n`));
898
903
  process.exit(1);
899
904
  }
900
905
  })();