UNPKG

@microfox/cli

Version:

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

314 lines (309 loc) 13.7 kB
#!/usr/bin/env node "use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { kickstartCommand: () => kickstartCommand }); module.exports = __toCommonJS(index_exports); // src/commands/kickstart.ts var import_fs = __toESM(require("fs")); var import_path = __toESM(require("path")); var import_chalk = __toESM(require("chalk")); var import_readline_sync = __toESM(require("readline-sync")); var import_inquirer = __toESM(require("inquirer")); // src/utils/getProjectRoot.ts var getWorkingDirectory = () => { return process.cwd(); }; // 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 = import_path.default.join(workingDir, agentName); if (import_fs.default.existsSync(agentDir)) { throw new Error(`Directory already exists at ${agentDir}`); } console.log( import_chalk.default.blue( `\u{1F680} Creating agent ${import_chalk.default.bold(agentName)} at ${agentDir} ` ) ); import_fs.default.mkdirSync(agentDir, { recursive: true }); const templatePath = import_path.default.resolve(__dirname, "agent-template.txt"); const templateContent = import_fs.default.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 = import_path.default.join(agentDir, filePath); const destDir = import_path.default.dirname(destPath); if (!import_fs.default.existsSync(destDir)) { import_fs.default.mkdirSync(destDir, { recursive: true }); } import_fs.default.writeFileSync(destPath, content); console.log(import_chalk.default.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 = import_path.default.join(workingDir, simpleName); if (import_fs.default.existsSync(packageDir)) { throw new Error(`Directory already exists at ${packageDir}`); } console.log( import_chalk.default.blue( `\u{1F680} Creating package ${import_chalk.default.bold(packageName)} at ${packageDir} ` ) ); import_fs.default.mkdirSync(packageDir, { recursive: true }); const templatePath = import_path.default.resolve(__dirname, "package-template.txt"); const templateContent = import_fs.default.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 = import_path.default.join(packageDir, filePath); const destDir = import_path.default.dirname(destPath); if (!import_fs.default.existsSync(destDir)) { import_fs.default.mkdirSync(destDir, { recursive: true }); } import_fs.default.writeFileSync(destPath, content); console.log(import_chalk.default.green(`\u2705 Created ${filePath}`)); } const docsDir = import_path.default.join(packageDir, "docs"); const docsConstructors = import_path.default.join(docsDir, "constructors"); const docsFunctions = import_path.default.join(docsDir, "functions"); import_fs.default.mkdirSync(docsDir, { recursive: true }); import_fs.default.mkdirSync(docsConstructors, { recursive: true }); import_fs.default.mkdirSync(docsFunctions, { recursive: true }); } async function createBackgroundAgentProject(agentName) { const workingDir = getWorkingDirectory(); const agentDir = import_path.default.join(workingDir, agentName); if (import_fs.default.existsSync(agentDir)) { throw new Error(`Directory already exists at ${agentDir}`); } console.log( import_chalk.default.blue( `\u{1F680} Creating background agent ${import_chalk.default.bold(agentName)} at ${agentDir} ` ) ); import_fs.default.mkdirSync(agentDir, { recursive: true }); const templateDir = import_path.default.resolve(__dirname, "background-agent"); const copyTemplates = (src, dest) => { const entries = import_fs.default.readdirSync(src, { withFileTypes: true }); for (const entry of entries) { const srcPath = import_path.default.join(src, entry.name); const destPath = import_path.default.join(dest, entry.name.replace(/\.txt$/, "")); if (entry.isDirectory()) { import_fs.default.mkdirSync(destPath, { recursive: true }); copyTemplates(srcPath, destPath); } else if (entry.name.endsWith(".txt")) { const templateContent = import_fs.default.readFileSync(srcPath, "utf-8"); const content = templateContent.replace(/<%= agentName %>/g, agentName); import_fs.default.writeFileSync(destPath, content); console.log(import_chalk.default.green(`\u2705 Created ${import_path.default.relative(agentDir, destPath)}`)); } } }; copyTemplates(templateDir, agentDir); } async function kickstartCommand() { console.log(import_chalk.default.cyan("\u{1F680} Let's kickstart your new project!\n")); const { boilerplateType } = await import_inquirer.default.prompt([ { type: "list", name: "boilerplateType", message: "Select boilerplate type:", choices: ["package", "agent"] } ]); if (!boilerplateType) { console.log(import_chalk.default.yellow("Operation cancelled.")); return; } if (boilerplateType === "agent") { const { agentType } = await import_inquirer.default.prompt([ { type: "list", name: "agentType", message: "Select agent type:", choices: ["plain", "background"] } ]); if (agentType === "plain") { const agentName = import_readline_sync.default.question( import_chalk.default.yellow("\u{1F4E6} Enter agent name: ") ); if (!agentName.trim()) { throw new Error("Agent name cannot be empty"); } await createAgentProject(agentName.trim()); console.log( import_chalk.default.green( ` \u{1F389} Successfully created agent ${import_chalk.default.bold(agentName)}!` ) ); console.log(import_chalk.default.gray(`\u{1F4CD} Located at ${import_path.default.join(getWorkingDirectory(), agentName)}`)); console.log(import_chalk.default.yellow("\n\u{1F4A1} Next steps:")); console.log(import_chalk.default.yellow(` 1. cd ${agentName}`)); console.log(import_chalk.default.yellow(" 2. npm install")); console.log(import_chalk.default.yellow(" 3. Configure your env.json")); console.log(import_chalk.default.yellow(" 4. npm run dev")); console.log(import_chalk.default.yellow(" 5. Start developing your agent!")); } else if (agentType === "background") { const agentName = import_readline_sync.default.question( import_chalk.default.yellow("\u{1F4E6} Enter agent name: ") ); if (!agentName.trim()) { throw new Error("Agent name cannot be empty"); } await createBackgroundAgentProject(agentName.trim()); console.log( import_chalk.default.green( ` \u{1F389} Successfully created background agent ${import_chalk.default.bold(agentName)}!` ) ); console.log(import_chalk.default.gray(`\u{1F4CD} Located at ${import_path.default.join(getWorkingDirectory(), agentName)}`)); console.log(import_chalk.default.yellow("\n\u{1F4A1} Next steps:")); console.log(import_chalk.default.yellow(` 1. cd ${agentName}`)); console.log(import_chalk.default.yellow(" 2. npm install")); console.log(import_chalk.default.yellow(" 3. Configure your env.json")); console.log(import_chalk.default.yellow(" 4. npm run dev")); console.log(import_chalk.default.yellow(" 5. Start developing your agent!")); } } else if (boilerplateType === "package") { const packageName = import_readline_sync.default.question( import_chalk.default.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( import_chalk.default.green( ` \u{1F389} Successfully created package ${import_chalk.default.bold(finalPackageName)}!` ) ); console.log(import_chalk.default.gray(`\u{1F4CD} Located at ${import_path.default.join(getWorkingDirectory(), simpleName)}`)); console.log(import_chalk.default.yellow("\n\u{1F4A1} Next steps:")); console.log(import_chalk.default.yellow(` 1. cd ${simpleName}`)); console.log(import_chalk.default.yellow(" 2. npm install")); console.log(import_chalk.default.yellow(" 3. npm run build")); console.log(import_chalk.default.yellow(" 4. npm test")); console.log(import_chalk.default.yellow(" 5. Start developing your SDK!")); console.log( import_chalk.default.gray( ` \u{1F4DA} Your package is ready to be published to npm as "${finalPackageName}"` ) ); } else { console.log(import_chalk.default.red('Invalid boilerplate type selected. Please choose "package" or "agent".')); } } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { kickstartCommand }); //# sourceMappingURL=index.js.map