UNPKG

microfox

Version:

Universal CLI tool for creating modern TypeScript packages with npm availability checking

290 lines (286 loc) 11.1 kB
#!/usr/bin/env node import { getWorkingDirectory } from "./chunk-TZQZMKHP.mjs"; import { __require } from "./chunk-SXDIALXJ.mjs"; // src/commands/kickstart.ts import { Command } from "commander"; import fs from "fs"; import path from "path"; import chalk from "chalk"; import readlineSync from "readline-sync"; import inquirer from "inquirer"; // src/utils/npmChecker.ts async function isPackageNameAvailable(packageName) { try { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 5e3); const response = await fetch(`https://registry.npmjs.org/${packageName}`, { signal: controller.signal }); clearTimeout(timeoutId); if (response.ok) { return false; } if (response.status === 404) { return true; } console.warn( `Warning: Unexpected status ${response.status} when checking npm availability for ${packageName}. Proceeding with caution.` ); return false; } catch (error) { if (error.name === "AbortError") { console.warn( `Warning: Timeout when checking npm availability for ${packageName}. Proceeding with caution.` ); } else { console.warn( `Warning: Could not check npm availability for ${packageName}. Proceeding with caution.` ); } return false; } } async function checkPackageNameAndPrompt(packageName) { const readlineSync2 = __require("readline-sync"); let currentName = (packageName == null ? void 0 : packageName.startsWith("@microfox/")) ? packageName : `@microfox/${packageName}`; while (true) { console.log(`\u{1F50D} Checking npm availability for "${currentName}"...`); const isAvailable = await isPackageNameAvailable(currentName); if (isAvailable) { console.log(`\u2705 Package name "${currentName}" is available on npm!`); return currentName; } else { console.log(`\u274C Package name "${currentName}" is already taken on npm.`); const newName = readlineSync2.question( "Please enter a new package name: " ); if (!newName || newName.trim() === "") { console.log("\u274C Invalid package name. Please try again."); continue; } currentName = newName.trim(); } } } // src/commands/kickstart.ts async function createAgentProject(agentName) { const workingDir = getWorkingDirectory(); const agentDir = path.join(workingDir, agentName); if (fs.existsSync(agentDir)) { throw new Error(`Directory already exists at ${agentDir}`); } console.log( chalk.blue( `\u{1F680} Creating agent ${chalk.bold(agentName)} at ${agentDir} ` ) ); fs.mkdirSync(agentDir, { recursive: true }); const templatePath = path.resolve(__dirname, "agent-template.txt"); const templateContent = fs.readFileSync(templatePath, "utf-8"); const fileSections = templateContent.split("--- filename: ").slice(1); for (const section of fileSections) { const lines = section.split("\n"); const filePath = lines.shift().trim(); const content = lines.join("\n").replace(/<%= agentName %>/g, agentName); const destPath = path.join(agentDir, filePath); const destDir = path.dirname(destPath); if (!fs.existsSync(destDir)) { fs.mkdirSync(destDir, { recursive: true }); } fs.writeFileSync(destPath, content); console.log(chalk.green(`\u2705 Created ${filePath}`)); } } async function createPackageProject(packageName) { const simpleName = packageName.includes("/") ? packageName.split("/")[1] : packageName; const titleName = simpleName.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" "); const description = `A TypeScript SDK for ${titleName}.`; const className = simpleName.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("") + "Sdk"; const workingDir = getWorkingDirectory(); const packageDir = path.join(workingDir, simpleName); if (fs.existsSync(packageDir)) { throw new Error(`Directory already exists at ${packageDir}`); } console.log( chalk.blue( `\u{1F680} Creating package ${chalk.bold(packageName)} at ${packageDir} ` ) ); fs.mkdirSync(packageDir, { recursive: true }); const templatePath = path.resolve(__dirname, "package-template.txt"); const templateContent = fs.readFileSync(templatePath, "utf-8"); const fileSections = templateContent.split("--- filename: ").slice(1); for (const section of fileSections) { const lines = section.split("\n"); const filePath = lines.shift().trim().replace(/<%= simpleName %>/g, simpleName); let content = lines.join("\n"); content = content.replace(/<%= packageName %>/g, packageName); content = content.replace(/<%= simpleName %>/g, simpleName); content = content.replace(/<%= titleName %>/g, titleName); content = content.replace(/<%= description %>/g, description); content = content.replace(/<%= className %>/g, className); const destPath = path.join(packageDir, filePath); const destDir = path.dirname(destPath); if (!fs.existsSync(destDir)) { fs.mkdirSync(destDir, { recursive: true }); } fs.writeFileSync(destPath, content); console.log(chalk.green(`\u2705 Created ${filePath}`)); } const docsDir = path.join(packageDir, "docs"); const docsConstructors = path.join(docsDir, "constructors"); const docsFunctions = path.join(docsDir, "functions"); fs.mkdirSync(docsDir, { recursive: true }); fs.mkdirSync(docsConstructors, { recursive: true }); fs.mkdirSync(docsFunctions, { recursive: true }); } async function createBackgroundAgentProject(agentName) { const workingDir = getWorkingDirectory(); const agentDir = path.join(workingDir, agentName); if (fs.existsSync(agentDir)) { throw new Error(`Directory already exists at ${agentDir}`); } console.log( chalk.blue( `\u{1F680} Creating background agent ${chalk.bold(agentName)} at ${agentDir} ` ) ); fs.mkdirSync(agentDir, { recursive: true }); const templateDir = path.resolve(__dirname, "background-agent"); const copyTemplates = (src, dest) => { const entries = fs.readdirSync(src, { withFileTypes: true }); for (const entry of entries) { const srcPath = path.join(src, entry.name); const destPath = path.join(dest, entry.name.replace(/\.txt$/, "")); if (entry.isDirectory()) { fs.mkdirSync(destPath, { recursive: true }); copyTemplates(srcPath, destPath); } else if (entry.name.endsWith(".txt")) { const templateContent = fs.readFileSync(srcPath, "utf-8"); const content = templateContent.replace(/<%= agentName %>/g, agentName); fs.writeFileSync(destPath, content); console.log(chalk.green(`\u2705 Created ${path.relative(agentDir, destPath)}`)); } } }; copyTemplates(templateDir, agentDir); } async function kickstartAction() { console.log(chalk.cyan("\u{1F680} Let's kickstart your new project!\n")); const { boilerplateType } = await inquirer.prompt([ { type: "list", name: "boilerplateType", message: "Select boilerplate type:", choices: ["package", "agent"] } ]); if (!boilerplateType) { console.log(chalk.yellow("Operation cancelled.")); return; } if (boilerplateType === "agent") { const { agentType } = await inquirer.prompt([ { type: "list", name: "agentType", message: "Select agent type:", choices: ["plain", "background"] } ]); if (agentType === "plain") { const agentName = readlineSync.question( chalk.yellow("\u{1F4E6} Enter agent name: ") ); if (!agentName.trim()) { throw new Error("Agent name cannot be empty"); } await createAgentProject(agentName.trim()); console.log( chalk.green( ` \u{1F389} Successfully created agent ${chalk.bold(agentName)}!` ) ); console.log(chalk.gray(`\u{1F4CD} Located at ${path.join(getWorkingDirectory(), agentName)}`)); console.log(chalk.yellow("\n\u{1F4A1} Next steps:")); console.log(chalk.yellow(` 1. cd ${agentName}`)); console.log(chalk.yellow(" 2. npm install")); console.log(chalk.yellow(" 3. Configure your env.json")); console.log(chalk.yellow(" 4. npm run dev")); console.log(chalk.yellow(" 5. Start developing your agent!")); } else if (agentType === "background") { const agentName = readlineSync.question( chalk.yellow("\u{1F4E6} Enter agent name: ") ); if (!agentName.trim()) { throw new Error("Agent name cannot be empty"); } await createBackgroundAgentProject(agentName.trim()); console.log( chalk.green( ` \u{1F389} Successfully created background agent ${chalk.bold(agentName)}!` ) ); console.log(chalk.gray(`\u{1F4CD} Located at ${path.join(getWorkingDirectory(), agentName)}`)); console.log(chalk.yellow("\n\u{1F4A1} Next steps:")); console.log(chalk.yellow(` 1. cd ${agentName}`)); console.log(chalk.yellow(" 2. npm install")); console.log(chalk.yellow(" 3. Configure your env.json")); console.log(chalk.yellow(" 4. npm run dev")); console.log(chalk.yellow(" 5. Start developing your agent!")); } } else if (boilerplateType === "package") { const packageName = readlineSync.question( chalk.yellow("\u{1F4E6} Enter package name: ") ); if (!packageName.trim()) { throw new Error("Package name cannot be empty"); } const finalPackageName = await checkPackageNameAndPrompt(`@microfox/${packageName.trim()}`); await createPackageProject(finalPackageName); const simpleName = finalPackageName.includes("/") ? finalPackageName.split("/")[1] : finalPackageName; console.log( chalk.green( ` \u{1F389} Successfully created package ${chalk.bold(finalPackageName)}!` ) ); console.log(chalk.gray(`\u{1F4CD} Located at ${path.join(getWorkingDirectory(), simpleName)}`)); console.log(chalk.yellow("\n\u{1F4A1} Next steps:")); console.log(chalk.yellow(` 1. cd ${simpleName}`)); console.log(chalk.yellow(" 2. npm install")); console.log(chalk.yellow(" 3. npm run build")); console.log(chalk.yellow(" 4. npm test")); console.log(chalk.yellow(" 5. Start developing your SDK!")); console.log( chalk.gray( ` \u{1F4DA} Your package is ready to be published to npm as "${finalPackageName}"` ) ); } else { console.log(chalk.red('Invalid boilerplate type selected. Please choose "package" or "agent".')); } } var kickstartCommand = new Command("kickstart").description("Kickstart a new TypeScript SDK or agent package").action(async () => { try { console.log(chalk.blue("\u{1F680} Package Kickstarter\n")); await kickstartAction(); } catch (error) { console.error(chalk.red("\u274C Error:"), error instanceof Error ? error.message : String(error)); process.exit(1); } }); export { kickstartCommand }; //# sourceMappingURL=chunk-E3UDC54U.mjs.map