/** * Self Packaging Command - Build and package the dsk CLI for distribution */ import { Command } from 'commander'; import chalk from 'chalk'; import { execa } from 'execa'; import { existsSync, mkdirSync, readFileSync } from 'fs'; import { dirname, join } from 'path'; import { fileURLToPath } from 'url'; /** * Create the self:package command */ export function createSelfPackageCommand(): Command { const cmd = new Command('self:package'); cmd .description('Build and package the dsk CLI into a .tgz for distribution') .option('-v, --verbose', 'Show detailed build output') .action(async (options) => { const projectRoot = resolveProjectRoot(); if (!existsSync(join(projectRoot, 'package.json'))) { console.error(chalk.red('❌ Could not locate package.json for dsk-cli')); process.exit(1); } const pkg = JSON.parse(readFileSync(join(projectRoot, 'package.json'), 'utf-8')); console.log(chalk.blue(`📦 Packaging ${pkg.name}@${pkg.version}`)); // 1) Build TypeScript → dist console.log(chalk.blue('🏗️ Building CLI...')); await execa('bun', ['x', 'tsc'], { cwd: projectRoot, stdio: options.verbose ? 'inherit' : 'inherit' }); // 2) Pack npm tarball using bun pack (fallback to npm pack) console.log(chalk.blue('🧰 Creating package tarball...')); let tgzName = ''; try { const { stdout } = await execa('bun', ['pack'], { cwd: projectRoot }); tgzName = stdout.trim().split(/\s|\n/).pop() || ''; } catch { const { stdout } = await execa('npm', ['pack'], { cwd: projectRoot }); tgzName = stdout.trim().split(/\s|\n/).pop() || ''; } if (!tgzName) { console.error(chalk.red('❌ Failed to determine generated package filename')); process.exit(1); } const releaseDir = join(projectRoot, 'release'); mkdirSync(releaseDir, { recursive: true }); const src = join(projectRoot, tgzName); const dest = join(releaseDir, tgzName); await execa('bash', ['-lc', `mv -f ${JSON.stringify(src)} ${JSON.stringify(dest)}`]); console.log(chalk.green(`✅ Created ${dest}`)); }); return cmd; } function resolveProjectRoot(): string { const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); // When compiled, this file lives under dist/commands. Project root is two levels up. const candidate = join(__dirname, '..', '..'); return candidate; }