npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@nexical/cli-core

v0.1.12

Published

The core framework for building powerful, extensible Command Line Interfaces (CLIs) within the Nexical ecosystem.

Readme

@nexical/cli-core

The core framework for building powerful, extensible Command Line Interfaces (CLIs) within the Nexical ecosystem.

This package provides the foundational architecture for specialized CLI toolsets, including command discovery, execution orchestration, and a class-based command pattern. It is designed to be agnostic, allowing it to be used as the backbone for other CLI tools that need a similar structure and extensibility.

Table of Contents


Features

  • Class-Based Architecture: Build commands as TypeScript classes with inheritance and lifecycle methods.
  • Dynamic Discovery: Automatically recursively finds and registers commands from specified directories.
  • Type-Safe Definitions: Declarative definition of arguments and options.
  • Built-in Help: Automatic generation of help text for commands and subcommands.
  • Configuration Support: Aware of project-level configuration (e.g., {command_name}.yml).
  • Robust Error Handling: Standardized error reporting and debug modes.

Installation

This package is typically used as a dependency within a specific CLI implementation (like @astrical/cli).

npm install @nexical/cli-core

Usage

To use the core framework, you need to instantiate the CLI class and start it. This is typically done in your CLI's entry point (e.g., index.ts).

Configuration

The CLI class accepts a CLIConfig object to customize behavior:

import { CLI } from '@nexical/cli-core';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

const __dirname = path.dirname(fileURLToPath(import.meta.url));

const app = new CLI({
    // 1. The name of your binary/command (displayed in help)
    commandName: 'my-cli', 

    // 2. Directories to recursively search for command files
    searchDirectories: [
        path.resolve(__dirname, 'commands'),
        // You can add multiple directories, e.g., for plugins
        path.resolve(process.cwd(), 'plugins/commands')
    ]
});

app.start();

Directory Structure

A typical project using @nexical/cli-core looks like this:

my-cli/
├── package.json
├── src/
│   ├── index.ts        <-- Entry point (initializes CLI)
│   └── commands/       <-- Command files
│       ├── init.ts
│       ├── build.ts
│       └── module/     <-- Subcommands
│           ├── add.ts
│           └── list.ts

Creating Commands

The core framework itself only includes a Help command. All functional commands must be implemented by consuming libraries.

The BaseCommand

All commands must extend the BaseCommand abstract class exported by the core.

// src/commands/greet.ts
import { BaseCommand } from '@nexical/cli-core';

export default class GreetCommand extends BaseCommand {
    // Description shown in help
    static description = 'Greets the user';

    // Implement the run method
    async run(options: any) {
        this.info('Hello from my-cli!');
    }
}

Defining Arguments & Options

You can define arguments and options using the static args property.

export default class GreetCommand extends BaseCommand {
    static description = 'Greets the user with a custom message';

    static args = {
        // Positional arguments
        args: [
            { 
                name: 'name', 
                required: false, 
                description: 'Name to greet',
                default: 'World'
            }
        ],
        // Flags/Options
        options: [
            { 
                name: '--shout', 
                description: 'Print in uppercase', 
                default: false 
            },
            {
                name: '--count <n>',
                description: 'Number of times to greet',
                default: 1
            }
        ]
    };

    async run(options: any) {
        // 'name' comes from args (mapped to options by name)
        // 'shout' and 'count' come from options
        const { name, shout, count } = options;
        
        const message = `Hello, ${name}!`;
        const finalMessage = shout ? message.toUpperCase() : message;

        for (let i = 0; i < count; i++) {
            this.info(finalMessage);
        }
    }
}

Command Discovery Rules

The CommandLoader uses the file structure to determine command names:

  • File Name = Command Name:
    • commands/build.ts -> my-cli build
  • Nested Directories = Subcommands:
    • commands/user/create.ts -> my-cli user create
  • Index Files = Parent Command:
    • commands/user/index.ts -> my-cli user (The handler for the root user command)

Note: A file must default export a class extending BaseCommand to be registered.


Architecture

The core is built around three main components:

  1. CLI: The main entry point. It wraps CAC to handle argument parsing and acts as the dependency injection container for commands.
  2. CommandLoader: Scans the filesystem for command files. It handles importing typescript files and validating that they export a valid command class.
  3. BaseCommand: Provides the interface for commands, including:
    • init(): Async initialization hook (pre-run).
    • run(): The main execution logic.
    • this.projectRoot: Automatically resolved path to the project root (if running in a project context).
    • Output helpers:
      • this.success(msg): Logs success message (✔) in green.
      • this.warn(msg): Logs warning message (⚠) in yellow.
      • this.error(msg, code?): Logs error (✖) in red and exits.
      • this.notice(msg): Logs a notice (📢) in blue.
      • this.input(msg): Logs an input prompt display (?) in cyan.
      • this.info(msg): Standard informational message.
    • Input helpers:
      • this.prompt(msg): Prompts the user for input and returns the result.

License

Apache-2.0