UNPKG

@usrrname/cursorrules

Version:

A wicked npx-able lib of cursor rules with Otaku AI agents

103 lines (83 loc) • 3.61 kB
import { copyFile, cp, mkdir } from 'node:fs/promises'; import { dirname, join, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; import { help } from '../commands.mjs'; import { detectNpxSandbox } from './detect-npx.mjs'; import { findFolderUp } from './find-folder-up.mjs'; import { findPackageRoot } from './find-package-root.mjs'; import { validateDirname } from './validate-dirname.mjs'; const detection = detectNpxSandbox(); const __dirname = dirname(fileURLToPath(import.meta.url)); /** @type {string|undefined} */ let sourceRulesBasePath = ''; if (detection.isNpxSandbox || !sourceRulesBasePath) { const packageRoot = findPackageRoot(__dirname, '@usrrname/cursorrules'); sourceRulesBasePath = resolve(packageRoot, '.cursor', 'rules'); } // only for local development and testing if (process.env.CI || ['development', 'test'].includes(process.env.NODE_ENV ?? '')) { // running inside repo / globally installed copy → locate nearest .cursor const found = await findFolderUp('.cursor', process.cwd()) ?? await findFolderUp('.cursor', __dirname); if (!found) throw new Error("'.cursor' folder not found"); sourceRulesBasePath = resolve(found, 'rules'); } /** * @param {string} dirname - output folder relative path */ export const downloadFiles = async (dirname) => { if (!dirname) throw new Error('Output directory is required'); console.info('šŸ“„ Downloading all rules...'); const outputDir = await validateDirname(dirname); if (!sourceRulesBasePath) { console.error(`āŒ Error: sourceRulesBasePath is not defined`); process.exit(1); } try { // copy whole folder await cp( sourceRulesBasePath, outputDir, { recursive: true }, ) console.log(`āœ… Success! All rules saved to ${outputDir}`); } catch (err) { console.error(`āŒ Error: ${err.message}`, err); process.exit(1); } } /** * Download selected rules only * @param {string} folderName - output folder relative path * @param {Array<{category: string, displayName: string, selected: boolean, name: string, path: string, fullPath: string}>} selectedRules - Array of selected rule objects */ export const downloadSelectedFiles = async (folderName, selectedRules) => { if (!folderName) throw new Error('Output directory is required'); if (!selectedRules || selectedRules.length === 0) { console.log('ā­ļø No rules selected, skipping download'); await help(); return; } console.info('šŸ“„ Downloading selected rules...'); const outputDir = await validateDirname(folderName) try { // Create output directory structure await mkdir(outputDir, { recursive: true }); await mkdir(join(outputDir, '.cursor'), { recursive: true }); // Copy selected rules for (const rule of selectedRules) { const sourcePath = join(sourceRulesBasePath, rule.path); const destPath = join(outputDir, '.cursor', 'rules', rule.path); const destDir = dirname(destPath); // Ensure destination directory exists await mkdir(destDir, { recursive: true }); // Copy the rule file await copyFile(sourcePath, destPath); console.log(` šŸ“„ Copied: ${rule.displayName}`); } console.log(`\nšŸŽ‰ Success! ${selectedRules.length} selected rules saved to ${outputDir}`); } catch (err) { console.error(`āŒ Error: ${err.message}`, err); process.exit(1); } }