about summary refs log tree commit diff stats
path: root/tree-sitter/dsk/dsk-cli/src/commands/self.ts
blob: 2b43fd69afeb501ee143815a24aa7667f5b34786 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/**
 * 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;
}