UNPKG

@kya-os/create-xmcpi-app

Version:
290 lines 11.5 kB
#!/usr/bin/env node import path from "path"; import fs from "fs-extra"; import chalk from "chalk"; import { Command } from "commander"; import inquirer from "inquirer"; import ora from "ora"; import { fileURLToPath } from "url"; import { checkNodeVersion } from "./utils/check-node.js"; import { createProject } from "./helpers/create.js"; import { isFolderEmpty } from "./utils/is-folder-empty.js"; import { createKYAOSBanner } from "./effects/index.js"; checkNodeVersion(); const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, "../package.json"), "utf8")); const program = new Command() .name("create-xmcpi-app") .description("Create a new xmcp application with identity features built-in") .version(packageJson.version, "-v, --version", "Output the current version of create-xmcpi-app.") .argument("[directory]") .usage("[directory] [options]") .helpOption("-h, --help", "Display help message.") .option("-y, --yes", "Skip confirmation prompt", false) .option("--use-npm", "Use npm as package manager (default: use npm)") .option("--use-yarn", "Use yarn as package manager") .option("--use-pnpm", "Use pnpm as package manager") .option("--skip-install", "Skip installing dependencies", false) .option("--skip-identity", "Skip identity generation", false) .option("--vercel", "Add Vercel support for deployment", false) .option("--http", "Enable HTTP transport", false) .option("--stdio", "Enable STDIO transport", false) .option("--local", "Use local xmcp-i dependency", false) .option("--no-animation", "Skip the black hole animation", false) .option("--fast", "Use shorter animation duration", false) .action(async (projectDir, options) => { console.log(chalk.bold(`\ncreate-xmcpi-app@${packageJson.version}`)); // Show KYA-OS banner const banner = await createKYAOSBanner(); console.log(chalk.cyan(banner)); console.log(chalk.dim("\nEnhanced with identity features by MCP-I\n")); // If project directory wasn't specified, ask for it if (!projectDir) { const answers = await inquirer.prompt([ { type: "input", name: "projectDir", message: "What is your project named?", default: "my-xmcpi-app", }, ]); projectDir = answers.projectDir; } // Normalize project directory const resolvedProjectPath = path.resolve(process.cwd(), projectDir); const projectName = path.basename(resolvedProjectPath); // Check if directory exists if (fs.existsSync(resolvedProjectPath)) { const stats = fs.statSync(resolvedProjectPath); if (!stats.isDirectory()) { console.error(chalk.red(`Error: ${projectName} exists but is not a directory.`)); process.exit(1); } // Check if directory is empty if (!isFolderEmpty(resolvedProjectPath, projectName)) { console.error(chalk.red(`The directory ${resolvedProjectPath} is not empty.`)); process.exit(1); } } let packageManager = "npm"; let useLocalXmcp = options.local; let deployToVercel = options.vercel; let skipInstall = options.skipInstall; let skipIdentity = options.skipIdentity; let transports = ["http"]; let agentName = projectName; let agentDescription = "XMCP-I server with identity features"; let agentRepository = ""; // Handle transport selection from CLI options if (options.http || options.stdio) { transports = []; if (options.http) transports.push("http"); if (options.stdio) transports.push("stdio"); } if (!options.yes) { // Package manager selection if (options.useYarn) packageManager = "yarn"; if (options.usePnpm) packageManager = "pnpm"; if (!options.useYarn && !options.usePnpm && !options.useNpm) { const pmAnswers = await inquirer.prompt([ { type: "list", name: "packageManager", message: "Select a package manager:", choices: [ { name: "npm", value: "npm" }, { name: "yarn", value: "yarn" }, { name: "pnpm", value: "pnpm" }, ], default: "npm", }, ]); packageManager = pmAnswers.packageManager; } // Transport selection (skip if already specified via CLI options) if (!options.http && !options.stdio) { const transportAnswers = await inquirer.prompt([ { type: "checkbox", name: "transports", message: "Select the transports you want to use:", choices: [ { name: "HTTP (runs on a server)", value: "http", checked: true, }, { name: "STDIO (runs on the user's machine)", value: "stdio", checked: false, }, ], validate: (input) => { if (input.length === 0) { return "You must select at least one transport."; } return true; }, }, ]); transports = transportAnswers.transports; } // Vercel deployment option if (!options.vercel && transports.includes("http")) { const vercelAnswers = await inquirer.prompt([ { type: "confirm", name: "deployToVercel", message: "Add Vercel deployment support?", default: true, }, ]); deployToVercel = vercelAnswers.deployToVercel; } // Agent information for identity generation if (!skipIdentity) { console.log(chalk.blue("\n🤖 Agent Configuration:")); const agentInfo = await inquirer.prompt([ { type: "input", name: "name", message: "What's your agent name?", default: projectName, }, { type: "input", name: "description", message: "Brief description of your agent:", default: "XMCP-I server with identity features", }, { type: "input", name: "repository", message: "Repository URL (optional):", default: "", }, ]); agentName = agentInfo.name; agentDescription = agentInfo.description; agentRepository = agentInfo.repository; } console.log(); console.log(`Creating a new xmcp app in ${chalk.green(resolvedProjectPath)}.\n`); const { confirmed } = await inquirer.prompt([ { type: "confirm", name: "confirmed", message: "Ok to continue?", default: true, }, ]); if (!confirmed) { console.log(chalk.yellow("Aborting installation.")); process.exit(0); } } else { // Use command-line options when --yes is provided if (options.useYarn) packageManager = "yarn"; if (options.usePnpm) packageManager = "pnpm"; } const spinner = ora("Creating your xmcp-i app with identity features...").start(); try { spinner.text = "Scaffolding project structure..."; await createProject({ projectPath: resolvedProjectPath, projectName, packageManager, transports: transports, packageVersion: packageJson.version, useLocalXmcp, deployToVercel, skipInstall, agentName, agentDescription, agentRepository, skipIdentity, skipAnimation: options.noAnimation === false ? true : false, // Handle --no-animation flag fastAnimation: options.fast, spinner, // Pass spinner to stop it before animation }); spinner.succeed(chalk.green("Your xmcp-i app is ready")); console.log(); console.log("Next Steps:"); // Show agent management with claim URL first if (!skipIdentity) { console.log("Agent management:"); console.log(" Follow the Claim URL above to claim your agent"); if (resolvedProjectPath !== process.cwd()) { console.log(` cd ${chalk.cyan(projectDir)}`); } console.log(` ${chalk.cyan(`${packageManager} run kya-check`)} - Check agent status`); console.log(` ${chalk.cyan(`${packageManager} run kya-env`)} - Show environment variables`); console.log(); } console.log("Start agent:"); if (resolvedProjectPath !== process.cwd()) { console.log(` cd ${chalk.cyan(projectDir)}`); } if (skipInstall) { if (packageManager === "yarn") { console.log(` ${chalk.cyan("yarn install")}`); } else if (packageManager === "pnpm") { console.log(` ${chalk.cyan("pnpm install")}`); } else { console.log(` ${chalk.cyan("npm install")}`); } } // Show appropriate command based on transport if (transports.includes("stdio")) { console.log(` ${chalk.cyan("npx xmcp build")}`); } else { // HTTP transport - show dev command if (packageManager === "yarn") { console.log(` ${chalk.cyan("yarn dev")}`); } else if (packageManager === "pnpm") { console.log(` ${chalk.cyan("pnpm dev")}`); } else { console.log(` ${chalk.cyan("npm run dev")}`); } } console.log(); console.log("Test your agent:"); if (resolvedProjectPath !== process.cwd()) { console.log(` cd ${chalk.cyan(projectDir)}`); } // Show test:greet command if (packageManager === "yarn") { console.log(` ${chalk.cyan("yarn test:greet")}`); } else if (packageManager === "pnpm") { console.log(` ${chalk.cyan("pnpm test:greet")}`); } else { console.log(` ${chalk.cyan("npm run test:greet")}`); } console.log(); // Explicitly exit after successful completion process.exit(0); } catch (error) { spinner.fail(chalk.red("Failed to create the project.")); console.error(error); process.exit(1); } }); program.parse(process.argv); //# sourceMappingURL=index.js.map