qraft
Version:
A powerful CLI tool to qraft structured project setups from GitHub template repositories
198 lines โข 10.8 kB
JavaScript
;
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