@juspay/neurolink 7.34.0 → 7.35.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 +6 -0
- package/README.md +64 -7
- package/dist/cli/commands/setup-anthropic.d.ts +16 -0
- package/dist/cli/commands/setup-anthropic.js +414 -0
- package/dist/cli/commands/setup-azure.d.ts +17 -0
- package/dist/cli/commands/setup-azure.js +415 -0
- package/dist/cli/commands/setup-bedrock.d.ts +13 -0
- package/dist/cli/commands/setup-bedrock.js +487 -0
- package/dist/cli/commands/setup-gcp.d.ts +18 -0
- package/dist/cli/commands/setup-gcp.js +569 -0
- package/dist/cli/commands/setup-google-ai.d.ts +16 -0
- package/dist/cli/commands/setup-google-ai.js +369 -0
- package/dist/cli/commands/setup-huggingface.d.ts +8 -0
- package/dist/cli/commands/setup-huggingface.js +200 -0
- package/dist/cli/commands/setup-mistral.d.ts +8 -0
- package/dist/cli/commands/setup-mistral.js +233 -0
- package/dist/cli/commands/setup-openai.d.ts +16 -0
- package/dist/cli/commands/setup-openai.js +402 -0
- package/dist/cli/commands/setup.d.ts +19 -0
- package/dist/cli/commands/setup.js +539 -0
- package/dist/cli/factories/commandFactory.d.ts +4 -0
- package/dist/cli/factories/commandFactory.js +41 -0
- package/dist/cli/factories/setupCommandFactory.d.ts +18 -0
- package/dist/cli/factories/setupCommandFactory.js +137 -0
- package/dist/cli/parser.js +4 -1
- package/dist/cli/utils/envManager.d.ts +3 -2
- package/dist/cli/utils/envManager.js +18 -4
- package/package.json +1 -1
@@ -0,0 +1,415 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
/**
|
3
|
+
* Azure OpenAI Setup Command
|
4
|
+
*
|
5
|
+
* Setup for Azure OpenAI integration:
|
6
|
+
* - AZURE_OPENAI_API_KEY (required)
|
7
|
+
* - AZURE_OPENAI_ENDPOINT (required)
|
8
|
+
* - AZURE_OPENAI_MODEL (optional)
|
9
|
+
*
|
10
|
+
* Follows the same UX patterns as other setup commands
|
11
|
+
*/
|
12
|
+
import inquirer from "inquirer";
|
13
|
+
import chalk from "chalk";
|
14
|
+
import ora from "ora";
|
15
|
+
import { logger } from "../../lib/utils/logger.js";
|
16
|
+
import { updateEnvFile as updateEnvFileShared, displayEnvUpdateSummary, } from "../utils/envManager.js";
|
17
|
+
export async function handleAzureSetup(argv) {
|
18
|
+
try {
|
19
|
+
const options = {
|
20
|
+
checkOnly: argv.check || false,
|
21
|
+
interactive: !argv.nonInteractive,
|
22
|
+
};
|
23
|
+
logger.always(chalk.blue("🔍 Checking Azure OpenAI configuration..."));
|
24
|
+
// Step 1: Check for existing configuration
|
25
|
+
const hasApiKey = !!process.env.AZURE_OPENAI_API_KEY;
|
26
|
+
const hasEndpoint = !!process.env.AZURE_OPENAI_ENDPOINT;
|
27
|
+
const hasModel = !!process.env.AZURE_OPENAI_MODEL;
|
28
|
+
// Display current status
|
29
|
+
displayCurrentStatus(hasApiKey, hasEndpoint, hasModel);
|
30
|
+
// Check-only mode - show status and exit
|
31
|
+
if (options.checkOnly) {
|
32
|
+
if (hasApiKey && hasEndpoint) {
|
33
|
+
logger.always(chalk.green("✅ Azure OpenAI setup complete"));
|
34
|
+
const apiKey = process.env.AZURE_OPENAI_API_KEY;
|
35
|
+
if (apiKey) {
|
36
|
+
logger.always(` API Key: ${maskCredential(apiKey)}`);
|
37
|
+
}
|
38
|
+
logger.always(` Endpoint: ${process.env.AZURE_OPENAI_ENDPOINT}`);
|
39
|
+
if (hasModel) {
|
40
|
+
logger.always(` Model: ${process.env.AZURE_OPENAI_MODEL}`);
|
41
|
+
}
|
42
|
+
else {
|
43
|
+
logger.always(" Model: (using deployment default)");
|
44
|
+
}
|
45
|
+
}
|
46
|
+
else {
|
47
|
+
logger.always(chalk.yellow("⚠️ Azure OpenAI setup incomplete"));
|
48
|
+
}
|
49
|
+
return;
|
50
|
+
}
|
51
|
+
const config = {};
|
52
|
+
// Step 2: Handle existing configuration
|
53
|
+
if (hasApiKey && hasEndpoint) {
|
54
|
+
logger.always(chalk.green("✅ Azure OpenAI credentials found in environment"));
|
55
|
+
const apiKey = process.env.AZURE_OPENAI_API_KEY;
|
56
|
+
if (apiKey) {
|
57
|
+
logger.always(` API Key: ${maskCredential(apiKey)}`);
|
58
|
+
}
|
59
|
+
logger.always(` Endpoint: ${process.env.AZURE_OPENAI_ENDPOINT}`);
|
60
|
+
if (hasModel) {
|
61
|
+
logger.always(` Model: ${process.env.AZURE_OPENAI_MODEL}`);
|
62
|
+
}
|
63
|
+
else {
|
64
|
+
logger.always(" Model: (using deployment default)");
|
65
|
+
}
|
66
|
+
if (options.interactive) {
|
67
|
+
const { reconfigure } = await inquirer.prompt([
|
68
|
+
{
|
69
|
+
type: "confirm",
|
70
|
+
name: "reconfigure",
|
71
|
+
message: "Azure OpenAI is already configured. Do you want to reconfigure?",
|
72
|
+
default: false,
|
73
|
+
},
|
74
|
+
]);
|
75
|
+
if (!reconfigure) {
|
76
|
+
// Still offer model selection if no model is set
|
77
|
+
if (!hasModel) {
|
78
|
+
const { wantsCustomModel } = await inquirer.prompt([
|
79
|
+
{
|
80
|
+
type: "confirm",
|
81
|
+
name: "wantsCustomModel",
|
82
|
+
message: "Do you want to specify an Azure OpenAI model? (optional)",
|
83
|
+
default: false,
|
84
|
+
},
|
85
|
+
]);
|
86
|
+
if (wantsCustomModel) {
|
87
|
+
config.model = await promptForModel();
|
88
|
+
}
|
89
|
+
}
|
90
|
+
else {
|
91
|
+
// Offer to change existing model
|
92
|
+
const { wantsChangeModel } = await inquirer.prompt([
|
93
|
+
{
|
94
|
+
type: "confirm",
|
95
|
+
name: "wantsChangeModel",
|
96
|
+
message: `Do you want to change the Azure OpenAI model? (current: ${process.env.AZURE_OPENAI_MODEL})`,
|
97
|
+
default: false,
|
98
|
+
},
|
99
|
+
]);
|
100
|
+
if (wantsChangeModel) {
|
101
|
+
config.model = await promptForModel();
|
102
|
+
}
|
103
|
+
}
|
104
|
+
if (config.model) {
|
105
|
+
await updateEnvFileWithConfig(config);
|
106
|
+
logger.always(chalk.green("✅ Model configuration updated!"));
|
107
|
+
logger.always(` AZURE_OPENAI_MODEL=${config.model}`);
|
108
|
+
}
|
109
|
+
else {
|
110
|
+
logger.always(chalk.blue("👍 Keeping existing configuration."));
|
111
|
+
}
|
112
|
+
// Show usage example
|
113
|
+
showUsageExample();
|
114
|
+
return;
|
115
|
+
}
|
116
|
+
else {
|
117
|
+
// User chose to reconfigure - mark this for proper handling
|
118
|
+
logger.always(chalk.blue("📝 Reconfiguring Azure OpenAI setup..."));
|
119
|
+
config.isReconfiguring = true;
|
120
|
+
}
|
121
|
+
}
|
122
|
+
else {
|
123
|
+
// Non-interactive mode - just use existing credentials
|
124
|
+
logger.always(chalk.green("✅ Setup complete! Using existing Azure OpenAI configuration."));
|
125
|
+
return;
|
126
|
+
}
|
127
|
+
}
|
128
|
+
// Step 3: Interactive setup for missing or reconfiguring credentials
|
129
|
+
if (options.interactive) {
|
130
|
+
const isReconfiguring = config.isReconfiguring === true;
|
131
|
+
// Handle API key setup/reconfiguration
|
132
|
+
if (!hasApiKey || isReconfiguring) {
|
133
|
+
if (!hasApiKey) {
|
134
|
+
// No API key exists - prompt for it
|
135
|
+
logger.always("");
|
136
|
+
logger.always(chalk.yellow("📋 To get your Azure OpenAI credentials:"));
|
137
|
+
logger.always("1. Visit: https://portal.azure.com/");
|
138
|
+
logger.always("2. Navigate to your Azure OpenAI resource");
|
139
|
+
logger.always("3. Go to 'Keys and Endpoint' section");
|
140
|
+
logger.always("4. Copy the API key and endpoint URL");
|
141
|
+
logger.always("");
|
142
|
+
}
|
143
|
+
else if (isReconfiguring) {
|
144
|
+
// Ask if they want to change the API key
|
145
|
+
const apiKey = process.env.AZURE_OPENAI_API_KEY;
|
146
|
+
const { wantsChangeApiKey } = await inquirer.prompt([
|
147
|
+
{
|
148
|
+
type: "confirm",
|
149
|
+
name: "wantsChangeApiKey",
|
150
|
+
message: `Do you want to change the Azure OpenAI API key? (current: ${apiKey ? maskCredential(apiKey) : "****"})`,
|
151
|
+
default: false,
|
152
|
+
},
|
153
|
+
]);
|
154
|
+
if (!wantsChangeApiKey) {
|
155
|
+
config.apiKey = undefined; // Don't update the API key
|
156
|
+
}
|
157
|
+
}
|
158
|
+
if (!hasApiKey || (isReconfiguring && config.apiKey !== undefined)) {
|
159
|
+
const { apiKey } = await inquirer.prompt([
|
160
|
+
{
|
161
|
+
type: "password",
|
162
|
+
name: "apiKey",
|
163
|
+
message: isReconfiguring
|
164
|
+
? "Enter your new Azure OpenAI API key:"
|
165
|
+
: "Enter your Azure OpenAI API key:",
|
166
|
+
validate: validateApiKey,
|
167
|
+
},
|
168
|
+
]);
|
169
|
+
config.apiKey = apiKey.trim();
|
170
|
+
}
|
171
|
+
}
|
172
|
+
// Handle endpoint setup/reconfiguration
|
173
|
+
if (!hasEndpoint || isReconfiguring) {
|
174
|
+
if (isReconfiguring && hasEndpoint) {
|
175
|
+
const { wantsChangeEndpoint } = await inquirer.prompt([
|
176
|
+
{
|
177
|
+
type: "confirm",
|
178
|
+
name: "wantsChangeEndpoint",
|
179
|
+
message: `Do you want to change the Azure OpenAI endpoint? (current: ${process.env.AZURE_OPENAI_ENDPOINT})`,
|
180
|
+
default: false,
|
181
|
+
},
|
182
|
+
]);
|
183
|
+
if (!wantsChangeEndpoint) {
|
184
|
+
config.endpoint = undefined; // Don't update the endpoint
|
185
|
+
}
|
186
|
+
}
|
187
|
+
if (!hasEndpoint ||
|
188
|
+
(isReconfiguring && config.endpoint !== undefined)) {
|
189
|
+
const { endpoint } = await inquirer.prompt([
|
190
|
+
{
|
191
|
+
type: "input",
|
192
|
+
name: "endpoint",
|
193
|
+
message: isReconfiguring
|
194
|
+
? "Enter your new Azure OpenAI endpoint URL:"
|
195
|
+
: "Enter your Azure OpenAI endpoint URL:",
|
196
|
+
validate: validateEndpoint,
|
197
|
+
},
|
198
|
+
]);
|
199
|
+
config.endpoint = endpoint.trim();
|
200
|
+
}
|
201
|
+
}
|
202
|
+
// Prompt for model selection
|
203
|
+
const { wantsCustomModel } = await inquirer.prompt([
|
204
|
+
{
|
205
|
+
type: "confirm",
|
206
|
+
name: "wantsCustomModel",
|
207
|
+
message: hasModel
|
208
|
+
? `Do you want to change the Azure OpenAI model? (current: ${process.env.AZURE_OPENAI_MODEL})`
|
209
|
+
: "Do you want to specify an Azure OpenAI model? (optional)",
|
210
|
+
default: false,
|
211
|
+
},
|
212
|
+
]);
|
213
|
+
if (wantsCustomModel) {
|
214
|
+
config.model = await promptForModel();
|
215
|
+
}
|
216
|
+
}
|
217
|
+
else {
|
218
|
+
// Non-interactive mode
|
219
|
+
logger.always(chalk.yellow("⚠️ Non-interactive mode: setup incomplete"));
|
220
|
+
logger.always(chalk.yellow("💡 Run without --non-interactive to configure Azure OpenAI"));
|
221
|
+
return;
|
222
|
+
}
|
223
|
+
// Step 4: Update .env file
|
224
|
+
if (config.apiKey || config.endpoint || config.model) {
|
225
|
+
await updateEnvFileWithConfig(config);
|
226
|
+
logger.always(chalk.green("✅ Azure OpenAI setup complete!"));
|
227
|
+
if (config.apiKey) {
|
228
|
+
logger.always(` API Key: ${maskCredential(config.apiKey)}`);
|
229
|
+
}
|
230
|
+
if (config.endpoint) {
|
231
|
+
logger.always(` Endpoint: ${config.endpoint}`);
|
232
|
+
}
|
233
|
+
if (config.model) {
|
234
|
+
logger.always(` Model: ${config.model}`);
|
235
|
+
}
|
236
|
+
// Show usage example
|
237
|
+
showUsageExample();
|
238
|
+
}
|
239
|
+
else if (options.interactive && !options.checkOnly) {
|
240
|
+
logger.always(chalk.green("✅ Setup complete!"));
|
241
|
+
showUsageExample();
|
242
|
+
}
|
243
|
+
}
|
244
|
+
catch (error) {
|
245
|
+
logger.error(chalk.red("❌ Azure OpenAI setup failed:"));
|
246
|
+
logger.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
|
247
|
+
process.exit(1);
|
248
|
+
}
|
249
|
+
}
|
250
|
+
/**
|
251
|
+
* Display current configuration status
|
252
|
+
*/
|
253
|
+
function displayCurrentStatus(hasApiKey, hasEndpoint, hasModel) {
|
254
|
+
if (hasApiKey) {
|
255
|
+
logger.always(chalk.green("✔ AZURE_OPENAI_API_KEY found in environment"));
|
256
|
+
}
|
257
|
+
else {
|
258
|
+
logger.always(chalk.red("✘ AZURE_OPENAI_API_KEY not found"));
|
259
|
+
}
|
260
|
+
if (hasEndpoint) {
|
261
|
+
logger.always(chalk.green(`✔ AZURE_OPENAI_ENDPOINT found: ${process.env.AZURE_OPENAI_ENDPOINT}`));
|
262
|
+
}
|
263
|
+
else {
|
264
|
+
logger.always(chalk.red("✘ AZURE_OPENAI_ENDPOINT not found"));
|
265
|
+
}
|
266
|
+
if (hasModel) {
|
267
|
+
logger.always(chalk.green(`✔ AZURE_OPENAI_MODEL found: ${process.env.AZURE_OPENAI_MODEL}`));
|
268
|
+
}
|
269
|
+
else {
|
270
|
+
logger.always(chalk.yellow("⚠ AZURE_OPENAI_MODEL not set (will use deployment default)"));
|
271
|
+
}
|
272
|
+
}
|
273
|
+
/**
|
274
|
+
* Validate Azure OpenAI API key format
|
275
|
+
*/
|
276
|
+
function validateApiKey(input) {
|
277
|
+
if (!input.trim()) {
|
278
|
+
return "Azure OpenAI API key is required";
|
279
|
+
}
|
280
|
+
const trimmed = input.trim();
|
281
|
+
if (trimmed.length < 20) {
|
282
|
+
return "Azure OpenAI API key seems too short";
|
283
|
+
}
|
284
|
+
// Azure OpenAI keys are typically 32 character hex strings
|
285
|
+
if (!/^[a-f0-9]{32}$/i.test(trimmed)) {
|
286
|
+
return "Azure OpenAI API key should be a 32-character hexadecimal string";
|
287
|
+
}
|
288
|
+
return true;
|
289
|
+
}
|
290
|
+
/**
|
291
|
+
* Validate Azure OpenAI endpoint URL
|
292
|
+
*/
|
293
|
+
function validateEndpoint(input) {
|
294
|
+
if (!input.trim()) {
|
295
|
+
return "Azure OpenAI endpoint URL is required";
|
296
|
+
}
|
297
|
+
const trimmed = input.trim();
|
298
|
+
try {
|
299
|
+
const url = new URL(trimmed);
|
300
|
+
if (!url.hostname.includes("openai.azure.com")) {
|
301
|
+
return "Endpoint should be an Azure OpenAI URL (*.openai.azure.com)";
|
302
|
+
}
|
303
|
+
return true;
|
304
|
+
}
|
305
|
+
catch {
|
306
|
+
return "Invalid URL format. Should be like: https://your-resource.openai.azure.com/";
|
307
|
+
}
|
308
|
+
}
|
309
|
+
/**
|
310
|
+
* Prompt user for model selection
|
311
|
+
*/
|
312
|
+
async function promptForModel() {
|
313
|
+
const { modelChoice } = await inquirer.prompt([
|
314
|
+
{
|
315
|
+
type: "list",
|
316
|
+
name: "modelChoice",
|
317
|
+
message: "Select an Azure OpenAI model:",
|
318
|
+
choices: [
|
319
|
+
{
|
320
|
+
name: "gpt-4o (Latest multimodal model)",
|
321
|
+
value: "gpt-4o",
|
322
|
+
},
|
323
|
+
{
|
324
|
+
name: "gpt-4o-mini (Cost-effective)",
|
325
|
+
value: "gpt-4o-mini",
|
326
|
+
},
|
327
|
+
{
|
328
|
+
name: "gpt-4-turbo (Previous generation)",
|
329
|
+
value: "gpt-4-turbo",
|
330
|
+
},
|
331
|
+
{
|
332
|
+
name: "gpt-35-turbo (Legacy, most cost-effective)",
|
333
|
+
value: "gpt-35-turbo",
|
334
|
+
},
|
335
|
+
{
|
336
|
+
name: "Custom deployment name (enter manually)",
|
337
|
+
value: "custom",
|
338
|
+
},
|
339
|
+
],
|
340
|
+
},
|
341
|
+
]);
|
342
|
+
if (modelChoice === "custom") {
|
343
|
+
const { customModel } = await inquirer.prompt([
|
344
|
+
{
|
345
|
+
type: "input",
|
346
|
+
name: "customModel",
|
347
|
+
message: "Enter your Azure OpenAI deployment name:",
|
348
|
+
validate: (input) => {
|
349
|
+
if (!input.trim()) {
|
350
|
+
return "Deployment name is required";
|
351
|
+
}
|
352
|
+
// Basic validation - Azure deployment names are alphanumeric with hyphens
|
353
|
+
const trimmed = input.trim();
|
354
|
+
if (!/^[a-z0-9-]+$/i.test(trimmed)) {
|
355
|
+
return "Deployment name should contain only letters, numbers, and hyphens";
|
356
|
+
}
|
357
|
+
return true;
|
358
|
+
},
|
359
|
+
},
|
360
|
+
]);
|
361
|
+
return customModel.trim();
|
362
|
+
}
|
363
|
+
return modelChoice;
|
364
|
+
}
|
365
|
+
/**
|
366
|
+
* Update .env file with Azure OpenAI configuration using shared utilities
|
367
|
+
*/
|
368
|
+
async function updateEnvFileWithConfig(config) {
|
369
|
+
const spinner = ora("💾 Updating .env file...").start();
|
370
|
+
try {
|
371
|
+
// Prepare environment variables for the shared utility
|
372
|
+
const newVars = {};
|
373
|
+
if (config.apiKey) {
|
374
|
+
newVars.AZURE_OPENAI_API_KEY = config.apiKey;
|
375
|
+
}
|
376
|
+
if (config.endpoint) {
|
377
|
+
newVars.AZURE_OPENAI_ENDPOINT = config.endpoint;
|
378
|
+
}
|
379
|
+
if (config.model) {
|
380
|
+
newVars.AZURE_OPENAI_MODEL = config.model;
|
381
|
+
}
|
382
|
+
// Use shared envManager utility with backup enabled
|
383
|
+
const result = updateEnvFileShared(newVars, ".env", true);
|
384
|
+
spinner.succeed(chalk.green("✔ .env file updated successfully"));
|
385
|
+
// Display summary using shared utility
|
386
|
+
displayEnvUpdateSummary(result, false);
|
387
|
+
}
|
388
|
+
catch (error) {
|
389
|
+
spinner.fail(chalk.red("❌ Failed to update .env file"));
|
390
|
+
logger.error(chalk.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
391
|
+
throw error;
|
392
|
+
}
|
393
|
+
}
|
394
|
+
/**
|
395
|
+
* Mask API key for display
|
396
|
+
*/
|
397
|
+
function maskCredential(credential) {
|
398
|
+
if (!credential || credential.length < 8) {
|
399
|
+
return "****";
|
400
|
+
}
|
401
|
+
const start = credential.slice(0, 4);
|
402
|
+
const end = credential.slice(-4);
|
403
|
+
const middle = "*".repeat(Math.max(4, credential.length - 8));
|
404
|
+
return `${start}${middle}${end}`;
|
405
|
+
}
|
406
|
+
/**
|
407
|
+
* Show usage example
|
408
|
+
*/
|
409
|
+
function showUsageExample() {
|
410
|
+
logger.always("");
|
411
|
+
logger.always(chalk.green("🚀 You can now use Azure OpenAI with the NeuroLink CLI:"));
|
412
|
+
logger.always(chalk.cyan(" pnpm cli generate 'Hello from Azure OpenAI!' --provider azure"));
|
413
|
+
logger.always(chalk.cyan(" pnpm cli generate 'Explain quantum computing' --provider azure"));
|
414
|
+
logger.always(chalk.cyan(" pnpm cli generate 'Analyze this data' --provider azure --enable-analytics"));
|
415
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
/**
|
3
|
+
* AWS Bedrock Setup Command for New Developers
|
4
|
+
*
|
5
|
+
* Checks for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
|
6
|
+
* Auto-detects AWS CLI configuration, prompts for missing config, updates .env safely
|
7
|
+
*/
|
8
|
+
interface BedrockSetupArgv {
|
9
|
+
check?: boolean;
|
10
|
+
nonInteractive?: boolean;
|
11
|
+
}
|
12
|
+
export declare function handleBedrockSetup(argv: BedrockSetupArgv): Promise<void>;
|
13
|
+
export {};
|