@juspay/neurolink
Version:
Universal AI Development Platform with working MCP integration, multi-provider support, voice (TTS/STT/realtime), and professional CLI. 58+ external MCP servers discoverable, multimodal file processing, RAG pipelines. Build, test, and deploy AI applicatio
206 lines ⢠8.05 kB
JavaScript
import chalk from "chalk";
import ora from "ora";
import inquirer from "inquirer";
import fs from "fs";
import path from "path";
import { logger } from "../../lib/utils/logger.js";
import { getTopModelChoices } from "../../lib/utils/modelChoices.js";
import { AIProviderName } from "../../lib/types/index.js";
/**
* Validates Mistral API key format
* Mistral keys typically start with "sk-" and contain base62 plus "-" or "_".
*/
function validateMistralApiKey(apiKey) {
const key = apiKey.trim();
return /^sk-[A-Za-z0-9_-]{20,}$/.test(key);
}
/**
* Safely parse and reconstruct .env file content
*/
function updateEnvFile(updates) {
const envPath = path.resolve(process.cwd(), ".env");
let envContent = "";
// Read existing .env if it exists
if (fs.existsSync(envPath)) {
envContent = fs.readFileSync(envPath, "utf-8");
}
// Parse existing environment variables
const envLines = envContent.split("\n");
const envVars = new Map();
// Track which variables we found and their positions
envLines.forEach((line, index) => {
const trimmed = line.trim();
if (trimmed && !trimmed.startsWith("#")) {
const equalIndex = trimmed.indexOf("=");
if (equalIndex > 0) {
const key = trimmed.substring(0, equalIndex);
const value = trimmed.substring(equalIndex + 1);
envVars.set(key, { value, lineIndex: index });
}
}
});
// Update existing variables or add new ones
for (const [key, newValue] of Object.entries(updates)) {
const existing = envVars.get(key);
if (existing) {
// Update existing variable
envLines[existing.lineIndex] = `${key}=${newValue}`;
}
else {
// Add new variable
envLines.push(`${key}=${newValue}`);
}
}
// Write updated content
fs.writeFileSync(envPath, envLines.join("\n"));
}
/**
* Check current Mistral AI configuration
*/
function checkMistralConfig() {
const apiKey = process.env.MISTRAL_API_KEY;
const model = process.env.MISTRAL_MODEL;
const hasApiKey = !!apiKey;
const hasModel = !!model;
const isValid = typeof apiKey === "string" && validateMistralApiKey(apiKey);
return {
hasApiKey,
hasModel,
apiKey: apiKey ? `${apiKey.substring(0, 8)}...` : undefined,
model,
isValid,
};
}
export const handleMistralSetup = async (argv) => {
const spinner = ora();
try {
spinner.start("Checking Mistral AI configuration...");
const config = checkMistralConfig();
spinner.stop();
// Display current status
logger.always(chalk.bold.blue("\nš§ Mistral AI Configuration Status\n"));
logger.always(`${config.hasApiKey ? "ā
" : "ā"} API Key: ${config.apiKey || "Not set"}`);
logger.always(`${config.hasModel ? "ā
" : "ā ļø"} Model: ${config.model || "Not set (will use default)"}`);
if (config.isValid) {
logger.always(chalk.green("\nā
Mistral AI is properly configured!"));
if (argv.check) {
return;
}
const { shouldReconfigure } = await inquirer.prompt([
{
type: "confirm",
name: "shouldReconfigure",
message: "Configuration looks good. Do you want to reconfigure anyway?",
default: false,
},
]);
if (!shouldReconfigure) {
logger.always(chalk.green("ā
Keeping existing configuration."));
return;
}
}
else {
logger.always(chalk.yellow("\nā ļø Mistral AI configuration needs setup."));
if (argv.check) {
process.exit(1);
}
}
if (argv["non-interactive"]) {
logger.always(chalk.yellow("Non-interactive mode: Skipping configuration setup."));
logger.always(chalk.blue("Please set MISTRAL_API_KEY manually."));
return;
}
// Interactive setup
logger.always(chalk.blue("\nš ļø Let's configure Mistral AI!\n"));
// Show instructions for getting API key
logger.always(chalk.yellow("š To get your Mistral AI API key:"));
logger.always("1. Visit: https://console.mistral.ai/");
logger.always("2. Sign up or sign in to your account");
logger.always("3. Go to 'API Keys' section");
logger.always("4. Create a new API key");
logger.always("5. Copy the API key\n");
// Step 1: API Key
const { apiKey } = await inquirer.prompt([
{
type: "password",
name: "apiKey",
message: "Enter your Mistral AI API key:",
mask: "*",
validate: (input) => {
if (!input.trim()) {
return "API key is required";
}
if (!validateMistralApiKey(input.trim())) {
return "Invalid API key format. Should be alphanumeric and at least 20 characters";
}
return true;
},
},
]);
// Step 2: Model Selection
const { modelChoice } = await inquirer.prompt([
{
type: "select",
name: "modelChoice",
message: "Select a Mistral model:",
choices: getTopModelChoices(AIProviderName.MISTRAL, 5),
},
]);
let selectedModel = modelChoice;
if (modelChoice === "custom") {
const { customModel } = await inquirer.prompt([
{
type: "input",
name: "customModel",
message: "Enter custom Mistral model name:",
validate: (input) => {
const trimmed = input.trim();
if (!trimmed) {
return "Model name is required";
}
return true;
},
},
]);
selectedModel = customModel.trim();
}
// Save configuration
spinner.start("Saving configuration...");
const updates = {
MISTRAL_API_KEY: apiKey.trim(),
MISTRAL_MODEL: selectedModel,
};
updateEnvFile(updates);
spinner.stop();
logger.always(chalk.green("\nā
Mistral AI configuration saved successfully!"));
logger.always(chalk.blue("\nš Usage examples:"));
logger.always(chalk.gray(' neurolink generate "Hello, how are you?" --provider mistral'));
logger.always(chalk.gray(` neurolink generate "Explain quantum physics" --provider mistral --model ${selectedModel}`));
logger.always(chalk.blue("\nš Resources:"));
logger.always(chalk.gray(" ⢠Mistral AI Console: https://console.mistral.ai/"));
logger.always(chalk.gray(" ⢠API Documentation: https://docs.mistral.ai/"));
logger.always(chalk.gray(" ⢠Model Information: https://docs.mistral.ai/getting-started/models/"));
logger.always(chalk.blue("\nš” Features:"));
logger.always(chalk.gray(" ⢠European GDPR-compliant AI"));
logger.always(chalk.gray(" ⢠Multilingual support"));
logger.always(chalk.gray(" ⢠Fast inference speeds"));
}
catch (error) {
spinner.stop();
logger.error("Mistral AI setup failed", error);
throw error;
}
};
export const setupMistralBuilder = {
check: {
type: "boolean",
describe: "Only check existing configuration without prompting",
default: false,
},
"non-interactive": {
type: "boolean",
describe: "Skip interactive prompts",
default: false,
},
};
//# sourceMappingURL=setup-mistral.js.map