{"id":13686745,"url":"https://github.com/fxjs-modules/cli","last_synced_at":"2026-06-17T07:32:29.356Z","repository":{"id":122982941,"uuid":"189879993","full_name":"fxjs-modules/cli","owner":"fxjs-modules","description":"fibjs Cli builder","archived":false,"fork":false,"pushed_at":"2022-09-30T19:02:21.000Z","size":56,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-08T08:04:12.748Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fxjs-modules.png","metadata":{"files":{"readme":"README.md","changelog":"History.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2019-06-02T18:17:09.000Z","updated_at":"2022-09-30T18:44:35.000Z","dependencies_parsed_at":"2023-03-13T12:16:43.599Z","dependency_job_id":null,"html_url":"https://github.com/fxjs-modules/cli","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/fxjs-modules/cli","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fxjs-modules%2Fcli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fxjs-modules%2Fcli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fxjs-modules%2Fcli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fxjs-modules%2Fcli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fxjs-modules","download_url":"https://codeload.github.com/fxjs-modules/cli/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fxjs-modules%2Fcli/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34439296,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-17T02:00:05.408Z","response_time":127,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T15:00:39.299Z","updated_at":"2026-06-17T07:32:29.340Z","avatar_url":"https://github.com/fxjs-modules.png","language":"TypeScript","funding_links":[],"categories":["Packages"],"sub_categories":["Command Line"],"readme":"[![NPM version](https://img.shields.io/npm/v/@fxjs/cli.svg?style=flat)](https://npmjs.com/package/@fxjs/cli)\n[![NPM downloads](https://img.shields.io/npm/dm/@fxjs/cli.svg?style=flat)](https://npmjs.com/package/@fxjs/cli)\n[![Build Status](https://travis-ci.org/fxjs-modules/cli.svg)](https://travis-ci.org/fxjs-modules/cli)\n[![Build status](https://ci.appveyor.com/api/projects/status/61m8kfc4hg7msuap?svg=true)](https://ci.appveyor.com/project/richardo2016/cli)\n\n## Introduction\n\n**FCli** is a fibjs Cli builder, almost migration of [cac.js] from node.js to fibjs\n\n## Features\n\n- **Commander.js Like**: There's a large deal of users of [commander.js] in node.js ecosystem, FCli has similar APIs with [commander.js].\n- **Easy to learn**. There're only 4 APIs you need to learn for building simple CLIs: `cli.option` `cli.version` `cli.help` `cli.parse`.\n- **utility features**. Enable features like\n  - default command\n  - **git-like** subcommands\n  - validation for required arguments and options\n  - rest arguments\n  - dot-nested options, automated help message generation and so on.\n\n## Table of Contents\n\n\u003c!-- toc --\u003e\n\n- [Install](#install)\n- [Usage](#usage)\n  - [Simple Parsing](#simple-parsing)\n  - [Display Help Message and Version](#display-help-message-and-version)\n  - [Command-specific Options](#command-specific-options)\n  - [Brackets](#brackets)\n  - [Rest Arguments](#rest-arguments)\n  - [Dot-style Options](#dot-nested-options)\n  - [Default Command](#default-command)\n  - [Supply an array as option value](#supply-an-array-as-option-value)\n  - [With TypeScript](#with-typescript)\n  - [With Deno](#with-deno)\n- [References](#references)\n  - [CLI Instance](#cli-instance)\n    - [@fxjs/cli(name?)](#fxjscliname)\n    - [cli.command(name, description, config?)](#clicommandname-description-config)\n    - [cli.option(name, description, config?)](#clioptionname-description-config)\n    - [cli.parse(argv?)](#cliparseargv)\n    - [cli.version(version, customFlags?)](#cliversionversion-customflags)\n    - [cli.help(callback?)](#clihelpcallback)\n    - [cli.outputHelp(subCommand?)](#clioutputhelpsubcommand)\n  - [Command Instance](#command-instance)\n    - [command.option()](#commandoption)\n    - [command.action(callback)](#commandactioncallback)\n    - [command.alias(name)](#commandaliasname)\n    - [command.example(example)](#commandexampleexample)\n  - [Events](#events)\n- [FAQ](#faq)\n  - [How is the name written and pronounced?](#how-is-the-name-written-and-pronounced)\n  - [Why not use Commander.js?](#why-not-use-commanderjs)\n- [Contributing](#contributing)\n- [Author](#author)\n\n\u003c!-- tocstop --\u003e\n\n## Install\n\n```bash\nnpm i -S @fxjs/cli\n# or\nfibjs --install @fxjs/cli\n```\n\n## Usage\n\n### Simple Parsing\n\nUse FCli as simple argument parser:\n\n```js\n// examples/basic-usage.js\nconst cli = require('@fxjs/cli')()\n\ncli.option('--type \u003ctype\u003e', 'Choose a project type', {\n  default: 'node'\n})\n\nconst parsed = cli.parse()\n\nconsole.dir(parsed)\n```\n\n\u003cimg src=\"https://user-images.githubusercontent.com/6339390/58762798-09eab780-8586-11e9-8459-cdf361ddbf44.png\" alt=\"image\" style=\"max-width:100%;\"\u003e\n\n### Display Help Message and Version\n\n```js\n// examples/help.js\nconst cli = require('@fxjs/cli')()\n\ncli.option('--type [type]', 'Choose a project type', {\n  default: 'node'\n})\ncli.option('--name \u003cname\u003e', 'Provide your name')\n\ncli.command('lint [...files]', 'Lint files').action((files, options) =\u003e {\n  console.log(files, options)\n})\n\n// Display help message when `-h` or `--help` appears\ncli.help()\n// Display version number when `-v` or `--version` appears\n// It's also used in help message\ncli.version('0.0.0')\n\ncli.parse()\n```\n\n\u003cimg src=\"https://user-images.githubusercontent.com/6339390/58762812-36063880-8586-11e9-9796-2b053db5dbf8.png\" alt=\"image\" style=\"max-width:100%;\"\u003e\n\n### Command-specific Options\n\nYou can attach options to a command.\n\n```js\nconst cli = require('@fxjs/cli')()\n\ncli\n  .command('rm \u003cdir\u003e', 'Remove a dir')\n  .option('-r, --recursive', 'Remove recursively')\n  .action((dir, options) =\u003e {\n    console.log('remove ' + dir + (options.recursive ? ' recursively' : ''))\n  })\n\ncli.help()\n\ncli.parse()\n```\n\n\u003cimg src=\"https://user-images.githubusercontent.com/6339390/58762857-9ac19300-8586-11e9-98c9-12add42e1d3a.png\" alt=\"image\" style=\"max-width:100%;\"\u003e\n\nA command's options are validated when the command is used. Any unknown options will be reported as an error by default. However, if an action-based command does not define an action, then the options are not validated. If you really want to use unknown options, pass `allowUnknownOptions: true` when initializing the command, like this:\n\n```js\nconst cli = require('@fxjs/cli')()\n\ncli\n  .command('rm \u003cdir\u003e', 'Remove a dir', {\n    allowUnknownOptions: true\n  })\n  .option('-r, --recursive', 'Remove recursively')\n  .action((dir, options) =\u003e {\n    console.log('remove ' + dir + (options.recursive ? ' recursively' : ''))\n  })\n```\n\n### Brackets\n\nWhen using brackets in command name, angled brackets indicate required command arguments, while square bracket indicate optional arguments.\n\nWhen using brackets in option name, angled brackets indicate that a string / number value is required, while square bracket indicate that the value can also be `true`.\n\n```js\nconst cli = require('@fxjs/cli')()\n\ncli\n  .command('deploy \u003cfolder\u003e', 'Deploy a folder to AWS')\n  .option('--scale [level]', 'Scaling level')\n  .action((folder, options) =\u003e {\n    // ...\n  })\n\ncli\n  .command('build [project]', 'Build a project')\n  .option('--out \u003cdir\u003e', 'Output directory')\n  .action((folder, options) =\u003e {\n    // ...\n  })\n\ncli.parse()\n```\n\nTo allow an option whose value is `false`, you need to manually speicfy a negative option:\n\n```js\ncli\n  .command('build [project]', 'Build a project')\n  .option('--no-config', 'Disable config file')\n  .option('--config \u003cpath\u003e', 'Use a custom config file')\n```\n\nThis will let FCli set the default value of `config` to true, and you can use `--no-config` flag to set it to `false`.\n\n### Rest Arguments\n\nThe last argument of a command can be rest, and only the last argument. To make an argument rest you have to add `...` to the start of argument name, just like the rest operator in JavaScript. Here is an example:\n\n```js\nconst cli = require('@fxjs/cli')()\n\ncli\n  .command('build \u003centry\u003e [...otherFiles]', 'Build your app')\n  .option('--foo', 'Foo option')\n  .action((entry, otherFiles, options) =\u003e {\n    console.log(entry)\n    console.log(otherFiles)\n    console.log(options)\n  })\n\ncli.help()\n\ncli.parse()\n```\n\n\u003cimg src=\"https://user-images.githubusercontent.com/6339390/58765401-4da0e980-85a5-11e9-9c6c-2081b56ce8ef.png\" alt=\"image\" style=\"max-width:100%;\"\u003e\n\n### Dot-style Options\n\nDot-style options will be merged into a single option.\n\n```js\nconst cli = require('@fxjs/cli')()\n\ncli\n  .command('build', 'desc')\n  .option('--env \u003cenv\u003e', 'Set envs')\n  .example('--env.API_SECRET xxx')\n  .action(options =\u003e {\n    console.log(options)\n  })\n\ncli.help()\n\ncli.parse()\n```\n\n\u003cimg src=\"https://user-images.githubusercontent.com/6339390/58762916-6e5a4680-8587-11e9-8e9b-7fb194a0c63e.png\" alt=\"image\" style=\"max-width:100%;\"\u003e\n\n### Default Command\n\nRegister a command that will be used when no other command is matched.\n\n```js\nconst cli = require('@fxjs/cli')()\n\ncli\n  // Simply omit the command name, just brackets\n  .command('[...files]', 'Build files')\n  .option('--minimize', 'Minimize output')\n  .action((files, options) =\u003e {\n    console.log(files)\n    console.log(options.minimize)\n  })\n\ncli.parse()\n```\n\n### Supply an array as option value\n\n```bash\nnode cli.js --include project-a\n# The parsed options will be:\n# { include: 'project-a' }\n\nnode cli.js --include project-a --include project-b\n# The parsed options will be:\n# { include: ['project-a', 'project-b'] }\n```\n\n## References\n\n### CLI Instance\n\nCLI instance is created by invoking the `@fxjs/cli` function:\n\n```js\nconst cli = require('@fxjs/cli')()\n```\n\n#### @fxjs/cli(name?)\n\nCreate a CLI instance, optionally specify the program name which will be used to display in help and version message. When not set we use the basename of `argv[1]`.\n\n#### cli.command(name, description, config?)\n\n- Type: `(name: string, description: string) =\u003e Command`\n\nCreate a command instance.\n\nThe option also accepts a third argument `config` for additional command config:\n\n- `config.allowUnknownOptions`: `boolean` Allow unknown options in this command.\n- `config.ignoreOptionDefaultValue`: `boolean` Don't use the options's default value in parsed options, only display them in help message.\n\n#### cli.option(name, description, config?)\n\n- Type: `(name: string, description: string, config?: OptionConfig) =\u003e CLI`\n\nAdd a global option.\n\nThe option also accepts a third argument `config` for additional option config:\n\n- `config.default`: Default value for the option.\n- `config.type`: `any[]` When set to `[]`, the option value returns an array type. You can also use a conversion function such as `[String]`, which will invoke the option value with `String`.\n\n#### cli.parse(argv?)\n\n- Type: `(argv = process.argv) =\u003e ParsedArgv`\n\n```ts\ninterface ParsedArgv {\n  args: string[]\n  options: {\n    [k: string]: any\n  }\n}\n```\n\nWhen this method is called, `cli.rawArgs` `cli.args` `cli.options` `cli.matchedCommand` will also be available.\n\n#### cli.version(version, customFlags?)\n\n- Type: `(version: string, customFlags = '-v, --version') =\u003e CLI`\n\nOutput version number when `-v, --version` flag appears.\n\n#### cli.help(callback?)\n\n- Type: `(callback?: HelpCallback) =\u003e CLI`\n\nOutput help message when `-h, --help` flag appears.\n\nOptional `callback` allows post-processing of help text before it is displayed:\n\n```ts\ntype HelpCallback = (sections: HelpSection[]) =\u003e void\n\ninterface HelpSection {\n  title?: string\n  body: string\n}\n```\n\n#### cli.outputHelp(subCommand?)\n\n- Type: `(subCommand?: boolean) =\u003e CLI`\n\nOutput help message. Optional `subCommand` argument if you want to output the help message for the matched sub-command instead of the global help message.\n\n### Command Instance\n\nCommand instance is created by invoking the `cli.command` method:\n\n```js\nconst command = cli.command('build [...files]', 'Build given files')\n```\n\n#### command.option()\n\nBasically the same as `cli.option` but this adds the option to specific command.\n\n#### command.action(callback)\n\n- Type: `(callback: ActionCallback) =\u003e Command`\n\nUse a callback function as the command action when the command matches user inputs.\n\n```ts\ntype ActionCallback = (\n  // Parsed CLI args\n  // The last arg will be an array if it's an varadic argument\n  ...args: string | string[] | number | number[]\n  // Parsed CLI options\n  options: Options\n) =\u003e any\n\ninterface Options {\n  [k: string]: any\n}\n```\n\n#### command.alias(name)\n\n- Type: `(name: string) =\u003e Command`\n\nAdd an alias name to this command, the `name` here can't contain brackets.\n\n#### command.allowUnknownOptions()\n\n- Type: `() =\u003e Command`\n\nAllow unknown options in this command, by default FCli will log an error when unknown options are used.\n\n#### command.example(example)\n\n- Type: `(example: CommandExample) =\u003e Command`\n\nAdd an example which will be displayed at the end of help message.\n\n```ts\ntype CommandExample = ((name: string) =\u003e string) | string\n```\n\n### Events\n\nListen to commands:\n\n```js\n// Listen to the `foo` command\ncli.on('command:foo', () =\u003e {\n  // Do something\n})\n\n// Listen to the default command\ncli.on('command:!', () =\u003e {\n  // Do something\n})\n\n// Listen to unknown commands\ncli.on('command:*', () =\u003e {\n  console.error('Invalid command: %', cli.args.join(' '))\n  process.exit(1)\n})\n```\n\n## Q \u0026 A\n\n### Why not cac.js directly?\n\n**@fxjs/cli** is inspired by [cac.js]\n\n[cac.js] is one lightweight, fast cli builder for node.js/deno app, [egoist], author of [cac.js], were managed to make convenient and elegant tool for javascript ecosystem.\n\nIn fact, I trid to make PR to [cac.js] to make it support fibjs, in a way, it's much better than [commander.js] in  **cross-platform**, you would never find and node.js specific API in [cac.js]! As a contrast, `require('child_process')` is just writeen in [commander.js]'s source code, that made it difficult running [commander.js] in fibjs.\n\nBut there's some typically better APIs in fibjs that cac.js cannot use --- if do so, [cac.js]'s source code would contains many fibjs-only codes, useless for node.js/deno, that would mutilate elegant structure of [cac.js]\n\nThe 2nd best, I copid test cases and examples from [cac.js] as initial test case as **@fxjs/cli**, then I reimplement almost features of [cac.js] and add some fibjs specific features in **@fxjs/cli**. \n\nThx much to [egoist] and other contributors' of [cac.js] :)\n\n## License\n\n- [MIT](./LICENSE)\n- [cac.js MIT License]\n\n[commander.js]:https://www.npmjs.com/package/commander\n[cac.js]:https://github.com/cacjs/cac\n[egoist]:https://github.com/egoist\n[cac.js MIT License]:https://github.com/cacjs/cac/blob/e5f32f7c9dc83a4f12ccea2acbf43c814773c7f3/LICENSE\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffxjs-modules%2Fcli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffxjs-modules%2Fcli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffxjs-modules%2Fcli/lists"}