about summary refs log tree commit diff stats
path: root/tree-sitter/dsk/dsk-cli/src/commands/self.ts
diff options
context:
space:
mode:
Diffstat (limited to 'tree-sitter/dsk/dsk-cli/src/commands/self.ts')
-rw-r--r--tree-sitter/dsk/dsk-cli/src/commands/self.ts71
1 files changed, 71 insertions, 0 deletions
diff --git a/tree-sitter/dsk/dsk-cli/src/commands/self.ts b/tree-sitter/dsk/dsk-cli/src/commands/self.ts
new file mode 100644
index 0000000..2b43fd6
--- /dev/null
+++ b/tree-sitter/dsk/dsk-cli/src/commands/self.ts
@@ -0,0 +1,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;
+}
+
+