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