UNPKG

vibescript

Version:

The ultimate prompt-driven, component-based, AI-powered, vibe-oriented programming language.

206 lines (192 loc) • 9 kB
#!/usr/bin/env node // This shebang tells the system to use node to run this script // Import the Commander library for CLI argument parsing import { Command } from "commander"; // Import fs module to read files import fs from "fs"; // Import path module to handle file paths import path from "path"; // Import chalk library for colored terminal output import chalk from "chalk"; // Import ora for loading spinners import ora from "ora"; // Import the compileVibeScript function from the compiler module import { compileVibeScript } from "../lib/compiler.js"; // Import the watchVibeScript function from the watcher module import { watchVibeScript } from "../lib/watcher.js"; // Import the deployToVercel function from the deploy module import { deployToVercel } from "../lib/deploy.js"; // Import linting functions from the linter module import { lintVibeScript, printLintResults } from "../lib/linter.js"; // Import dotenv for environment variable loading import dotenv from "dotenv"; // This function loads the config file if it exists function loadConfig(): any { // Resolve the path to vibe.config.json in the current directory const configPath: any = path.resolve("vibe.config.json"); // Check if the config file exists if (fs.existsSync(configPath)) { // Try to read and parse the config file try { // Read the file as UTF-8 and parse as JSON return JSON.parse(fs.readFileSync(configPath, "utf8")); } catch (err: any) { // If parsing fails, log an error console.error("āŒ Failed to parse vibe.config.json:", (err as any).message); } } // Return empty object if no config file exists return {}; } // This function prints the configuration to the console function printConfig(config: any): any { // Print a cyan bold header console.log(chalk.cyan.bold("\nšŸš€ VibeScript Configuration")); // Print a cyan separator line console.log(chalk.cyan("───────────────────────────")); // Print the model setting console.log(`${chalk.bold("Model:")} ${(config as any).model}`); // Print the port setting console.log(`${chalk.bold("Port:")} ${(config as any).port}`); // Print that cache is enabled console.log(`${chalk.bold("Cache:")} Enabled`); // Print a blank line console.log(); } // This function checks if the OpenAI API key is set function checkApiKey(): any { // This is the API key check function // Check if the environment variable is missing or empty if (!process.env.OPENAI_API_KEY || process.env.OPENAI_API_KEY.trim() === "") { // This checks for missing API key // Try to load from .env file dotenv.config(); // This loads the .env file if it exists // Check again after loading .env file if (!process.env.OPENAI_API_KEY || process.env.OPENAI_API_KEY.trim() === "") { // Still missing after loading .env // Print an error message in red bold console.error( // This prints the error message chalk.red.bold("\nāŒ Missing OpenAI API Key!") + // This is the error header // Print instructions on how to set it "\n\nPlease set your API key before running VibeScript:\n" + // This is the instruction text // Print the export command in yellow chalk.yellow("export OPENAI_API_KEY=\"your_api_key_here\"") + // This is the export command "\n\nOr create a " + chalk.green(".env") + " file with:\n" + // This introduces the .env option chalk.green("OPENAI_API_KEY=your_api_key_here") + // This is the .env content // Print a link to get an API key "\n\nGet one here: " + // This introduces the link chalk.blue.underline("https://platform.openai.com/account/api-keys") + // This is the link // Print a blank line "\n" // This adds a newline ); // This closes the console.error call // Exit with error code 1 process.exit(1); // This exits the program with error } // This is the end of the still missing check } // This is the end of the API key check } // This is the end of the checkApiKey function // Create a new Commander program instance const program: any = new Command(); // Load the config file const fileConfig: any = loadConfig(); // Set up the main program command program // Set the command name .name("vibe") // Set the description .description("Compile and run VibeScript projects") // Set the version number .version("2.1.1"); // Add a lint subcommand program // Define the command name .command("lint") // Set the description .description("Lint your VibeScript file for vibe violations") // Add a required file argument .argument("<file>", "VibeScript file to lint") // Define the action to run when lint command is executed .action((file: any) => { // This is the lint command action handler // Check if the file exists if (!fs.existsSync(file)) { // This checks if the input file exists // Print error if file doesn't exist console.error(chalk.red(`āŒ File not found: ${file}`)); // This prints the file not found error // Exit with error code process.exit(1); // This exits with error code 1 } // This is the end of the file existence check // Run the linter on the file const issues: any = lintVibeScript(file); // This runs the linting function // Print the results const exitCode: any = printLintResults(issues, file); // This prints the lint results // Exit with the appropriate code process.exit(exitCode); // This exits with the lint exit code }); // This is the end of the lint command action // Set up the main compile command program // Add a required file argument .argument("<file>", "VibeScript file to compile") // Add watch option flag .option("-w, --watch", "Enable hot reload") // Add deploy option flag .option("-d, --deploy", "Deploy to Vercel after build") // Add model option with default from config .option( "-m, --model <model>", "Choose OpenAI model (gpt-5.1, gpt-5-mini, gpt-5-nano, gpt-oss-120b, gpt-oss-20b, etc)", (fileConfig as any).model || "gpt-5-nano" ) // Add port option with default from config .option( "-p, --port <port>", "Port for dev server", (fileConfig as any).port || 3000 ) // Define the action to run when the main command is executed .action(async (file: any, options: any) => { // Check API key before doing anything checkApiKey(); // Build the config object from options const config: any = { // Use the model from options model: (options as any).model, // Use the port from options port: (options as any).port, }; // Print the configuration printConfig(config); // Check if watch mode is enabled if ((options as any).watch) { // Print a message about starting dev mode console.log(chalk.blue("šŸ”„ Starting development mode...")); // Start watching the file await watchVibeScript(file, config); } else { // Create a main spinner for the build process const buildSpinner: any = ora("Building your vibes...").start(); // This creates and starts the build spinner try { // This starts a try block for error handling // Compile the file await compileVibeScript(file, config); // Stop spinner with success buildSpinner.succeed("Build complete! Check the 'dist' folder for your generated files."); // This stops the spinner with success // Check if deploy flag is set if ((options as any).deploy) { // This checks if deploy flag is set // Create a spinner for deployment const deploySpinner: any = ora("Deploying to Vercel...").start(); // This creates and starts the deploy spinner try { // This starts a try block for deployment // Deploy to Vercel await deployToVercel(); // This deploys to Vercel // Stop spinner with success deploySpinner.succeed("Deployed to Vercel successfully!"); // This stops the spinner with success } catch (error: any) { // This catches deployment errors // Stop spinner with error deploySpinner.fail(`Deployment failed: ${(error as any).message}`); // This stops the spinner with error // Exit with error code process.exit(1); // This exits with error code } // This is the end of deployment try-catch block } // This is the end of deploy flag check } catch (error: any) { // This catches build errors // Stop spinner with error buildSpinner.fail(`Build failed: ${(error as any).message}`); // This stops the spinner with error // Exit with error code process.exit(1); // This exits with error code } // This is the end of build try-catch block } }); // Parse the command line arguments program.parse(process.argv); // This parses the CLI arguments and executes the appropriate command