@juspay/neurolink 1.6.0 → 1.10.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.
- package/CHANGELOG.md +200 -7
- package/README.md +101 -18
- package/dist/agent/direct-tools.d.ts +1203 -0
- package/dist/agent/direct-tools.js +387 -0
- package/dist/cli/commands/agent-generate.d.ts +2 -0
- package/dist/cli/commands/agent-generate.js +70 -0
- package/dist/cli/commands/config.d.ts +6 -6
- package/dist/cli/commands/config.js +326 -273
- package/dist/cli/commands/mcp.d.ts +2 -1
- package/dist/cli/commands/mcp.js +874 -146
- package/dist/cli/commands/ollama.d.ts +1 -1
- package/dist/cli/commands/ollama.js +153 -143
- package/dist/cli/index.js +687 -325
- package/dist/cli/utils/complete-setup.d.ts +19 -0
- package/dist/cli/utils/complete-setup.js +81 -0
- package/dist/cli/utils/env-manager.d.ts +44 -0
- package/dist/cli/utils/env-manager.js +226 -0
- package/dist/cli/utils/interactive-setup.d.ts +48 -0
- package/dist/cli/utils/interactive-setup.js +302 -0
- package/dist/core/dynamic-models.d.ts +208 -0
- package/dist/core/dynamic-models.js +250 -0
- package/dist/core/factory.d.ts +13 -6
- package/dist/core/factory.js +177 -62
- package/dist/core/types.d.ts +4 -2
- package/dist/core/types.js +4 -4
- package/dist/index.d.ts +16 -16
- package/dist/index.js +16 -16
- package/dist/lib/agent/direct-tools.d.ts +1203 -0
- package/dist/lib/agent/direct-tools.js +387 -0
- package/dist/lib/core/dynamic-models.d.ts +208 -0
- package/dist/lib/core/dynamic-models.js +250 -0
- package/dist/lib/core/factory.d.ts +13 -6
- package/dist/lib/core/factory.js +177 -62
- package/dist/lib/core/types.d.ts +4 -2
- package/dist/lib/core/types.js +4 -4
- package/dist/lib/index.d.ts +16 -16
- package/dist/lib/index.js +16 -16
- package/dist/lib/mcp/auto-discovery.d.ts +120 -0
- package/dist/lib/mcp/auto-discovery.js +793 -0
- package/dist/lib/mcp/client.d.ts +66 -0
- package/dist/lib/mcp/client.js +245 -0
- package/dist/lib/mcp/config.d.ts +31 -0
- package/dist/lib/mcp/config.js +74 -0
- package/dist/lib/mcp/context-manager.d.ts +4 -4
- package/dist/lib/mcp/context-manager.js +24 -18
- package/dist/lib/mcp/factory.d.ts +28 -11
- package/dist/lib/mcp/factory.js +36 -29
- package/dist/lib/mcp/function-calling.d.ts +51 -0
- package/dist/lib/mcp/function-calling.js +510 -0
- package/dist/lib/mcp/index.d.ts +190 -0
- package/dist/lib/mcp/index.js +156 -0
- package/dist/lib/mcp/initialize-tools.d.ts +28 -0
- package/dist/lib/mcp/initialize-tools.js +209 -0
- package/dist/lib/mcp/initialize.d.ts +17 -0
- package/dist/lib/mcp/initialize.js +51 -0
- package/dist/lib/mcp/logging.d.ts +71 -0
- package/dist/lib/mcp/logging.js +183 -0
- package/dist/lib/mcp/manager.d.ts +67 -0
- package/dist/lib/mcp/manager.js +176 -0
- package/dist/lib/mcp/neurolink-mcp-client.d.ts +96 -0
- package/dist/lib/mcp/neurolink-mcp-client.js +417 -0
- package/dist/lib/mcp/orchestrator.d.ts +3 -3
- package/dist/lib/mcp/orchestrator.js +46 -43
- package/dist/lib/mcp/registry.d.ts +12 -4
- package/dist/lib/mcp/registry.js +64 -37
- package/dist/lib/mcp/servers/ai-providers/ai-analysis-tools.d.ts +1 -1
- package/dist/lib/mcp/servers/ai-providers/ai-analysis-tools.js +204 -65
- package/dist/lib/mcp/servers/ai-providers/ai-core-server.js +142 -102
- package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.d.ts +6 -6
- package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.js +197 -142
- package/dist/lib/mcp/servers/utilities/utility-server.d.ts +8 -0
- package/dist/lib/mcp/servers/utilities/utility-server.js +326 -0
- package/dist/lib/mcp/tool-integration.d.ts +67 -0
- package/dist/lib/mcp/tool-integration.js +179 -0
- package/dist/lib/mcp/unified-registry.d.ts +269 -0
- package/dist/lib/mcp/unified-registry.js +1411 -0
- package/dist/lib/neurolink.d.ts +68 -6
- package/dist/lib/neurolink.js +304 -42
- package/dist/lib/providers/agent-enhanced-provider.d.ts +59 -0
- package/dist/lib/providers/agent-enhanced-provider.js +242 -0
- package/dist/lib/providers/amazonBedrock.d.ts +3 -3
- package/dist/lib/providers/amazonBedrock.js +54 -50
- package/dist/lib/providers/anthropic.d.ts +2 -2
- package/dist/lib/providers/anthropic.js +92 -84
- package/dist/lib/providers/azureOpenAI.d.ts +2 -2
- package/dist/lib/providers/azureOpenAI.js +97 -86
- package/dist/lib/providers/function-calling-provider.d.ts +70 -0
- package/dist/lib/providers/function-calling-provider.js +359 -0
- package/dist/lib/providers/googleAIStudio.d.ts +10 -5
- package/dist/lib/providers/googleAIStudio.js +60 -38
- package/dist/lib/providers/googleVertexAI.d.ts +3 -3
- package/dist/lib/providers/googleVertexAI.js +96 -86
- package/dist/lib/providers/huggingFace.d.ts +3 -3
- package/dist/lib/providers/huggingFace.js +70 -63
- package/dist/lib/providers/index.d.ts +11 -11
- package/dist/lib/providers/index.js +18 -18
- package/dist/lib/providers/mcp-provider.d.ts +62 -0
- package/dist/lib/providers/mcp-provider.js +183 -0
- package/dist/lib/providers/mistralAI.d.ts +3 -3
- package/dist/lib/providers/mistralAI.js +42 -36
- package/dist/lib/providers/ollama.d.ts +4 -4
- package/dist/lib/providers/ollama.js +128 -98
- package/dist/lib/providers/openAI.d.ts +7 -3
- package/dist/lib/providers/openAI.js +45 -33
- package/dist/lib/utils/logger.js +2 -2
- package/dist/lib/utils/providerUtils-fixed.d.ts +8 -0
- package/dist/lib/utils/providerUtils-fixed.js +75 -0
- package/dist/lib/utils/providerUtils.d.ts +8 -1
- package/dist/lib/utils/providerUtils.js +63 -32
- package/dist/mcp/auto-discovery.d.ts +120 -0
- package/dist/mcp/auto-discovery.js +794 -0
- package/dist/mcp/client.d.ts +66 -0
- package/dist/mcp/client.js +245 -0
- package/dist/mcp/config.d.ts +31 -0
- package/dist/mcp/config.js +74 -0
- package/dist/mcp/context-manager.d.ts +4 -4
- package/dist/mcp/context-manager.js +24 -18
- package/dist/mcp/factory.d.ts +28 -11
- package/dist/mcp/factory.js +36 -29
- package/dist/mcp/function-calling.d.ts +51 -0
- package/dist/mcp/function-calling.js +510 -0
- package/dist/mcp/index.d.ts +190 -0
- package/dist/mcp/index.js +156 -0
- package/dist/mcp/initialize-tools.d.ts +28 -0
- package/dist/mcp/initialize-tools.js +210 -0
- package/dist/mcp/initialize.d.ts +17 -0
- package/dist/mcp/initialize.js +51 -0
- package/dist/mcp/logging.d.ts +71 -0
- package/dist/mcp/logging.js +183 -0
- package/dist/mcp/manager.d.ts +67 -0
- package/dist/mcp/manager.js +176 -0
- package/dist/mcp/neurolink-mcp-client.d.ts +96 -0
- package/dist/mcp/neurolink-mcp-client.js +417 -0
- package/dist/mcp/orchestrator.d.ts +3 -3
- package/dist/mcp/orchestrator.js +46 -43
- package/dist/mcp/registry.d.ts +12 -4
- package/dist/mcp/registry.js +64 -37
- package/dist/mcp/servers/ai-providers/ai-analysis-tools.d.ts +1 -1
- package/dist/mcp/servers/ai-providers/ai-analysis-tools.js +204 -65
- package/dist/mcp/servers/ai-providers/ai-core-server.js +142 -102
- package/dist/mcp/servers/ai-providers/ai-workflow-tools.d.ts +6 -6
- package/dist/mcp/servers/ai-providers/ai-workflow-tools.js +197 -142
- package/dist/mcp/servers/utilities/utility-server.d.ts +8 -0
- package/dist/mcp/servers/utilities/utility-server.js +326 -0
- package/dist/mcp/tool-integration.d.ts +67 -0
- package/dist/mcp/tool-integration.js +179 -0
- package/dist/mcp/unified-registry.d.ts +269 -0
- package/dist/mcp/unified-registry.js +1411 -0
- package/dist/neurolink.d.ts +68 -6
- package/dist/neurolink.js +304 -42
- package/dist/providers/agent-enhanced-provider.d.ts +59 -0
- package/dist/providers/agent-enhanced-provider.js +242 -0
- package/dist/providers/amazonBedrock.d.ts +3 -3
- package/dist/providers/amazonBedrock.js +54 -50
- package/dist/providers/anthropic.d.ts +2 -2
- package/dist/providers/anthropic.js +92 -84
- package/dist/providers/azureOpenAI.d.ts +2 -2
- package/dist/providers/azureOpenAI.js +97 -86
- package/dist/providers/function-calling-provider.d.ts +70 -0
- package/dist/providers/function-calling-provider.js +359 -0
- package/dist/providers/googleAIStudio.d.ts +10 -5
- package/dist/providers/googleAIStudio.js +60 -38
- package/dist/providers/googleVertexAI.d.ts +3 -3
- package/dist/providers/googleVertexAI.js +96 -86
- package/dist/providers/huggingFace.d.ts +3 -3
- package/dist/providers/huggingFace.js +70 -63
- package/dist/providers/index.d.ts +11 -11
- package/dist/providers/index.js +18 -18
- package/dist/providers/mcp-provider.d.ts +62 -0
- package/dist/providers/mcp-provider.js +183 -0
- package/dist/providers/mistralAI.d.ts +3 -3
- package/dist/providers/mistralAI.js +42 -36
- package/dist/providers/ollama.d.ts +4 -4
- package/dist/providers/ollama.js +128 -98
- package/dist/providers/openAI.d.ts +7 -3
- package/dist/providers/openAI.js +45 -33
- package/dist/utils/logger.js +2 -2
- package/dist/utils/providerUtils-fixed.d.ts +8 -0
- package/dist/utils/providerUtils-fixed.js +75 -0
- package/dist/utils/providerUtils.d.ts +8 -1
- package/dist/utils/providerUtils.js +63 -32
- package/package.json +182 -160
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
|
|
10
|
-
import yargs from
|
|
11
|
-
import { hideBin } from
|
|
12
|
-
import ora from
|
|
13
|
-
import chalk from
|
|
14
|
-
import fs from
|
|
15
|
-
import { addMCPCommands } from
|
|
16
|
-
import ollamaCommand from
|
|
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(
|
|
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
|
-
|
|
43
|
-
const originalErrorMessageLowerCase = error.message
|
|
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(
|
|
48
|
-
originalErrorMessageLowerCase.includes(
|
|
49
|
-
originalErrorMessageLowerCase.includes(
|
|
50
|
-
originalErrorMessageLowerCase.includes(
|
|
51
|
-
originalErrorMessageLowerCase.includes(
|
|
52
|
-
originalErrorMessageLowerCase.includes(
|
|
53
|
-
originalErrorMessageLowerCase.includes(
|
|
54
|
-
originalErrorMessageLowerCase.includes(
|
|
55
|
-
originalErrorMessageLowerCase.includes(
|
|
56
|
-
originalErrorMessageLowerCase.includes(
|
|
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 (
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
errorStringLowerCase.includes(
|
|
63
|
-
errorStringLowerCase.includes(
|
|
64
|
-
errorStringLowerCase.includes(
|
|
65
|
-
errorStringLowerCase.includes(
|
|
66
|
-
errorStringLowerCase.includes(
|
|
67
|
-
errorStringLowerCase.includes(
|
|
68
|
-
errorStringLowerCase.includes(
|
|
69
|
-
errorStringLowerCase.includes(
|
|
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 =
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
originalErrorMessageLowerCase.includes(
|
|
78
|
-
originalErrorMessageLowerCase.includes(
|
|
79
|
-
originalErrorMessageLowerCase.includes(
|
|
80
|
-
originalErrorMessageLowerCase.includes(
|
|
81
|
-
|
|
82
|
-
errorStringLowerCase.includes(
|
|
83
|
-
errorStringLowerCase.includes(
|
|
84
|
-
errorStringLowerCase.includes(
|
|
85
|
-
errorStringLowerCase.includes(
|
|
86
|
-
errorStringLowerCase.includes(
|
|
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 =
|
|
80
|
+
genericMessage =
|
|
81
|
+
"Network error: Could not connect to the API endpoint or the request timed out.";
|
|
89
82
|
}
|
|
90
|
-
else if (errorStringLowerCase.includes(
|
|
91
|
-
|
|
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(
|
|
97
|
-
|
|
98
|
-
console.error(chalk.yellow(
|
|
99
|
-
console.error(chalk.yellow(
|
|
100
|
-
console.error(chalk.yellow(
|
|
101
|
-
console.error(chalk.yellow(
|
|
102
|
-
console.error(chalk.yellow(
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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(
|
|
140
|
-
.usage(
|
|
116
|
+
.scriptName("neurolink")
|
|
117
|
+
.usage("Usage: $0 <command> [options]")
|
|
141
118
|
.version()
|
|
142
119
|
.help()
|
|
143
|
-
.alias(
|
|
144
|
-
.alias(
|
|
120
|
+
.alias("h", "help")
|
|
121
|
+
.alias("V", "version")
|
|
145
122
|
.strictOptions()
|
|
146
123
|
.strictCommands()
|
|
147
|
-
.demandCommand(1,
|
|
148
|
-
.epilogue(
|
|
149
|
-
.showHelpOnFail(true,
|
|
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 =
|
|
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 =
|
|
134
|
+
process.env.NEUROLINK_DEBUG = "false";
|
|
158
135
|
}
|
|
159
136
|
// Keep existing quiet middleware
|
|
160
|
-
if (process.env.NEUROLINK_QUIET ===
|
|
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(
|
|
179
|
-
!err.message.includes(
|
|
180
|
-
!err.message.includes(
|
|
181
|
-
!err.message.includes(
|
|
182
|
-
!err.message.includes(
|
|
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 ||
|
|
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 => {
|
|
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(
|
|
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 => {
|
|
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(
|
|
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 => {
|
|
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([
|
|
216
|
-
.usage(
|
|
217
|
-
.positional(
|
|
218
|
-
type:
|
|
219
|
-
description:
|
|
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(
|
|
223
|
-
choices: [
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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 ===
|
|
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] ===
|
|
273
|
+
if (typeof console[key] === "function") {
|
|
240
274
|
console[key] = () => { };
|
|
241
275
|
}
|
|
242
276
|
});
|
|
243
277
|
}
|
|
244
|
-
const spinner = argv.format ===
|
|
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,
|
|
251
|
-
provider: 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([
|
|
257
|
-
|
|
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(
|
|
262
|
-
|
|
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 ||
|
|
265
|
-
|
|
266
|
-
|
|
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) +
|
|
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(
|
|
274
|
-
|
|
275
|
-
|
|
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 ===
|
|
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
|
-
|
|
293
|
-
|
|
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,
|
|
355
|
+
handleError(error, "Text generation");
|
|
298
356
|
}
|
|
299
357
|
}
|
|
300
358
|
})
|
|
301
359
|
// Stream Text Command
|
|
302
|
-
.command(
|
|
303
|
-
.usage(
|
|
304
|
-
.positional(
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
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(
|
|
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,545 @@ const cli = yargs(args)
|
|
|
317
402
|
try {
|
|
318
403
|
const stream = await sdk.generateTextStream({
|
|
319
404
|
prompt: argv.prompt,
|
|
320
|
-
provider: argv.provider ===
|
|
321
|
-
|
|
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(
|
|
415
|
+
if (!argv.quiet) {
|
|
416
|
+
process.stdout.write("\n");
|
|
417
|
+
} // Ensure newline after stream
|
|
330
418
|
}
|
|
331
419
|
catch (error) {
|
|
332
|
-
handleError(error,
|
|
420
|
+
handleError(error, "Text streaming");
|
|
333
421
|
}
|
|
334
422
|
})
|
|
335
423
|
// Batch Processing Command
|
|
336
|
-
.command(
|
|
337
|
-
.usage(
|
|
338
|
-
.positional(
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
.option(
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
.
|
|
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(
|
|
355
|
-
(!buffer.toString(
|
|
356
|
-
|
|
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
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
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
|
-
|
|
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(
|
|
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 ===
|
|
374
|
-
|
|
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([
|
|
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();
|
|
527
|
+
if (spinner) {
|
|
528
|
+
spinner.render();
|
|
529
|
+
} // Update spinner without changing text
|
|
380
530
|
}
|
|
381
531
|
catch (error) {
|
|
382
|
-
results.push({
|
|
383
|
-
|
|
532
|
+
results.push({
|
|
533
|
+
prompt: prompts[i],
|
|
534
|
+
error: error.message,
|
|
535
|
+
});
|
|
536
|
+
if (spinner) {
|
|
384
537
|
spinner.render();
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
if (argv.delay && i < prompts.length - 1) {
|
|
541
|
+
await new Promise((resolve) => setTimeout(resolve, argv.delay));
|
|
385
542
|
}
|
|
386
|
-
if (argv.delay && i < prompts.length - 1)
|
|
387
|
-
await new Promise(resolve => setTimeout(resolve, argv.delay));
|
|
388
543
|
}
|
|
389
|
-
if (spinner)
|
|
390
|
-
spinner.succeed(chalk.green(
|
|
544
|
+
if (spinner) {
|
|
545
|
+
spinner.succeed(chalk.green("✅ Batch processing complete!"));
|
|
546
|
+
}
|
|
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 +
|
|
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
|
-
|
|
561
|
+
}
|
|
562
|
+
handleError(error, "Batch processing");
|
|
405
563
|
}
|
|
406
564
|
})
|
|
407
565
|
// Provider Command Group (Corrected Structure)
|
|
408
|
-
.command(
|
|
566
|
+
.command("provider <subcommand>", "Manage AI provider configurations and status", (yargsProvider) => {
|
|
567
|
+
// Builder for the main 'provider' command
|
|
409
568
|
yargsProvider
|
|
410
|
-
.usage(
|
|
411
|
-
.command(
|
|
412
|
-
.usage(
|
|
413
|
-
.option(
|
|
414
|
-
|
|
415
|
-
|
|
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(
|
|
580
|
+
console.log(chalk.yellow("ℹ️ Verbose mode enabled. Displaying detailed status.\n")); // Added newline
|
|
418
581
|
}
|
|
419
|
-
const spinner = argv.quiet
|
|
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 = [
|
|
587
|
+
const providers = [
|
|
588
|
+
"openai",
|
|
589
|
+
"bedrock",
|
|
590
|
+
"vertex",
|
|
591
|
+
"anthropic",
|
|
592
|
+
"azure",
|
|
593
|
+
"google-ai",
|
|
594
|
+
"huggingface",
|
|
595
|
+
"ollama",
|
|
596
|
+
"mistral",
|
|
597
|
+
];
|
|
598
|
+
// Import hasProviderEnvVars to check environment variables
|
|
599
|
+
const { hasProviderEnvVars } = await import("../lib/utils/providerUtils.js");
|
|
423
600
|
const results = [];
|
|
424
601
|
for (const p of providers) {
|
|
425
|
-
if (spinner)
|
|
602
|
+
if (spinner) {
|
|
426
603
|
spinner.text = `Testing ${p}...`;
|
|
604
|
+
}
|
|
605
|
+
// First check if provider has env vars configured
|
|
606
|
+
const hasEnvVars = hasProviderEnvVars(p);
|
|
607
|
+
if (!hasEnvVars && p !== "ollama") {
|
|
608
|
+
// No env vars, don't even try to test
|
|
609
|
+
results.push({
|
|
610
|
+
provider: p,
|
|
611
|
+
status: "not-configured",
|
|
612
|
+
configured: false,
|
|
613
|
+
error: "Missing required environment variables",
|
|
614
|
+
});
|
|
615
|
+
if (spinner) {
|
|
616
|
+
spinner.fail(`${p}: ${chalk.gray("⚪ Not configured")} - Missing environment variables`);
|
|
617
|
+
}
|
|
618
|
+
else if (!argv.quiet) {
|
|
619
|
+
console.log(`${p}: ${chalk.gray("⚪ Not configured")} - Missing environment variables`);
|
|
620
|
+
}
|
|
621
|
+
continue;
|
|
622
|
+
}
|
|
623
|
+
// Special handling for Ollama
|
|
624
|
+
if (p === "ollama") {
|
|
625
|
+
try {
|
|
626
|
+
// 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)
|
|
630
|
+
});
|
|
631
|
+
if (!serviceResponse.ok) {
|
|
632
|
+
throw new Error("Ollama service not responding");
|
|
633
|
+
}
|
|
634
|
+
// Service is running, now check if the default model is available
|
|
635
|
+
const { models } = await serviceResponse.json();
|
|
636
|
+
const defaultOllamaModel = "llama3.2:latest";
|
|
637
|
+
const modelIsAvailable = models.some((m) => m.name === defaultOllamaModel);
|
|
638
|
+
if (modelIsAvailable) {
|
|
639
|
+
results.push({
|
|
640
|
+
provider: p,
|
|
641
|
+
status: "working",
|
|
642
|
+
configured: true,
|
|
643
|
+
authenticated: true,
|
|
644
|
+
responseTime: 0,
|
|
645
|
+
});
|
|
646
|
+
if (spinner) {
|
|
647
|
+
spinner.succeed(`${p}: ${chalk.green("✅ Working")} - Service running and model '${defaultOllamaModel}' is available.`);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
else {
|
|
651
|
+
results.push({
|
|
652
|
+
provider: p,
|
|
653
|
+
status: "failed",
|
|
654
|
+
configured: true,
|
|
655
|
+
authenticated: false,
|
|
656
|
+
error: `Ollama service is running, but model '${defaultOllamaModel}' is not found. Please run 'ollama pull ${defaultOllamaModel}'.`,
|
|
657
|
+
});
|
|
658
|
+
if (spinner) {
|
|
659
|
+
spinner.fail(`${p}: ${chalk.red("❌ Model Not Found")} - Run 'ollama pull ${defaultOllamaModel}'`);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
catch (error) {
|
|
664
|
+
results.push({
|
|
665
|
+
provider: p,
|
|
666
|
+
status: "failed",
|
|
667
|
+
configured: false,
|
|
668
|
+
authenticated: false,
|
|
669
|
+
error: "Ollama is not running. Please start with: ollama serve",
|
|
670
|
+
});
|
|
671
|
+
if (spinner) {
|
|
672
|
+
spinner.fail(`${p}: ${chalk.red("❌ Failed")} - Service not running`);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
continue;
|
|
676
|
+
}
|
|
677
|
+
// Provider has env vars, now test authentication
|
|
427
678
|
try {
|
|
428
679
|
const start = Date.now();
|
|
429
|
-
|
|
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({
|
|
685
|
+
prompt: "test",
|
|
686
|
+
maxTokens: 1,
|
|
687
|
+
});
|
|
430
688
|
const duration = Date.now() - start;
|
|
431
|
-
results.push({
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
689
|
+
results.push({
|
|
690
|
+
provider: p,
|
|
691
|
+
status: "working",
|
|
692
|
+
configured: true,
|
|
693
|
+
authenticated: true,
|
|
694
|
+
responseTime: duration,
|
|
695
|
+
});
|
|
696
|
+
if (spinner) {
|
|
697
|
+
spinner.succeed(`${p}: ${chalk.green("✅ Working")} (${duration}ms)`);
|
|
698
|
+
}
|
|
699
|
+
else if (!argv.quiet) {
|
|
700
|
+
console.log(`${p}: ${chalk.green("✅ Working")} (${duration}ms)`);
|
|
701
|
+
}
|
|
436
702
|
}
|
|
437
703
|
catch (error) {
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
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
|
+
}
|
|
717
|
+
results.push({
|
|
718
|
+
provider: p,
|
|
719
|
+
status: "failed",
|
|
720
|
+
configured: true,
|
|
721
|
+
authenticated: authStatus,
|
|
722
|
+
error: errorMsg,
|
|
723
|
+
});
|
|
724
|
+
if (spinner) {
|
|
725
|
+
spinner.fail(`${p}: ${chalk.red("❌ " + statusText)} - ${errorMsg.split("\n")[0]}`);
|
|
726
|
+
}
|
|
727
|
+
else if (!argv.quiet) {
|
|
728
|
+
console.error(`${p}: ${chalk.red("❌ " + statusText)} - ${errorMsg.split("\n")[0]}`);
|
|
729
|
+
}
|
|
443
730
|
}
|
|
444
731
|
}
|
|
445
|
-
const working = results.filter(r => r.status ===
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
732
|
+
const working = results.filter((r) => r.status === "working").length;
|
|
733
|
+
const configured = results.filter((r) => r.configured).length;
|
|
734
|
+
if (spinner) {
|
|
735
|
+
spinner.info(chalk.blue(`\n📊 Summary: ${working}/${results.length} providers working, ${configured}/${results.length} configured`));
|
|
736
|
+
}
|
|
737
|
+
else if (!argv.quiet) {
|
|
738
|
+
console.log(chalk.blue(`\n📊 Summary: ${working}/${results.length} providers working, ${configured}/${results.length} configured`));
|
|
739
|
+
}
|
|
450
740
|
if (argv.verbose && !argv.quiet) {
|
|
451
|
-
console.log(chalk.blue(
|
|
741
|
+
console.log(chalk.blue("\n📋 Detailed Results:"));
|
|
452
742
|
console.log(JSON.stringify(results, null, 2));
|
|
453
743
|
}
|
|
454
744
|
})
|
|
455
|
-
.command(
|
|
456
|
-
console.log(
|
|
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");
|
|
457
747
|
})
|
|
458
|
-
.command(
|
|
459
|
-
.usage(
|
|
460
|
-
.positional(
|
|
461
|
-
type:
|
|
462
|
-
choices: [
|
|
463
|
-
|
|
748
|
+
.command("configure <providerName>", "Display configuration guidance for a provider", (y) => y
|
|
749
|
+
.usage("Usage: $0 provider configure <providerName>")
|
|
750
|
+
.positional("providerName", {
|
|
751
|
+
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",
|
|
464
764
|
demandOption: true,
|
|
465
765
|
})
|
|
466
|
-
.example(
|
|
766
|
+
.example("$0 provider configure openai", "Show OpenAI configuration help"), async (argv) => {
|
|
467
767
|
console.log(chalk.blue(`\n🔧 Configuration guidance for ${chalk.bold(argv.providerName)}:`));
|
|
468
|
-
console.log(chalk.yellow(
|
|
469
|
-
console.log(chalk.gray(
|
|
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"));
|
|
470
770
|
})
|
|
471
|
-
.demandCommand(1,
|
|
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
|
-
)
|
|
771
|
+
.demandCommand(1, "Please specify a provider subcommand (status, list, or configure).");
|
|
772
|
+
})
|
|
477
773
|
// Status Command (Standalone, for backward compatibility or direct access)
|
|
478
|
-
.command(
|
|
479
|
-
.usage(
|
|
480
|
-
.option(
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
.example(
|
|
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) => {
|
|
487
784
|
// This logic is duplicated from 'provider status' for the alias
|
|
488
785
|
if (argv.verbose && !argv.quiet) {
|
|
489
|
-
console.log(chalk.yellow(
|
|
786
|
+
console.log(chalk.yellow("ℹ️ Verbose mode enabled. Displaying detailed status.\n")); // Added newline
|
|
490
787
|
}
|
|
491
|
-
const spinner = argv.quiet
|
|
788
|
+
const spinner = argv.quiet
|
|
789
|
+
? null
|
|
790
|
+
: ora("🔍 Checking AI provider status...\n").start();
|
|
492
791
|
// Middleware sets argv.verbose if NEUROLINK_DEBUG is true and --verbose is not specified
|
|
493
792
|
// Removed the spinner.stopAndPersist logic from here as it's handled before spinner start
|
|
494
|
-
const providers = [
|
|
793
|
+
const providers = [
|
|
794
|
+
"openai",
|
|
795
|
+
"bedrock",
|
|
796
|
+
"vertex",
|
|
797
|
+
"anthropic",
|
|
798
|
+
"azure",
|
|
799
|
+
"google-ai",
|
|
800
|
+
"huggingface",
|
|
801
|
+
"ollama",
|
|
802
|
+
"mistral",
|
|
803
|
+
];
|
|
495
804
|
const results = [];
|
|
496
805
|
for (const p of providers) {
|
|
497
|
-
if (spinner)
|
|
806
|
+
if (spinner) {
|
|
498
807
|
spinner.text = `Testing ${p}...`;
|
|
808
|
+
}
|
|
499
809
|
try {
|
|
500
810
|
const start = Date.now();
|
|
501
|
-
await sdk.generateText({ prompt:
|
|
811
|
+
await sdk.generateText({ prompt: "test", provider: p, maxTokens: 1 });
|
|
502
812
|
const duration = Date.now() - start;
|
|
503
|
-
results.push({
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
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)`);
|
|
820
|
+
}
|
|
821
|
+
else if (!argv.quiet) {
|
|
822
|
+
console.log(`${p}: ${chalk.green("✅ Working")} (${duration}ms)`);
|
|
823
|
+
}
|
|
508
824
|
}
|
|
509
825
|
catch (error) {
|
|
510
|
-
results.push({
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
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
|
+
}
|
|
515
837
|
}
|
|
516
838
|
}
|
|
517
|
-
const working = results.filter(r => r.status ===
|
|
518
|
-
if (spinner)
|
|
839
|
+
const working = results.filter((r) => r.status === "working").length;
|
|
840
|
+
if (spinner) {
|
|
519
841
|
spinner.info(chalk.blue(`\n📊 Summary: ${working}/${results.length} providers working`));
|
|
520
|
-
|
|
842
|
+
}
|
|
843
|
+
else if (!argv.quiet) {
|
|
521
844
|
console.log(chalk.blue(`\n📊 Summary: ${working}/${results.length} providers working`));
|
|
845
|
+
}
|
|
522
846
|
if (argv.verbose && !argv.quiet) {
|
|
523
|
-
console.log(chalk.blue(
|
|
847
|
+
console.log(chalk.blue("\n📋 Detailed Results:"));
|
|
524
848
|
console.log(JSON.stringify(results, null, 2));
|
|
525
849
|
}
|
|
526
850
|
})
|
|
527
851
|
// Configuration Commands Refactored
|
|
528
|
-
.command(
|
|
852
|
+
.command("config <subcommand>", "Manage NeuroLink configuration", (yargsConfig) => {
|
|
529
853
|
yargsConfig
|
|
530
|
-
.usage(
|
|
531
|
-
.command(
|
|
532
|
-
|
|
533
|
-
|
|
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",
|
|
534
861
|
})
|
|
535
|
-
.
|
|
536
|
-
|
|
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);
|
|
537
866
|
})
|
|
538
|
-
.command(
|
|
539
|
-
|
|
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...");
|
|
540
881
|
// Actual show logic here
|
|
541
882
|
})
|
|
542
|
-
.command(
|
|
543
|
-
.positional(
|
|
544
|
-
|
|
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) => {
|
|
545
894
|
console.log(`Config set: Key: ${argv.key}, Value: ${argv.value}`);
|
|
546
895
|
// Actual set logic here
|
|
547
896
|
})
|
|
548
|
-
.command(
|
|
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) => {
|
|
549
902
|
console.log(`Config import: Importing from ${argv.file}`);
|
|
550
|
-
if (argv.file.includes(
|
|
551
|
-
handleError(new Error(
|
|
903
|
+
if (argv.file.includes("invalid-config.json")) {
|
|
904
|
+
handleError(new Error("Invalid or unparseable JSON in config file."), "Config import");
|
|
552
905
|
}
|
|
553
906
|
// Actual import logic here
|
|
554
907
|
})
|
|
555
|
-
.command(
|
|
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) => {
|
|
556
913
|
console.log(`Config export: Exporting to ${argv.file}`);
|
|
557
|
-
if (argv.file.includes(
|
|
558
|
-
handleError(new Error(
|
|
914
|
+
if (argv.file.includes("read-only-dir")) {
|
|
915
|
+
handleError(new Error("Permission denied. Cannot write to read-only directory."), "Config export");
|
|
559
916
|
}
|
|
560
917
|
// Actual export logic here
|
|
561
918
|
})
|
|
562
|
-
.command(
|
|
563
|
-
console.log(
|
|
919
|
+
.command("validate", "Validate the current configuration", () => { }, async (argv) => {
|
|
920
|
+
console.log("Config validate: Validating configuration...");
|
|
564
921
|
// Actual validation logic here
|
|
565
922
|
})
|
|
566
|
-
.command(
|
|
567
|
-
console.log(
|
|
923
|
+
.command("reset", "Reset NeuroLink configuration to defaults", () => { }, async (argv) => {
|
|
924
|
+
console.log("Config reset: Resetting configuration...");
|
|
568
925
|
// Actual reset logic here
|
|
569
926
|
})
|
|
570
|
-
.demandCommand(1,
|
|
571
|
-
.example(
|
|
572
|
-
.example(
|
|
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
|
-
)
|
|
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)");
|
|
930
|
+
})
|
|
578
931
|
// Get Best Provider Command
|
|
579
|
-
.command(
|
|
580
|
-
.usage(
|
|
581
|
-
.option(
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
932
|
+
.command("get-best-provider", "Show the best available AI provider", (yargsInstance) => yargsInstance
|
|
933
|
+
.usage("Usage: $0 get-best-provider [options]")
|
|
934
|
+
.option("debug", {
|
|
935
|
+
type: "boolean",
|
|
936
|
+
default: false,
|
|
937
|
+
description: "Enable debug mode with selection reasoning",
|
|
938
|
+
})
|
|
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();
|
|
585
944
|
try {
|
|
586
945
|
const provider = await sdk.getBestProvider();
|
|
587
946
|
if (spinner) {
|
|
@@ -589,7 +948,7 @@ const cli = yargs(args)
|
|
|
589
948
|
spinner.succeed(chalk.green(`✅ Best provider selected: ${provider}`));
|
|
590
949
|
}
|
|
591
950
|
else {
|
|
592
|
-
spinner.succeed(chalk.green(
|
|
951
|
+
spinner.succeed(chalk.green("✅ Provider found"));
|
|
593
952
|
}
|
|
594
953
|
}
|
|
595
954
|
if (argv.debug) {
|
|
@@ -603,16 +962,19 @@ const cli = yargs(args)
|
|
|
603
962
|
}
|
|
604
963
|
}
|
|
605
964
|
catch (error) {
|
|
606
|
-
if (spinner && spinner.isSpinning)
|
|
965
|
+
if (spinner && spinner.isSpinning) {
|
|
607
966
|
spinner.fail();
|
|
608
|
-
|
|
967
|
+
}
|
|
968
|
+
handleError(error, "Provider selection");
|
|
609
969
|
}
|
|
610
970
|
})
|
|
611
|
-
.completion(
|
|
971
|
+
.completion("completion", "Generate shell completion script");
|
|
612
972
|
// Add MCP commands
|
|
613
973
|
addMCPCommands(cli);
|
|
614
974
|
// Add Ollama command
|
|
615
975
|
cli.command(ollamaCommand);
|
|
976
|
+
// Add Agent-Generate command
|
|
977
|
+
cli.command(agentGenerateCommand);
|
|
616
978
|
// Use an async IIFE to allow top-level await for parseAsync
|
|
617
979
|
(async () => {
|
|
618
980
|
try {
|