@ideascol/cli-maker
v1.11.0
Published
A simple library to help create CLIs
Downloads
273
Readme
@ideascol/cli-maker
A library to help create CLIs with support for command parameters and interactive prompts.
Quick start
npx @ideascol/cli-makerInstallation
To install the library, use npm:
npm install -g @ideascol/cli-makerCreate your own CLI
cli-makerUsage
To use the library, import the CliMaker class and create a new instance of it. Then, you can add commands and prompts to the CLI.
const { CLI, ParamType } = require('@ideascol/cli-maker');
const cli = new CLI("mycli", "A simple CLI", {
interactive: true,
version: '0.0.1',
branding: true, // Show GitHub star message (default: true)
introAnimation: {
enabled: true, // Show intro once per machine (unless overridden)
preset: 'retro-space', // Presets: retro-space, hacker, vaporwave, radar, pixel, steampunk, sonar
title: 'mycli', // Defaults to the CLI name
subtitle: 'A simple CLI',// Defaults to the CLI description
// Override any preset field if you want:
// frames: ['✦', '✹', '✸', '✺'],
// speedMs: 90,
// loops: 2,
// lines: ['Built with cli-maker'],
// introMode: 'always',
// asciiArt: ['custom ascii...'],
},
});
let commandExample = {
name: 'all-params',
description: 'Show all params',
params: [
{
name: 'favorite_fruit',
description: 'select your favorite fruit',
required: true,
type: ParamType.List,
options: ['manzana', 'pera', 'uva']
},
{
name: 'url',
description: 'The URL of your website',
type: ParamType.Url,
required: true
},
{
name: "is_ok",
description: "Is the user ok? (true or false)",
type: ParamType.Boolean,
},
{
name: 'email',
description: 'The email',
type: ParamType.Email,
required: true
},
{
name: 'age',
description: 'The age of the user',
type: ParamType.Number,
},
{
name: 'metadata',
description: 'List of tags',
type: ParamType.List,
options: ["tag1", "tag2"],
},
{
name: 'tags',
description: '(["tag1", "tag2"] or {"key1": "value1", "key2": "value2"})',
type: ParamType.Custom,
required: false,
}
],
action: (args) => {
console.log('EXAMPLE DATA');
console.log(args);
}
}
cli.command(commandExample);
cli.parse(process.argv);
Intro animation (first run)
Set introAnimation.enabled to true to display a small animated header the first time someone runs your CLI. A marker file is stored in ~/.cli-maker/<your-cli>-intro.json so the intro is only shown once by default. You can customize the frames, title, subtitle, and extra lines or disable the persistence with showOnce: false.
To force the intro on any run (ignoring the stored marker), run your CLI with --intro-always. To skip it once, use --no-intro.
You can also configure this behavior via introAnimation.introMode:
introMode: 'always'to always show.introMode: 'never'to never show.- Omit it (default) to show once with the stored marker.
- Text animates progressively by default; set
animateText: falseto disable.
Available presets for introAnimation.preset:
retro-space(naves y escáner)hacker(cursor parpadeante)vaporwave(frames ✦ ✺ ✹ ✸)radar(barras en arco)pixel(bloques ░▒▓█)steampunk(engranes ⚙)sonar(ondas ◉◎)rainbow(bordes y frames multicolor)
Setup command (step by step interactive)
You can generate a setup command for global variables:
import { CLI, ParamType } from '@ideascol/cli-maker';
const cli = new CLI('mycli', 'Demo CLI');
// Simplified method: setupCommand automatically infers the CLI name
cli.setupCommand({
name: 'setup', // optional, defaults to 'setup'
description: 'Configure global preferences', // optional
steps: [
{ name: 'api_key', description: 'API key', required: true, type: ParamType.Text },
{ name: 'environment', description: 'Select environment', type: ParamType.List, options: ['dev', 'staging', 'prod'], required: true },
{ name: 'telemetry', description: 'Allow metrics', type: ParamType.Boolean, defaultValue: true },
{ name: 'secret', description: 'Secret key', type: ParamType.Password, required: true },
],
encryption: {
enabled: true,
prompt: 'Passphrase para cifrar/descifrar',
},
});
cli.parse(process.argv);Alternatively, you can still use the standalone createSetupCommand function:
import { CLI, ParamType, createSetupCommand } from '@ideascol/cli-maker';
const cli = new CLI('mycli', 'Demo CLI');
const setup = createSetupCommand('mycli', { /* options */ });
cli.command(setup);The stored config is saved in ~/.cli-maker/<cli>-config.json (puedes cambiarlo con configFileName). Uses the previous value as default if exists, and validates according to ParamType.
Password fields are asked with hidden input and are stored in base64 (with __b64 marker) to avoid leaving them in plain text. If a previous value exists, it is masked.
To read the configuration in code:
import { CLI, ParamType } from '@ideascol/cli-maker';
const cli = new CLI('mycli', 'Demo CLI');
// First, define your setup command
cli.setupCommand({
steps: [
{ name: 'api_key', description: 'API key', type: ParamType.Password, required: true },
{ name: 'environment', description: 'Environment', type: ParamType.List, options: ['dev', 'prod'] },
],
encryption: { enabled: true },
});
// Then use the CLI methods to access config
cli.command({
name: 'deploy',
description: 'Deploy to server',
params: [],
action: async () => {
// Method 1: Load all config (automatically prompts for passphrase if Password fields exist)
const config = await cli.loadConfig();
console.log(config.api_key, config.environment);
// Method 2: Get a specific value (automatically prompts for passphrase if it's a Password field)
const apiKey = await cli.getConfigValue('api_key'); // Will prompt for passphrase
const env = await cli.getConfigValue('environment'); // No passphrase needed (not a Password field)
// Optional: Provide passphrase programmatically to avoid prompt
const apiKeyWithPass = await cli.getConfigValue('api_key', 'my-passphrase');
}
});Standalone functions (still available for advanced use cases):
import { loadSetupConfig, getRawConfig, getConfigValue } from '@ideascol/cli-maker';
// Load with decryption (requires steps and passphrase)
const config = loadSetupConfig('mycli', steps, { passphrase: 'my-pass' });
// Get raw config (no decryption)
const rawConfig = getRawConfig('mycli');
// Get specific value (no decryption)
const environment = getConfigValue('mycli', 'environment');Utility Functions
prompt and hiddenPrompt
You can use prompt and hiddenPrompt utility functions in your command actions:
import { prompt, hiddenPrompt } from '@ideascol/cli-maker';
cli.command({
name: 'login',
description: 'Login to the service',
params: [],
action: async () => {
const username = await prompt('Enter your username: ');
const password = await hiddenPrompt('Enter your password (hidden): ');
console.log(`Logging in as ${username}...`);
// Your login logic here
}
});prompt(question: string): Prompts the user for visible inputhiddenPrompt(question: string): Prompts the user for hidden input (password-like, input is not displayed)
CLI Static Methods
The CLI class also provides static methods for prompting users, which can be used anywhere without creating a CLI instance:
import { CLI } from '@ideascol/cli-maker';
// Prompt for visible input
const name = await CLI.askQuestion('What is your name? ');
console.log(`Hello, ${name}!`);
// Prompt for hidden input (password-like)
const secret = await CLI.askHiddenQuestion('Enter your secret key: ');
console.log(`Secret received (length: ${secret.length})`);CLI.askQuestion(question: string): Static method to prompt for visible inputCLI.askHiddenQuestion(question: string): Static method to prompt for hidden input (shows asterisks)
Password Type in Interactive Mode
When using ParamType.Password in interactive mode, the input is automatically hidden from the screen, providing a secure way to collect sensitive information:
cli.command({
name: 'secure-command',
description: 'Command with password parameter',
params: [
{
name: 'secret',
description: 'Your secret key',
required: true,
type: ParamType.Password
}
],
action: (args) => {
console.log('Secret received (length):', args.secret.length);
}
});