@juspay/neurolink 1.10.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 (144) hide show
  1. package/CHANGELOG.md +36 -33
  2. package/README.md +16 -0
  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 +185 -276
  12. package/dist/core/factory.js +9 -10
  13. package/dist/index.d.ts +23 -0
  14. package/dist/index.js +35 -0
  15. package/dist/lib/agent/direct-tools.d.ts +9 -9
  16. package/dist/lib/core/factory.js +9 -10
  17. package/dist/lib/index.d.ts +23 -0
  18. package/dist/lib/index.js +35 -0
  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 +27 -176
  54. package/dist/lib/mcp/registry.js +31 -372
  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-workflow-tools.d.ts +2 -2
  58. package/dist/lib/mcp/tool-integration.d.ts +4 -14
  59. package/dist/lib/mcp/tool-integration.js +43 -21
  60. package/dist/lib/mcp/tool-registry.d.ts +66 -0
  61. package/dist/lib/mcp/tool-registry.js +160 -0
  62. package/dist/lib/mcp/unified-mcp.d.ts +123 -0
  63. package/dist/lib/mcp/unified-mcp.js +246 -0
  64. package/dist/lib/mcp/unified-registry.d.ts +42 -229
  65. package/dist/lib/mcp/unified-registry.js +96 -1346
  66. package/dist/lib/neurolink.d.ts +3 -4
  67. package/dist/lib/neurolink.js +17 -18
  68. package/dist/lib/providers/agent-enhanced-provider.js +2 -2
  69. package/dist/lib/providers/amazonBedrock.js +2 -2
  70. package/dist/lib/providers/anthropic.js +3 -3
  71. package/dist/lib/providers/azureOpenAI.js +3 -3
  72. package/dist/lib/providers/function-calling-provider.js +34 -25
  73. package/dist/lib/providers/googleAIStudio.js +3 -3
  74. package/dist/lib/providers/googleVertexAI.js +2 -2
  75. package/dist/lib/providers/huggingFace.js +2 -2
  76. package/dist/lib/providers/mcp-provider.js +33 -5
  77. package/dist/lib/providers/mistralAI.js +2 -2
  78. package/dist/lib/providers/ollama.js +2 -2
  79. package/dist/lib/providers/openAI.js +2 -2
  80. package/dist/lib/utils/providerUtils-fixed.js +9 -9
  81. package/dist/mcp/adapters/plugin-bridge.d.ts +39 -0
  82. package/dist/mcp/adapters/plugin-bridge.js +82 -0
  83. package/dist/mcp/auto-discovery.d.ts +38 -96
  84. package/dist/mcp/auto-discovery.js +100 -745
  85. package/dist/mcp/client.js +4 -4
  86. package/dist/mcp/context-manager.js +72 -1
  87. package/dist/mcp/contracts/mcp-contract.d.ts +162 -0
  88. package/dist/mcp/contracts/mcp-contract.js +58 -0
  89. package/dist/mcp/core/plugin-manager.d.ts +45 -0
  90. package/dist/mcp/core/plugin-manager.js +110 -0
  91. package/dist/mcp/demo/plugin-demo.d.ts +20 -0
  92. package/dist/mcp/demo/plugin-demo.js +116 -0
  93. package/dist/mcp/ecosystem.d.ts +75 -0
  94. package/dist/mcp/ecosystem.js +162 -0
  95. package/dist/mcp/external-client.d.ts +88 -0
  96. package/dist/mcp/external-client.js +323 -0
  97. package/dist/mcp/external-manager.d.ts +112 -0
  98. package/dist/mcp/external-manager.js +302 -0
  99. package/dist/mcp/factory.d.ts +4 -4
  100. package/dist/mcp/function-calling.js +59 -34
  101. package/dist/mcp/index.d.ts +39 -184
  102. package/dist/mcp/index.js +72 -150
  103. package/dist/mcp/initialize.js +5 -5
  104. package/dist/mcp/logging.d.ts +27 -60
  105. package/dist/mcp/logging.js +77 -165
  106. package/dist/mcp/neurolink-mcp-client.js +31 -3
  107. package/dist/mcp/orchestrator.d.ts +1 -1
  108. package/dist/mcp/orchestrator.js +13 -12
  109. package/dist/mcp/plugin-manager.d.ts +98 -0
  110. package/dist/mcp/plugin-manager.js +295 -0
  111. package/dist/mcp/plugins/core/filesystem-mcp.d.ts +35 -0
  112. package/dist/mcp/plugins/core/filesystem-mcp.js +139 -0
  113. package/dist/mcp/plugins/core/neurolink-mcp.json +17 -0
  114. package/dist/mcp/plugins/filesystem-mcp.d.ts +36 -0
  115. package/dist/mcp/plugins/filesystem-mcp.js +54 -0
  116. package/dist/mcp/registry.d.ts +27 -176
  117. package/dist/mcp/registry.js +31 -372
  118. package/dist/mcp/security-manager.d.ts +85 -0
  119. package/dist/mcp/security-manager.js +344 -0
  120. package/dist/mcp/servers/ai-providers/ai-workflow-tools.d.ts +2 -2
  121. package/dist/mcp/tool-integration.d.ts +4 -14
  122. package/dist/mcp/tool-integration.js +43 -21
  123. package/dist/mcp/tool-registry.d.ts +66 -0
  124. package/dist/mcp/tool-registry.js +160 -0
  125. package/dist/mcp/unified-mcp.d.ts +123 -0
  126. package/dist/mcp/unified-mcp.js +246 -0
  127. package/dist/mcp/unified-registry.d.ts +42 -229
  128. package/dist/mcp/unified-registry.js +96 -1345
  129. package/dist/neurolink.d.ts +3 -4
  130. package/dist/neurolink.js +17 -18
  131. package/dist/providers/agent-enhanced-provider.js +2 -2
  132. package/dist/providers/amazonBedrock.js +2 -2
  133. package/dist/providers/anthropic.js +3 -3
  134. package/dist/providers/azureOpenAI.js +3 -3
  135. package/dist/providers/function-calling-provider.js +34 -25
  136. package/dist/providers/googleAIStudio.js +3 -3
  137. package/dist/providers/googleVertexAI.js +2 -2
  138. package/dist/providers/huggingFace.js +2 -2
  139. package/dist/providers/mcp-provider.js +33 -5
  140. package/dist/providers/mistralAI.js +2 -2
  141. package/dist/providers/ollama.js +2 -2
  142. package/dist/providers/openAI.js +2 -2
  143. package/dist/utils/providerUtils-fixed.js +9 -9
  144. package/package.json +1 -1
@@ -2,10 +2,8 @@ import { execSync } from "child_process";
2
2
  import chalk from "chalk";
3
3
  import ora from "ora";
4
4
  import inquirer from "inquirer";
5
- export const ollamaCommand = {
6
- command: "ollama <command>",
7
- describe: "Manage Ollama local AI models",
8
- builder: (yargs) => {
5
+ export function addOllamaCommands(cli) {
6
+ cli.command("ollama <command>", "Manage Ollama local AI models", (yargs) => {
9
7
  return yargs
10
8
  .command("list-models", "List installed Ollama models", {}, listModelsHandler)
11
9
  .command("pull <model>", "Download an Ollama model", {
@@ -27,9 +25,8 @@ export const ollamaCommand = {
27
25
  .command("stop", "Stop Ollama service", {}, stopHandler)
28
26
  .command("setup", "Interactive Ollama setup", {}, setupHandler)
29
27
  .demandCommand(1, "Please specify a command");
30
- },
31
- handler: () => { }, // No-op handler as subcommands handle everything
32
- };
28
+ }, () => { });
29
+ }
33
30
  async function listModelsHandler() {
34
31
  const spinner = ora("Fetching installed models...").start();
35
32
  try {
@@ -330,4 +327,4 @@ async function setupHandler() {
330
327
  chalk.gray('neurolink generate-text "Hello!" --provider ollama --model codellama'));
331
328
  console.log(chalk.gray("\nFor more information, see: https://docs.neurolink.ai/providers/ollama"));
332
329
  }
333
- export default ollamaCommand;
330
+ export default addOllamaCommands;
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",
@@ -624,9 +669,9 @@ const cli = yargs(args)
624
669
  if (p === "ollama") {
625
670
  try {
626
671
  // First, check if the service is running
627
- const serviceResponse = await fetch('http://localhost:11434/api/tags', {
628
- method: 'GET',
629
- signal: AbortSignal.timeout(2000)
672
+ const serviceResponse = await fetch("http://localhost:11434/api/tags", {
673
+ method: "GET",
674
+ signal: AbortSignal.timeout(2000),
630
675
  });
631
676
  if (!serviceResponse.ok) {
632
677
  throw new Error("Ollama service not responding");
@@ -677,14 +722,17 @@ const cli = yargs(args)
677
722
  // Provider has env vars, now test authentication
678
723
  try {
679
724
  const start = Date.now();
680
- // Import AIProviderFactory to test providers directly without fallback
681
- const { AIProviderFactory } = await import("../lib/core/factory.js");
682
- // Create and test provider directly to avoid automatic fallback
683
- const provider = await AIProviderFactory.createProvider(p);
684
- await provider.generateText({
725
+ // Add timeout to prevent hanging
726
+ const testPromise = sdk.generateText({
685
727
  prompt: "test",
728
+ provider: p,
686
729
  maxTokens: 1,
730
+ disableTools: true, // Disable tools for faster status check
731
+ });
732
+ const timeoutPromise = new Promise((_, reject) => {
733
+ setTimeout(() => reject(new Error("Provider test timeout (5s)")), 5000);
687
734
  });
735
+ await Promise.race([testPromise, timeoutPromise]);
688
736
  const duration = Date.now() - start;
689
737
  results.push({
690
738
  provider: p,
@@ -701,31 +749,21 @@ const cli = yargs(args)
701
749
  }
702
750
  }
703
751
  catch (error) {
704
- const errorMsg = error.message;
705
- let authStatus = false;
706
- let statusText = "Failed";
707
- // Check if it's an authentication error
708
- if (errorMsg.includes('401') || errorMsg.includes('Unauthorized') ||
709
- errorMsg.includes('Invalid API') || errorMsg.includes('Authentication') ||
710
- errorMsg.includes('API key') || errorMsg.includes('not authorized') ||
711
- errorMsg.includes('ExpiredToken') || errorMsg.includes('expired')) {
712
- statusText = "Invalid credentials";
713
- }
714
- else if (errorMsg.includes('fetch') || errorMsg.includes('blob')) {
715
- statusText = "Service error";
716
- }
752
+ const errorMsg = error.message.includes("timeout")
753
+ ? "Connection timeout"
754
+ : error.message.split("\n")[0];
717
755
  results.push({
718
756
  provider: p,
719
757
  status: "failed",
720
758
  configured: true,
721
- authenticated: authStatus,
759
+ authenticated: false,
722
760
  error: errorMsg,
723
761
  });
724
762
  if (spinner) {
725
- spinner.fail(`${p}: ${chalk.red("❌ " + statusText)} - ${errorMsg.split("\n")[0]}`);
763
+ spinner.fail(`${p}: ${chalk.red("❌ Failed")} - ${errorMsg}`);
726
764
  }
727
765
  else if (!argv.quiet) {
728
- console.error(`${p}: ${chalk.red("❌ " + statusText)} - ${errorMsg.split("\n")[0]}`);
766
+ console.error(`${p}: ${chalk.red("❌ Failed")} - ${errorMsg}`);
729
767
  }
730
768
  }
731
769
  }
@@ -742,255 +780,126 @@ const cli = yargs(args)
742
780
  console.log(JSON.stringify(results, null, 2));
743
781
  }
744
782
  })
745
- .command("list", "List available AI providers", (y) => y.usage("Usage: $0 provider list"), async () => {
746
- console.log("Available providers: openai, bedrock, vertex, anthropic, azure, google-ai, huggingface, ollama, mistral");
747
- })
748
- .command("configure <providerName>", "Display configuration guidance for a provider", (y) => y
749
- .usage("Usage: $0 provider configure <providerName>")
750
- .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", {
751
808
  type: "string",
752
- choices: [
753
- "openai",
754
- "bedrock",
755
- "vertex",
756
- "anthropic",
757
- "azure",
758
- "google-ai",
759
- "huggingface",
760
- "ollama",
761
- "mistral",
762
- ],
763
- description: "Name of the provider to configure",
764
- demandOption: true,
809
+ alias: "o",
810
+ description: "Output file for configuration",
765
811
  })
766
- .example("$0 provider configure openai", "Show OpenAI configuration help"), async (argv) => {
767
- console.log(chalk.blue(`\n🔧 Configuration guidance for ${chalk.bold(argv.providerName)}:`));
768
- console.log(chalk.yellow("💡 Set relevant environment variables for API keys and other settings."));
769
- console.log(chalk.gray(" Refer to the documentation for details: https://github.com/juspay/neurolink#configuration"));
770
- })
771
- .demandCommand(1, "Please specify a provider subcommand (status, list, or configure).");
772
- })
773
- // Status Command (Standalone, for backward compatibility or direct access)
774
- .command("status", "Check AI provider connectivity and performance (alias for provider status)", (yargsInstance) => yargsInstance
775
- .usage("Usage: $0 status [options]")
776
- .option("verbose", {
777
- // Ensure status alias also defines verbose
778
- type: "boolean",
779
- alias: "v", // Default is handled by middleware if NEUROLINK_DEBUG is set
780
- description: "Show detailed information",
781
- })
782
- .example("$0 status", "Check all providers")
783
- .example("$0 status --verbose", "Show detailed status information"), async (argv) => {
784
- // This logic is duplicated from 'provider status' for the alias
785
- if (argv.verbose && !argv.quiet) {
786
- console.log(chalk.yellow("ℹ️ Verbose mode enabled. Displaying detailed status.\n")); // Added newline
787
- }
788
- const spinner = argv.quiet
789
- ? null
790
- : ora("🔍 Checking AI provider status...\n").start();
791
- // Middleware sets argv.verbose if NEUROLINK_DEBUG is true and --verbose is not specified
792
- // Removed the spinner.stopAndPersist logic from here as it's handled before spinner start
793
- const providers = [
794
- "openai",
795
- "bedrock",
796
- "vertex",
797
- "anthropic",
798
- "azure",
799
- "google-ai",
800
- "huggingface",
801
- "ollama",
802
- "mistral",
803
- ];
804
- const results = [];
805
- for (const p of providers) {
806
- if (spinner) {
807
- spinner.text = `Testing ${p}...`;
808
- }
812
+ .example("$0 config export", "Export to stdout")
813
+ .example("$0 config export -o config.json", "Export to file"), async (argv) => {
809
814
  try {
810
- const start = Date.now();
811
- await sdk.generateText({ prompt: "test", provider: p, maxTokens: 1 });
812
- const duration = Date.now() - start;
813
- results.push({
814
- provider: p,
815
- status: "working",
816
- responseTime: duration,
817
- });
818
- if (spinner) {
819
- 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
+ }
820
841
  }
821
- else if (!argv.quiet) {
822
- console.log(`${p}: ${chalk.green("✅ Working")} (${duration}ms)`);
842
+ else {
843
+ process.stdout.write(output + "\n");
823
844
  }
824
845
  }
825
846
  catch (error) {
826
- results.push({
827
- provider: p,
828
- status: "failed",
829
- error: error.message,
830
- });
831
- if (spinner) {
832
- spinner.fail(`${p}: ${chalk.red("❌ Failed")} - ${error.message.split("\n")[0]}`);
833
- }
834
- else if (!argv.quiet) {
835
- console.error(`${p}: ${chalk.red("❌ Failed")} - ${error.message.split("\n")[0]}`);
836
- }
847
+ handleError(error, "Configuration export");
837
848
  }
838
- }
839
- const working = results.filter((r) => r.status === "working").length;
840
- if (spinner) {
841
- spinner.info(chalk.blue(`\n📊 Summary: ${working}/${results.length} providers working`));
842
- }
843
- else if (!argv.quiet) {
844
- console.log(chalk.blue(`\n📊 Summary: ${working}/${results.length} providers working`));
845
- }
846
- if (argv.verbose && !argv.quiet) {
847
- console.log(chalk.blue("\n📋 Detailed Results:"));
848
- console.log(JSON.stringify(results, null, 2));
849
- }
850
- })
851
- // Configuration Commands Refactored
852
- .command("config <subcommand>", "Manage NeuroLink configuration", (yargsConfig) => {
853
- yargsConfig
854
- .usage("Usage: $0 config <subcommand> [options]") // Add usage here
855
- .command("setup", "Interactive setup for NeuroLink configuration", (y) => y
856
- .usage("Usage: $0 config setup [options]")
857
- .option("quiet", {
858
- type: "boolean",
859
- alias: "q",
860
- description: "Suppress progress messages and interactive prompts",
861
- })
862
- .example("$0 config setup", "Run interactive setup wizard")
863
- .example("$0 config setup --quiet", "Run setup with minimal output"), async (argv) => {
864
- const { configSetup } = await import("./utils/complete-setup.js");
865
- await configSetup(argv.quiet);
866
- })
867
- .command("init", "Alias for setup: Interactive setup for NeuroLink configuration", (y) => y
868
- .usage("Usage: $0 config init [options]")
869
- .option("quiet", {
870
- type: "boolean",
871
- alias: "q",
872
- description: "Suppress progress messages and interactive prompts",
873
- })
874
- .example("$0 config init", "Run interactive setup wizard (alias for setup)")
875
- .example("$0 config init --quiet", "Run setup with minimal output"), async (argv) => {
876
- const { configInit } = await import("./utils/complete-setup.js");
877
- await configInit(argv.quiet);
878
- })
879
- .command("show", "Show current NeuroLink configuration", () => { }, async (argv) => {
880
- console.log("Config show: Displaying current configuration...");
881
- // Actual show logic here
882
- })
883
- .command("set <key> <value>", "Set a configuration key-value pair", (y) => y
884
- .positional("key", {
885
- type: "string",
886
- description: "Configuration key to set",
887
- demandOption: true,
888
- })
889
- .positional("value", {
890
- type: "string",
891
- description: "Value to set for the key",
892
- demandOption: true,
893
- }), async (argv) => {
894
- console.log(`Config set: Key: ${argv.key}, Value: ${argv.value}`);
895
- // Actual set logic here
896
849
  })
897
- .command("import <file>", "Import configuration from a file", (y) => y.positional("file", {
898
- type: "string",
899
- description: "File path to import from",
900
- demandOption: true,
901
- }), async (argv) => {
902
- console.log(`Config import: Importing from ${argv.file}`);
903
- if (argv.file.includes("invalid-config.json")) {
904
- handleError(new Error("Invalid or unparseable JSON in config file."), "Config import");
905
- }
906
- // Actual import logic here
907
- })
908
- .command("export <file>", "Export current configuration to a file", (y) => y.positional("file", {
909
- type: "string",
910
- description: "File path to export to",
911
- demandOption: true,
912
- }), async (argv) => {
913
- console.log(`Config export: Exporting to ${argv.file}`);
914
- if (argv.file.includes("read-only-dir")) {
915
- handleError(new Error("Permission denied. Cannot write to read-only directory."), "Config export");
916
- }
917
- // Actual export logic here
918
- })
919
- .command("validate", "Validate the current configuration", () => { }, async (argv) => {
920
- console.log("Config validate: Validating configuration...");
921
- // Actual validation logic here
922
- })
923
- .command("reset", "Reset NeuroLink configuration to defaults", () => { }, async (argv) => {
924
- console.log("Config reset: Resetting configuration...");
925
- // Actual reset logic here
926
- })
927
- .demandCommand(1, "Please specify a config subcommand (e.g., setup, show, set).")
928
- .example("$0 config setup", "Run interactive setup")
929
- .example("$0 config set provider openai", "Set default provider (using key/value)");
850
+ .demandCommand(1, "")
851
+ .example("$0 config export", "Export configuration");
930
852
  })
931
853
  // Get Best Provider Command
932
854
  .command("get-best-provider", "Show the best available AI provider", (yargsInstance) => yargsInstance
933
855
  .usage("Usage: $0 get-best-provider [options]")
934
- .option("debug", {
935
- type: "boolean",
936
- default: false,
937
- description: "Enable debug mode with selection reasoning",
856
+ .option("format", {
857
+ choices: ["text", "json"],
858
+ default: "text",
859
+ description: "Output format",
938
860
  })
939
- .example("$0 get-best-provider", "Get best provider")
940
- .example("$0 get-best-provider --debug", "Show selection logic"), async (argv) => {
941
- const spinner = argv.quiet
942
- ? null
943
- : 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) => {
944
863
  try {
945
- const provider = await sdk.getBestProvider();
946
- if (spinner) {
947
- if (argv.debug) {
948
- 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}`));
949
872
  }
950
873
  else {
951
- spinner.succeed(chalk.green("✅ Provider found"));
874
+ process.stdout.write(bestProvider + "\n");
952
875
  }
953
876
  }
954
- if (argv.debug) {
955
- // Debug mode: Show selection reasoning and metadata
956
- console.log(`\nBest available provider: ${provider}`);
957
- console.log(`Selection based on: availability, performance, and configuration`);
958
- }
959
- else {
960
- // Default mode: Clean provider name only
961
- console.log(provider);
962
- }
963
877
  }
964
878
  catch (error) {
965
- if (spinner && spinner.isSpinning) {
966
- spinner.fail();
967
- }
968
879
  handleError(error, "Provider selection");
969
880
  }
970
881
  })
971
- .completion("completion", "Generate shell completion script");
972
- // 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
973
890
  addMCPCommands(cli);
974
- // Add Ollama command
975
- cli.command(ollamaCommand);
976
- // Add Agent-Generate command
977
- cli.command(agentGenerateCommand);
978
- // 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
979
896
  (async () => {
980
897
  try {
981
- await cli.parseAsync();
898
+ await cli.parse();
982
899
  }
983
900
  catch (error) {
984
- // Yargs .fail() should handle most errors and exit,
985
- // but catch any other unhandled promise rejections from async handlers.
986
- // handleError is not called here because .fail() or command handlers should have already done so.
987
- // If an error reaches here, it's likely an unhandled exception not caught by yargs.
988
- if (error instanceof Error) {
989
- console.error(chalk.red(`Unhandled CLI Error: ${error.message}`));
990
- }
991
- else {
992
- console.error(chalk.red(`Unhandled CLI Error: ${String(error)}`));
993
- }
901
+ // Global error handler - should not reach here due to fail() handler
902
+ process.stderr.write(chalk.red(`Unexpected CLI error: ${error.message}\n`));
994
903
  process.exit(1);
995
904
  }
996
905
  })();
@@ -157,16 +157,15 @@ export class AIProviderFactory {
157
157
  // Wrap with MCP if enabled
158
158
  if (enableMCP) {
159
159
  try {
160
- // TEMPORARY: Disable MCP wrapping to test for hanging issues
161
- logger.debug(`[${functionTag}] MCP wrapping temporarily disabled for debugging`);
162
- // const { createMCPAwareProviderV3 } = await import("../providers/function-calling-provider.js");
163
- // provider = createMCPAwareProviderV3(provider, {
164
- // providerName,
165
- // modelName: resolvedModelName || undefined,
166
- // enableMCP: true,
167
- // enableFunctionCalling: true,
168
- // });
169
- // logger.debug(`[${functionTag}] Provider wrapped with MCP support`);
160
+ logger.debug(`[${functionTag}] Enabling MCP wrapping for AI integration`);
161
+ const { createMCPAwareProviderV3 } = await import("../providers/function-calling-provider.js");
162
+ provider = createMCPAwareProviderV3(provider, {
163
+ providerName,
164
+ modelName: resolvedModelName || undefined,
165
+ enableMCP: true,
166
+ enableFunctionCalling: true,
167
+ });
168
+ logger.debug(`[${functionTag}] Provider wrapped with MCP support`);
170
169
  }
171
170
  catch (mcpError) {
172
171
  logger.warn(`[${functionTag}] Failed to wrap with MCP, using base provider`, {