UNPKG

qraft

Version:

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

361 lines • 17.9 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.InteractiveMode = void 0; const chalk_1 = __importDefault(require("chalk")); const fs = __importStar(require("fs-extra")); const path = __importStar(require("path")); const boxSelector_1 = require("./boxSelector"); const prompts_1 = require("./prompts"); /** * Interactive mode manager for all CLI operations */ class InteractiveMode { constructor(boxManager) { this.boxManager = boxManager; this.prompts = new prompts_1.InteractivePrompts(); this.boxSelector = new boxSelector_1.InteractiveBoxSelector(boxManager); } /** * Interactive box copying workflow * @param boxName Optional box name to start with * @param options Initial options * @returns Promise<BoxOperationResult> Result of the operation */ async copyBox(boxName, options = {}) { try { console.log(chalk_1.default.blue.bold('šŸ“¦ Interactive Box Copy\n')); // Step 1: Select box if not provided let selectedBox; let selectedRegistry = options.registry; if (boxName) { // Parse and validate provided box name try { const boxRef = await this.boxManager.parseBoxReference(boxName, options.registry); const boxInfo = await this.boxManager.getBoxInfo(boxRef); if (!boxInfo) { console.log(chalk_1.default.red(`āŒ Box '${boxName}' not found.`)); const tryInteractive = await this.prompts.confirm('Would you like to browse available boxes instead?', true); if (!tryInteractive) { return { success: false, message: `Box '${boxName}' not found`, error: new Error(`Box '${boxName}' does not exist`) }; } const selection = await this.boxSelector.selectBox(options.registry); if (!selection) { return { success: false, message: 'Operation cancelled by user' }; } selectedBox = selection.box; selectedRegistry = selection.registry; } else { selectedBox = boxInfo; selectedRegistry = boxRef.registry; // Show preview and confirm await this.prompts.previewBox(selectedBox); const confirmed = await this.prompts.confirm(`Copy ${selectedBox.manifest.name}?`, true); if (!confirmed) { return { success: false, message: 'Operation cancelled by user' }; } } } catch (error) { console.error(chalk_1.default.red('āŒ Error finding box:'), error instanceof Error ? error.message : 'Unknown error'); const tryInteractive = await this.prompts.confirm('Would you like to browse available boxes instead?', true); if (!tryInteractive) { return { success: false, message: 'Box lookup failed', error: error instanceof Error ? error : new Error('Unknown error') }; } const selection = await this.boxSelector.selectBox(options.registry); if (!selection) { return { success: false, message: 'Operation cancelled by user' }; } selectedBox = selection.box; selectedRegistry = selection.registry; } } else { // Interactive box selection const selection = await this.boxSelector.selectBox(options.registry); if (!selection) { return { success: false, message: 'Operation cancelled by user' }; } selectedBox = selection.box; selectedRegistry = selection.registry; } // Step 2: Configure target directory let targetDirectory = options.target || selectedBox.manifest.defaultTarget || process.cwd(); if (!options.target) { targetDirectory = await this.prompts.promptTargetDirectory(targetDirectory); } targetDirectory = path.resolve(targetDirectory); // Step 3: Check for existing files and handle overwrites let forceOverwrite = options.force || false; if (!forceOverwrite) { const existingFiles = await this.checkExistingFiles(selectedBox.files, targetDirectory); if (existingFiles.length > 0) { forceOverwrite = await this.prompts.confirmOverwrite(existingFiles); if (!forceOverwrite) { return { success: false, message: 'Operation cancelled - files would be overwritten' }; } } } // Step 4: Ask about sync tracking preference (unless explicitly set) let enableSync = !options.nosync; // Default to sync enabled unless noSync is explicitly true if (options.nosync === undefined) { // Only prompt if not explicitly set via CLI flag enableSync = await this.prompts.confirm('Enable sync tracking? (Creates .qraft directory for updates and management)', true); } // Step 5: Show summary and final confirmation console.log(chalk_1.default.blue.bold('\nšŸ“‹ Copy Summary:')); console.log(` Box: ${chalk_1.default.cyan(selectedBox.manifest.name)} ${chalk_1.default.gray(`(${selectedBox.manifest.version})`)}`); console.log(` Registry: ${chalk_1.default.yellow(selectedRegistry)}`); console.log(` Target: ${chalk_1.default.gray(targetDirectory)}`); console.log(` Files: ${chalk_1.default.cyan(selectedBox.files.length)} files`); console.log(` Overwrite: ${forceOverwrite ? chalk_1.default.red('Yes') : chalk_1.default.green('No')}`); console.log(` Sync Tracking: ${enableSync ? chalk_1.default.green('Enabled') : chalk_1.default.yellow('Disabled')}`); const finalConfirm = await this.prompts.confirm('\nProceed with copy operation?', true); if (!finalConfirm) { return { success: false, message: 'Operation cancelled by user' }; } // Step 5: Perform the copy operation console.log(chalk_1.default.blue('\nā³ Copying files...')); const config = { boxName: selectedBox.manifest.name, targetDirectory, force: forceOverwrite, interactive: true, boxesDirectory: '', // Not used for GitHub mode nosync: !enableSync }; const result = await this.boxManager.copyBox(config, selectedRegistry); // Step 6: Show results if (result.success) { console.log(chalk_1.default.green.bold('\nāœ… Copy completed successfully!')); console.log(chalk_1.default.gray(` Copied ${result.copiedFiles?.length || 0} files`)); if (result.skippedFiles && result.skippedFiles.length > 0) { console.log(chalk_1.default.yellow(` Skipped ${result.skippedFiles.length} existing files`)); } // Show post-install steps if available if (selectedBox.manifest.postInstall && selectedBox.manifest.postInstall.length > 0) { console.log(chalk_1.default.blue.bold('\nšŸ“‹ Next Steps:')); selectedBox.manifest.postInstall.forEach((step, index) => { console.log(chalk_1.default.gray(` ${index + 1}. ${step}`)); }); } console.log(chalk_1.default.gray(`\nšŸ“ Files copied to: ${targetDirectory}`)); } else { console.error(chalk_1.default.red.bold('\nāŒ Copy failed')); console.error(chalk_1.default.red(result.message)); } return result; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; console.error(chalk_1.default.red('āŒ Unexpected error during copy operation:'), errorMessage); return { success: false, message: `Copy operation failed: ${errorMessage}`, error: error instanceof Error ? error : new Error('Unknown error') }; } } /** * Interactive list boxes workflow * @param registryName Optional registry to list from */ async listBoxes(registryName) { try { console.log(chalk_1.default.blue.bold('šŸ“¦ Interactive Box Browser\n')); // Select registry if not provided let selectedRegistry = registryName; if (!selectedRegistry) { const registries = await this.boxManager.listRegistries(); if (registries.length === 0) { console.log(chalk_1.default.red('āŒ No registries configured.')); console.log(chalk_1.default.gray('Add a registry first:')); console.log(chalk_1.default.cyan(' qraft config add-registry <name> <repository>')); return; } if (registries.length === 1) { selectedRegistry = registries[0].name; console.log(chalk_1.default.gray(`Using registry: ${chalk_1.default.cyan(selectedRegistry)}`)); } else { const registrySelection = await this.prompts.selectRegistry(registries); if (!registrySelection) { console.log(chalk_1.default.yellow('Operation cancelled.')); return; } selectedRegistry = registrySelection; } } // Use the interactive box selector for browsing const selection = await this.boxSelector.selectBox(selectedRegistry); if (selection) { console.log(chalk_1.default.green(`\nSelected: ${chalk_1.default.cyan(selection.box.manifest.name)} from ${chalk_1.default.yellow(selection.registry)}`)); const copyNow = await this.prompts.confirm('Would you like to copy this box now?', false); if (copyNow) { await this.copyBox(selection.box.manifest.name, { registry: selection.registry }); } } else { console.log(chalk_1.default.yellow('No box selected.')); } } catch (error) { console.error(chalk_1.default.red('āŒ Error browsing boxes:'), error instanceof Error ? error.message : 'Unknown error'); } } /** * Interactive authentication setup * @param registryName Optional specific registry */ async setupAuthentication(registryName) { try { if (registryName) { // Set up authentication for specific registry const token = await this.prompts.promptGitHubToken(registryName); console.log(chalk_1.default.blue('\nā³ Testing authentication...')); await this.boxManager.setRegistryToken(registryName, token); const authResult = await this.boxManager.testAuthentication(registryName); if (authResult.authenticated) { console.log(chalk_1.default.green.bold('\nāœ… Authentication successful!')); console.log(chalk_1.default.gray(` Registry: ${registryName}`)); console.log(chalk_1.default.gray(` Authenticated as: ${authResult.user}`)); } else { console.error(chalk_1.default.red.bold('\nāŒ Authentication failed')); console.error(chalk_1.default.red(` Error: ${authResult.error}`)); } } else { // Set up global authentication const token = await this.prompts.promptGitHubToken(); console.log(chalk_1.default.blue('\nā³ Testing authentication...')); await this.boxManager.setGlobalToken(token); const defaultRegistry = await this.boxManager.getDefaultRegistry(); const authResult = await this.boxManager.testAuthentication(defaultRegistry); if (authResult.authenticated) { console.log(chalk_1.default.green.bold('\nāœ… Authentication successful!')); console.log(chalk_1.default.gray(` Authenticated as: ${authResult.user}`)); console.log(chalk_1.default.gray(' Global token has been saved.')); } else { console.error(chalk_1.default.red.bold('\nāŒ Authentication failed')); console.error(chalk_1.default.red(` Error: ${authResult.error}`)); } } } catch (error) { console.error(chalk_1.default.red('āŒ Error setting up authentication:'), error instanceof Error ? error.message : 'Unknown error'); } } /** * Interactive registry configuration */ async configureRegistry() { try { const config = await this.prompts.promptRegistryConfig(); console.log(chalk_1.default.blue('\nā³ Adding registry...')); await this.boxManager.getConfigManager().addRegistry(config.name, { name: config.name, repository: config.repository }); if (config.setAsDefault) { await this.boxManager.getConfigManager().setDefaultRegistry(config.name); } console.log(chalk_1.default.green.bold('\nāœ… Registry added successfully!')); console.log(chalk_1.default.gray(` Name: ${config.name}`)); console.log(chalk_1.default.gray(` Repository: ${config.repository}`)); if (config.setAsDefault) { console.log(chalk_1.default.gray(' Set as default registry')); } // Ask if they want to set up authentication const setupAuth = await this.prompts.confirm('Would you like to set up authentication for this registry?', false); if (setupAuth) { await this.setupAuthentication(config.name); } } catch (error) { console.error(chalk_1.default.red('āŒ Error configuring registry:'), error instanceof Error ? error.message : 'Unknown error'); } } /** * Check for existing files that would be overwritten * @param files Array of file paths relative to target * @param targetDirectory Target directory * @returns Promise<string[]> Array of existing file paths */ async checkExistingFiles(files, targetDirectory) { const existingFiles = []; for (const file of files) { const fullPath = path.join(targetDirectory, file); if (await fs.pathExists(fullPath)) { existingFiles.push(fullPath); } } return existingFiles; } } exports.InteractiveMode = InteractiveMode; //# sourceMappingURL=interactiveMode.js.map