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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@robojs/cli

v0.1.0-next.0

Published

Build standalone CLIs with Robo.js - file-based routing for command-line tools

Downloads

56

Readme


@robojs/cli

Build standalone command-line applications with file-based routing powered by Robo.js. Create professional CLIs with minimal boilerplate, automatic help generation, and full TypeScript support.

Features

  • File-based routing - Commands map directly to files
  • Automatic help generation - Help text generated from your config
  • Subcommand support - Nested directories become subcommands
  • Type-safe options - Full TypeScript inference for command options
  • Zero config - Works out of the box

Installation

Add to your existing Robo.js project:

npx robo add @robojs/cli

Or create a new project with the plugin:

npx create-robo my-cli -p @robojs/cli

Quick Start

1. Create a command

Create src/cli/hello.ts:

import { createCliCommandConfig, type CliContext } from 'robo.js/cli.js'

export const config = createCliCommandConfig({
	description: 'Say hello to someone',
	options: [{ alias: '-n', name: '--name', description: 'Name to greet', type: 'string', default: 'World' }]
} as const)

export default (ctx: CliContext<typeof config>) => {
	console.log(`Hello, ${ctx.options.name}!`)
}

2. Build and link

npx robo build
npm link

The bin field is automatically added to package.json during build, and npm link makes your CLI available by name.

3. Run it

my-cli hello
# Hello, World!

my-cli hello --name Robo
# Hello, Robo!

Development

Use robo dev for watch mode — your CLI rebuilds automatically on every file change:

npx robo dev

The bin field is automatically added to package.json during build if it doesn't exist yet. To test with your actual CLI name, link your package:

npm link
mycli hello --name Robo

During robo dev, the interactive terminal provides /cli link (runs the link command for you), /cli list, and /cli run <command> for quick testing.

👉 Full development guide

Creating Commands

Commands are created by placing files in src/cli/. The file path determines the command name.

Basic Command

// src/cli/greet.ts
// Usage: mycli greet

export const config = {
	description: 'Greet the user'
}

export default () => {
	console.log('Hello!')
}

Command with Options

// src/cli/build.ts
// Usage: mycli build --watch --output ./dist

import { createCliCommandConfig, type CliContext } from 'robo.js/cli.js'

export const config = createCliCommandConfig({
	description: 'Build the project',
	options: [
		{ alias: '-w', name: '--watch', description: 'Watch for changes', type: 'boolean' },
		{ alias: '-o', name: '--output', description: 'Output directory', type: 'string', default: './build' }
	]
} as const)

export default (ctx: CliContext<typeof config>) => {
	console.log(`Building to ${ctx.options.output}...`)
	if (ctx.options.watch) {
		console.log('Watching for changes...')
	}
}

Subcommands

Create nested directories for subcommands:

src/cli/
├── db/
│   ├── index.ts      # mycli db
│   ├── migrate.ts    # mycli db migrate
│   └── seed.ts       # mycli db seed
└── config/
    ├── get.ts        # mycli config get
    └── set.ts        # mycli config set

Example subcommand:

// src/cli/db/migrate.ts
// Usage: mycli db migrate --target latest

import { createCliCommandConfig, type CliContext } from 'robo.js/cli.js'

export const config = createCliCommandConfig({
	description: 'Run database migrations',
	options: [
		{ alias: '-t', name: '--target', description: 'Target version', type: 'string', default: 'latest' },
		{ alias: '-f', name: '--force', description: 'Force migration', type: 'boolean' }
	]
} as const)

export default (ctx: CliContext<typeof config>) => {
	console.log(`Migrating to ${ctx.options.target}...`)
	if (ctx.options.force) {
		console.log('Force mode enabled')
	}
}

Positional Arguments

Enable positional arguments to accept values without flags:

// src/cli/install.ts
// Usage: mycli install lodash express react

import { createCliCommandConfig, type CliContext } from 'robo.js/cli.js'

export const config = createCliCommandConfig({
	description: 'Install packages',
	positionalArgs: true
} as const)

export default (ctx: CliContext<typeof config>) => {
	const packages = ctx.args
	console.log(`Installing: ${packages.join(', ')}`)
}

Command Configuration

Option Properties

| Property | Type | Description | | ------------- | ----------------------------------- | -------------------------------- | | alias | string | Short flag (e.g., -n) | | name | string | Long flag (e.g., --name) | | description | string | Help text for this option | | type | 'string' \| 'boolean' \| 'number' | Value type (default: 'string') | | required | boolean | Whether the option is required | | default | any | Default value if not provided |

Option Type Inference

When using createCliCommandConfig with as const, TypeScript infers the correct types:

import { createCliCommandConfig, type CliContext } from 'robo.js/cli.js'

export const config = createCliCommandConfig({
	description: 'Example command',
	options: [
		{ alias: '-p', name: '--port', type: 'number', default: 3000 }, // number (has default)
		{ alias: '-h', name: '--host', type: 'string' }, // string | undefined
		{ alias: '-v', name: '--verbose', type: 'boolean', required: true } // boolean (required)
	]
} as const)

export default (ctx: CliContext<typeof config>) => {
	ctx.options.port // TypeScript knows: number
	ctx.options.host // TypeScript knows: string | undefined
	ctx.options.verbose // TypeScript knows: boolean
}

Command Context

The handler receives a context object with:

| Property | Type | Description | | --------- | ---------- | --------------------------- | | args | string[] | Positional arguments | | options | object | Parsed option values | | logger | Logger | Robo.js logger instance | | cwd | string | Current working directory | | argv | string[] | Raw arguments after command |

Publishing Your CLI

1. Configure package.json

The bin field is auto-added during build. Just make sure files includes the build output:

{
	"name": "my-awesome-cli",
	"version": "1.0.0",
	"files": [".robo/build"]
}

2. Build and publish

npx robo build
npm publish

3. Users can now run

npx my-awesome-cli hello
# or after global install
mycli hello

Project Structure

my-cli/
├── src/
│   └── cli/
│       ├── hello.ts               # CLI commands
│       ├── db/
│       │   ├── index.ts
│       │   └── migrate.ts
├── config/
│   └── robo.ts                    # Robo.js config
├── package.json
└── tsconfig.json

API Reference

Exports from robo.js/cli.js

// Configuration helper
import { createCliCommandConfig } from 'robo.js/cli.js'

// Types
import type {
	CliContext, // Command handler context
	CliCommandConfig, // Command configuration
	CliOptionConfig, // Option configuration
	CliHandler // Handler function type
} from 'robo.js/cli.js'

createCliCommandConfig

Type-safe configuration helper that enables TypeScript inference:

import { createCliCommandConfig, type CliContext } from 'robo.js/cli.js'

export const config = createCliCommandConfig({
	description: 'My command',
	options: [{ alias: '-n', name: '--name', type: 'string', required: true }]
} as const) // Don't forget `as const`!

export default (ctx: CliContext<typeof config>) => {
	// ctx.options.name is typed as `string`
}

More on Robo.js

Explore more about Robo.js:

Heads up! This is the plugin documentation. For extending the internal Robo CLI (adding commands to npx robo), see the CLI Extending Guide.