UNPKG

qraft

Version:

A powerful CLI tool to qraft structured project setups from GitHub template repositories

198 lines โ€ข 10.8 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createCommand = createCommand; const chalk_1 = __importDefault(require("chalk")); const boxNameDerivation_1 = require("../core/boxNameDerivation"); const directoryScanner_1 = require("../core/directoryScanner"); const metadataGenerator_1 = require("../core/metadataGenerator"); const repositoryManager_1 = require("../core/repositoryManager"); const structureAnalyzer_1 = require("../core/structureAnalyzer"); const tagDetector_1 = require("../core/tagDetector"); const manifestBuilder_1 = require("../interactive/manifestBuilder"); const manifestUtils_1 = require("../utils/manifestUtils"); const update_1 = require("./update"); function createUserPrompt(question) { const readline = require('readline'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); return new Promise((resolve) => { rl.question(question, (answer) => { rl.close(); resolve(answer.trim()); }); }); } async function showDryRunPreview(preview) { console.log(chalk_1.default.cyan('\n๐Ÿ“‹ Preview: What will be created\n')); console.log(chalk_1.default.cyan('Source:')); console.log(chalk_1.default.gray(` ๐Ÿ“ Local Directory: ${preview.localPath}`)); console.log(chalk_1.default.gray(` ๐Ÿ“Š Estimated Files: ${preview.estimatedFiles} files`)); console.log(chalk_1.default.cyan('\nTarget:')); console.log(chalk_1.default.gray(` ๐Ÿ“ฆ Box Name: ${preview.boxName}`)); console.log(chalk_1.default.gray(` ๐Ÿ  Registry: ${preview.registry}`)); console.log(chalk_1.default.gray(` ๐Ÿ“ Target Location: ${preview.targetLocation}`)); console.log(chalk_1.default.cyan('\nActions:')); if (preview.hasConflicts) { console.log(chalk_1.default.yellow(' โš ๏ธ Update existing box')); } else { console.log(chalk_1.default.gray(' โœจ Create new box structure in registry')); } console.log(chalk_1.default.gray(` ๐Ÿ“ค Upload ${preview.estimatedFiles} files`)); console.log(chalk_1.default.gray(' ๐Ÿท๏ธ Generate metadata manifest')); console.log(chalk_1.default.gray(' ๐Ÿ”— Make box available for download')); console.log(chalk_1.default.cyan('\nโ“ Confirmation Required')); const answer = await createUserPrompt('Do you want to proceed with creating this box? (y/N): '); return answer.toLowerCase() === 'y'; } async function getDefaultRegistry(boxManager) { const config = await boxManager.getConfigManager().getConfig(); if (!config.defaultRegistry) { throw new Error('No default registry configured. Please specify a registry with --registry option or configure a default registry.'); } return config.defaultRegistry; } async function validateRegistryAccess(registry) { // Basic format validation if (!registry.includes('/')) { throw new Error('Registry must be in format "owner/repo"'); } const [owner, repo] = registry.split('/'); if (!owner || !repo) { throw new Error('Invalid registry format. Expected "owner/repo"'); } // TODO: Add actual GitHub API connectivity check in future tasks // For now, just validate the format console.log(chalk_1.default.gray(`Registry validation: ${registry} (format check passed)`)); } async function createCommand(boxManager, localPath, boxName, options = {}) { // Step 0: Check if this is an existing box that should be updated instead console.log(chalk_1.default.cyan('๐Ÿ” Checking for existing box...')); if (await manifestUtils_1.ManifestUtils.qraftDirectoryExists(localPath)) { if (await manifestUtils_1.ManifestUtils.hasCompleteLocalManifest(localPath)) { console.log(chalk_1.default.yellow('๐Ÿ“ฆ Existing box detected!')); console.log(chalk_1.default.gray('This directory already contains a qraft box with manifest.')); console.log(chalk_1.default.gray('Switching to update workflow instead of create workflow.\n')); // Route to update command instead return (0, update_1.updateCommand)(boxManager, localPath, { registry: options.registry, dryRun: options.dryRun, interactive: options.interactive }); } else { console.log(chalk_1.default.yellow('โš ๏ธ Incomplete .qraft directory found')); console.log(chalk_1.default.gray('The .qraft directory exists but manifest files are incomplete.')); if (options.interactive !== false) { const answer = await createUserPrompt('Do you want to recreate the box? This will overwrite existing .qraft files. (y/N): '); if (answer.toLowerCase() !== 'y') { console.log(chalk_1.default.yellow('โน๏ธ Operation cancelled by user')); return; } // Clean up incomplete .qraft directory await manifestUtils_1.ManifestUtils.removeQraftDirectory(localPath); console.log(chalk_1.default.gray('๐Ÿงน Cleaned up incomplete .qraft directory\n')); } else { throw new Error('Incomplete .qraft directory found. Use --interactive mode to recreate or manually clean up the .qraft directory.'); } } } const manifestBuilder = new manifestBuilder_1.ManifestBuilder(); console.log(chalk_1.default.blue.bold('๐Ÿ“ฆ Creating Box from Local Directory')); if (options.interactive !== false) { console.log(chalk_1.default.gray('๐ŸŽฏ Interactive mode enabled - you\'ll be guided through the process\n')); } try { // Step 1: Quick validation console.log(chalk_1.default.cyan('๐Ÿ” Validating setup...')); const directoryScanner = new directoryScanner_1.DirectoryScanner(); const structure = await directoryScanner.scanDirectory(localPath); const effectiveRegistry = options.registry || await getDefaultRegistry(boxManager); await validateRegistryAccess(effectiveRegistry); console.log(chalk_1.default.green('โœ… Setup validated\n')); // Step 2: Analyze and generate smart defaults console.log(chalk_1.default.cyan('๐Ÿง  Analyzing project...')); const tagDetector = new tagDetector_1.TagDetector(); const tags = await tagDetector.detectTags(structure); const structureAnalyzer = new structureAnalyzer_1.StructureAnalyzer(); const analysis = structureAnalyzer.analyzeStructure(structure, tags); const boxNameDerivation = new boxNameDerivation_1.BoxNameDerivation(); const nameResult = boxNameDerivation.deriveBoxName(localPath, structure, tags, analysis); const metadataGenerator = new metadataGenerator_1.MetadataGenerator(); const suggestedName = boxName || nameResult.primaryName; const generatedMetadata = metadataGenerator.generateMetadata(suggestedName, structure, tags, analysis); console.log(chalk_1.default.green('โœ… Analysis complete\n')); // Step 3: Interactive manifest building const manifestOptions = { suggestedName, suggestedDescription: generatedMetadata.description, suggestedAuthor: generatedMetadata.author || undefined, suggestedTags: generatedMetadata.tags || undefined, defaultTarget: './target', suggestedRemotePath: localPath, // Use local path as suggested remote path localPath: localPath }; const manifest = options.interactive === false ? await manifestBuilder.buildQuickManifest(generatedMetadata, manifestOptions) : await manifestBuilder.buildManifest(generatedMetadata, manifestOptions); // Step 4: Show preview and get final confirmation const preview = { localPath, boxName: manifest.name, registry: effectiveRegistry, estimatedFiles: structure.files.length, targetLocation: `${effectiveRegistry}/${manifest.name}`, hasConflicts: false }; const shouldProceed = await showDryRunPreview(preview); if (!shouldProceed) { console.log(chalk_1.default.yellow('โน๏ธ Operation cancelled by user')); return; } // Step 5: Create the box console.log(chalk_1.default.cyan('\n๐Ÿš€ Creating box...')); const [registryOwner, registryRepo] = effectiveRegistry.split('/'); const repositoryManager = new repositoryManager_1.RepositoryManager(await boxManager.getGitHubToken(effectiveRegistry)); const createResult = await repositoryManager.createBox(registryOwner, registryRepo, manifest.name, localPath, manifest, manifest.remotePath, // Use remotePath from manifest { commitMessage: `feat: add ${manifest.name} box - ${manifest.description}`, createPR: true }); if (!createResult.success) { throw new Error(`Failed to create box in repository: ${createResult.message}`); } // Success! console.log(chalk_1.default.green('\n๐ŸŽ‰ Box created successfully!')); console.log(chalk_1.default.cyan('\n๐Ÿ“‹ Summary:')); console.log(chalk_1.default.gray(` ๐Ÿ“ฆ Name: ${manifest.name}`)); console.log(chalk_1.default.gray(` ๐Ÿ“ Description: ${manifest.description}`)); console.log(chalk_1.default.gray(` ๐Ÿ  Registry: ${effectiveRegistry}`)); if (createResult.commitSha) { console.log(chalk_1.default.gray(` ๐Ÿ”— Commit: ${createResult.commitSha.substring(0, 8)}`)); } console.log(chalk_1.default.cyan('\n๐ŸŽฏ Next Steps:')); console.log(chalk_1.default.gray(` โ€ข Use: qraft copy ${manifest.name}`)); console.log(chalk_1.default.gray(' โ€ข Share the registry with others')); if (createResult.prUrl) { console.log(chalk_1.default.cyan('\n๐Ÿ”— Pull Request:')); console.log(chalk_1.default.gray(` ${createResult.prUrl}`)); } } catch (error) { console.error(chalk_1.default.red('\nโŒ Error:'), error.message); if (error.code) { console.error(chalk_1.default.gray('Code:'), error.code); } console.error(chalk_1.default.cyan('\n๐Ÿ’ก Help:')); console.error(chalk_1.default.gray(' โ€ข Run: qraft create --help')); console.error(chalk_1.default.gray(' โ€ข Check your directory and registry settings')); process.exit(1); } } //# sourceMappingURL=create.js.map