Files

3.5 KiB

@ermnvldmr/cli

An extensible, configuration-driven CLI toolkit designed specifically for the ermnvldmr monorepo.

Overview

The @ermnvldmr/cli package provides a unified way to declare, manage, and execute scripts across different packages and services in the monorepo. Instead of cluttering package.json with complex bash scripts or maintaining ad-hoc Node.js script files, developers can define their package's commands in a strongly-typed .config/cli.ts file.

Under the hood, it uses Commander.js for argument parsing and JITI for seamless, dynamic TypeScript execution.

Features

  • Centralized Configuration: Define all commands in a single .config/cli.ts file per package.
  • Type-Safe Builders: Use bashCommand and nodeCommand builders to get strict TypeScript inference.
  • Bash & Node Support: Easily execute shell scripts (via execa) or arbitrary asynchronous Node.js functions.
  • Commander Integration: Automatically registers commands, descriptions, and arguments into a robust CLI interface.

Installation

This package is intended to be used as a development dependency within the monorepo's workspace packages.

pnpm add -D @ermnvldmr/cli --workspace

Usage

1. Create a Configuration File

Create a .config/cli.ts file in the root of your package/service (e.g., packages/ui/.config/cli.ts).

import { defineCli, bashCommand, nodeCommand } from '@ermnvldmr/cli';

export default defineCli({
  commands: [
    bashCommand({
      name: 'hello',
      description: 'Prints a hello message via bash',
      script: 'echo "Hello from Bash!"'
    }),
    
    nodeCommand({
      name: 'build:custom',
      description: 'Runs a custom node build step',
      options: [
        {
          flags: '--minify',
          description: 'Enable minification',
          defaultValue: false
        }
      ],
      action: async (options) => {
        console.log('Building with node...');
        if (options.minify) {
          console.log('Minification enabled!');
        }
      }
    })
  ]
});

2. Run the CLI

You can invoke the CLI directly using pnpm exec from the package directory:

pnpm exec ermnvldmr-cli hello
pnpm exec ermnvldmr-cli build:custom --minify

Alternatively, you can wire it into your package.json scripts:

{
  "scripts": {
    "cli": "ermnvldmr-cli",
    "hello": "ermnvldmr-cli hello"
  }
}

API Reference

defineCli(config: CliConfig)

An identity helper function that provides strict TypeScript type-inference for your configuration object. It returns the configuration unmodified.

bashCommand(config: Omit<BashCommandConfig, 'type'>)

A builder function for defining shell commands.

  • script: The exact bash string to execute. It will be executed using execa with shell: true and stdio: 'inherit'.

nodeCommand(config: Omit<NodeCommandConfig, 'type'>)

A builder function for defining arbitrary JavaScript/TypeScript actions.

  • action: An asynchronous function (options: Record<string, unknown>) => Promise<void> | void that executes when the command is invoked.

Development

This package adheres to the global monorepo standards outlined in GEMINI.md:

  • Strict TypeScript: No any types are permitted.
  • TSDoc: All exported members must include comprehensive TSDoc comments.
  • TDD: Modifications and new builders should be accompanied by Vitest unit tests.