NachUI CLI Development Guide
You are modifying or expanding the official NachUI Command Line Interface (
packages/cli). The CLI uses Commander for commands, Clack for prompts, and Kleur for console styling.Directory Structure
src/index.ts: The CLI entry point that configures Commander and routes arguments.src/commands/: Individual command implementations:- init.ts: Installs config files and prepares a workspace for NachUI.
- add.ts: Downloads and adds primitives to the user's workspace.
- list.ts: Lists available components in the registry.
- update.ts: Updates local component files matching registry versions.
- remove.ts: Safely cleans up installed components from a workspace.
src/lib/: Common utilities:- api.ts: Registry fetching and API requests.
- package-manager.ts: Logic to detect the user's package manager (
npm,pnpm,yarn,bun).
Development and Compilation Commands
Always run CLI build and check scripts from the root directory using workspace filters:
1# Run typescript type check2pnpm --filter @repo/cli type-check34# Compile CLI into dist using tsup (generates ESM/CJS bundles)5pnpm --filter @repo/cli build67# Start compiler in watch mode for development8pnpm --filter @repo/cli dev
Designing CLI Commands with Commander
New commands must be added to the Commander instance in
src/index.ts and their logic defined under src/commands/.1import { Command } from 'commander';23const program = new Command();45program.name('nachui').description('Official CLI for NachUI').version('1.0.0');67program8 .command('my-command')9 .description('Explain command actions')10 .argument('[arg]', 'Optional command argument')11 .option('-f, --force', 'Force execution')12 .action(async (arg, options) => {13 // Import execution logic dynamically to keep startup fast14 const { myCommandAction } = await import('./commands/my-command');15 await myCommandAction(arg, options);16 });
Console Prompts & UI Style Guide (Clack & Kleur)
When designing user-facing console interfaces:
- Always wrap interactions in Clack's
intro()andoutro()statements. - Use spinners for any network operations (e.g. fetching registry, downloading files).
- Use Kleur for text styling and colors:
- Info / Dim: Use
kleur.dim()for secondary advice or descriptions. - Success: Use
kleur.green()orkleur.cyan(). - Errors / Warnings: Use
kleur.red()for failure states.
- Info / Dim: Use
1import * as p from '@clack/prompts';2import kleur from 'kleur';34export async function myCommandAction() {5 p.intro(kleur.cyan('NachUI Command'));67 const result = await p.text({8 message: 'Enter input details:',9 placeholder: 'e.g., button',10 validate: (value) => {11 if (!value) return 'Value is required!';12 },13 });1415 if (p.isCancel(result)) {16 p.cancel('Operation cancelled.');17 process.exit(0);18 }1920 const s = p.spinner();21 s.start('Running task...');22 // do work23 s.stop(kleur.green('Task complete!'));2425 p.outro(kleur.cyan('Done!'));26}
Error Handling & Cancellation Safety
- Always handle
p.isCancel(value)checks after every Clack prompt to exit cleanly when a user pressesCtrl+C. - Gracefully catch and log errors using
kleur.red()before terminating the process with a non-zero exit code (process.exit(1)). - Do not leave orphaned file-write operations or incomplete configurations if a command crashes halfway.