{"id":13392519,"url":"https://github.com/cacjs/cac","last_synced_at":"2026-01-11T18:04:47.283Z","repository":{"id":37663697,"uuid":"49640289","full_name":"cacjs/cac","owner":"cacjs","description":"Simple yet powerful framework for building command-line apps.","archived":false,"fork":false,"pushed_at":"2024-07-09T09:45:18.000Z","size":1814,"stargazers_count":2767,"open_issues_count":65,"forks_count":106,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-05-14T02:09:19.215Z","etag":null,"topics":["cli","command-line","commander","deno","framework","minimist","node"],"latest_commit_sha":null,"homepage":"","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/cacjs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"egoist","patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2016-01-14T10:27:18.000Z","updated_at":"2025-05-13T09:19:21.000Z","dependencies_parsed_at":"2023-02-05T02:01:13.377Z","dependency_job_id":"65432586-f3bb-491a-943a-0c5bbd8240d9","html_url":"https://github.com/cacjs/cac","commit_stats":{"total_commits":124,"total_committers":29,"mean_commits":4.275862068965517,"dds":0.2661290322580645,"last_synced_commit":"257b140085e8ef7527f3ce9628ae78ed29338ffb"},"previous_names":["egoist/cac"],"tags_count":120,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cacjs%2Fcac","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cacjs%2Fcac/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cacjs%2Fcac/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cacjs%2Fcac/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cacjs","download_url":"https://codeload.github.com/cacjs/cac/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254249206,"owners_count":22039029,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["cli","command-line","commander","deno","framework","minimist","node"],"created_at":"2024-07-30T17:00:26.227Z","updated_at":"2026-01-11T18:04:47.215Z","avatar_url":"https://github.com/cacjs.png","language":"TypeScript","readme":"\u003cimg width=\"945\" alt=\"2017-07-26 9 27 05\" src=\"https://user-images.githubusercontent.com/8784712/28623641-373450f4-7249-11e7-854d-1b076dab274d.png\"\u003e\n\n[![NPM version](https://img.shields.io/npm/v/cac.svg?style=flat)](https://npmjs.com/package/cac) [![NPM downloads](https://img.shields.io/npm/dm/cac.svg?style=flat)](https://npmjs.com/package/cac) [![CircleCI](https://circleci.com/gh/cacjs/cac/tree/master.svg?style=shield)](https://circleci.com/gh/cacjs/cac/tree/master) [![Codecov](https://badgen.net/codecov/c/github/cacjs/cac/master)](https://codecov.io/gh/cacjs/cac) [![donate](https://img.shields.io/badge/$-donate-ff69b4.svg?maxAge=2592000\u0026style=flat)](https://github.com/egoist/donate) [![install size](https://badgen.net/packagephobia/install/cac)](https://packagephobia.now.sh/result?p=cac)\n\n## Introduction\n\n**C**ommand **A**nd **C**onquer is a JavaScript library for building CLI apps.\n\n## Features\n\n- **Super light-weight**: No dependency, just a single file.\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- **Yet so powerful**. Enable features like default command, git-like subcommands, validation for required arguments and options, variadic arguments, dot-nested options, automated help message generation and so on.\n- **Developer friendly**. Written in TypeScript.\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  - [Dash in option names](#dash-in-option-names)\n  - [Brackets](#brackets)\n  - [Negated Options](#negated-options)\n  - [Variadic Arguments](#variadic-arguments)\n  - [Dot-nested Options](#dot-nested-options)\n  - [Default Command](#default-command)\n  - [Supply an array as option value](#supply-an-array-as-option-value)\n  - [Error Handling](#error-handling)\n  - [With TypeScript](#with-typescript)\n  - [With Deno](#with-deno)\n- [Projects Using CAC](#projects-using-cac)\n- [References](#references)\n  - [CLI Instance](#cli-instance)\n    - [cac(name?)](#cacname)\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()](#clioutputhelp)\n    - [cli.usage(text)](#cliusagetext)\n  - [Command Instance](#command-instance)\n    - [command.option()](#commandoption)\n    - [command.action(callback)](#commandactioncallback)\n    - [command.alias(name)](#commandaliasname)\n    - [command.allowUnknownOptions()](#commandallowunknownoptions)\n    - [command.example(example)](#commandexampleexample)\n    - [command.usage(text)](#commandusagetext)\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- [Project Stats](#project-stats)\n- [Contributing](#contributing)\n- [Author](#author)\n\n\u003c!-- tocstop --\u003e\n\n## Install\n\n```bash\nyarn add cac\n```\n\n## Usage\n\n### Simple Parsing\n\nUse CAC as simple argument parser:\n\n```js\n// examples/basic-usage.js\nconst cli = require('cac')()\n\ncli.option('--type \u003ctype\u003e', 'Choose a project type', {\n  default: 'node',\n})\n\nconst parsed = cli.parse()\n\nconsole.log(JSON.stringify(parsed, null, 2))\n```\n\n\u003cimg width=\"500\" alt=\"2018-11-26 12 28 03\" src=\"https://user-images.githubusercontent.com/8784712/48981576-2a871000-f112-11e8-8151-80f61e9b9908.png\"\u003e\n\n### Display Help Message and Version\n\n```js\n// examples/help.js\nconst cli = require('cac')()\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 width=\"500\" alt=\"2018-11-25 8 21 14\" src=\"https://user-images.githubusercontent.com/8784712/48979012-acb20d00-f0ef-11e8-9cc6-8ffca00ab78a.png\"\u003e\n\n### Command-specific Options\n\nYou can attach options to a command.\n\n```js\nconst cli = require('cac')()\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\nA command's options are validated when the command is used. Any unknown options will be reported as an error. 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, use [`command.allowUnknownOptions`](#commandallowunknownoptions).\n\n\u003cimg alt=\"command options\" width=\"500\" src=\"https://user-images.githubusercontent.com/8784712/49065552-49dc8500-f259-11e8-9c7b-a7c32d70920e.png\"\u003e\n\n### Dash in option names\n\nOptions in kebab-case should be referenced in camelCase in your code:\n\n```js\ncli\n  .command('dev', 'Start dev server')\n  .option('--clear-screen', 'Clear screen')\n  .action((options) =\u003e {\n    console.log(options.clearScreen)\n  })\n```\n\nIn fact `--clear-screen` and `--clearScreen` are both mapped to `options.clearScreen`.\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('cac')()\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\n### Negated Options\n\nTo allow an option whose value is `false`, you need to manually specify a negated 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 CAC set the default value of `config` to true, and you can use `--no-config` flag to set it to `false`.\n\n### Variadic Arguments\n\nThe last argument of a command can be variadic, and only the last argument. To make an argument variadic 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('cac')()\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 width=\"500\" alt=\"2018-11-25 8 25 30\" src=\"https://user-images.githubusercontent.com/8784712/48979056-47125080-f0f0-11e8-9d8f-3219e0beb0ed.png\"\u003e\n\n### Dot-nested Options\n\nDot-nested options will be merged into a single option.\n\n```js\nconst cli = require('cac')()\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 width=\"500\" alt=\"2018-11-25 9 37 53\" src=\"https://user-images.githubusercontent.com/8784712/48979771-6ada9400-f0fa-11e8-8192-e541b2cfd9da.png\"\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('cac')()\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### Error Handling\n\nTo handle command errors globally:\n\n```js\ntry {\n  // Parse CLI args without running the command\n  cli.parse(process.argv, { run: false })\n  // Run the command yourself\n  // You only need `await` when your command action returns a Promise\n  await cli.runMatchedCommand()\n} catch (error) {\n  // Handle error here..\n  // e.g.\n  // console.error(error.stack)\n  // process.exit(1)\n}\n```\n\n### With TypeScript\n\nFirst you need `@types/node` to be installed as a dev dependency in your project:\n\n```bash\nyarn add @types/node --dev\n```\n\nThen everything just works out of the box:\n\n```js\nconst { cac } = require('cac')\n// OR ES modules\nimport { cac } from 'cac'\n```\n\n### With Deno\n\n```ts\nimport { cac } from 'https://unpkg.com/cac/mod.ts'\n\nconst cli = cac('my-program')\n```\n\n## Projects Using CAC\n\nProjects that use **CAC**:\n\n- [VuePress](https://github.com/vuejs/vuepress): :memo: Minimalistic Vue-powered static site generator.\n- [SAO](https://github.com/egoist/sao): ⚔️ Futuristic scaffolding tool.\n- [DocPad](https://github.com/docpad/docpad): 🏹 Powerful Static Site Generator.\n- [Poi](https://github.com/egoist/poi): ⚡️ Delightful web development.\n- [bili](https://github.com/egoist/bili): 🥂 Schweizer Armeemesser for bundling JavaScript libraries.\n- [Lad](https://github.com/ladjs/lad): 👦 Lad scaffolds a Koa webapp and API framework for Node.js.\n- [Lass](https://github.com/lassjs/lass): 💁🏻 Scaffold a modern package boilerplate for Node.js.\n- [Foy](https://github.com/zaaack/foy): 🏗 A lightweight and modern task runner and build tool for general purpose.\n- [Vuese](https://github.com/vuese/vuese): 🤗 One-stop solution for vue component documentation.\n- [NUT](https://github.com/nut-project/nut): 🌰 A framework born for microfrontends\n- Feel free to add yours here...\n\n## References\n\n**💁 Check out [the generated docs](https://cac-api-doc.egoist.dev/classes/_cac_.cac.html) from source code if you want a more in-depth API references.**\n\nBelow is a brief overview.\n\n### CLI Instance\n\nCLI instance is created by invoking the `cac` function:\n\n```js\nconst cac = require('cac')\nconst cli = cac()\n```\n\n#### cac(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()\n\n- Type: `() =\u003e CLI`\n\nOutput help message.\n\n#### cli.usage(text)\n\n- Type: `(text: string) =\u003e CLI`\n\nAdd a global usage text. This is not used by sub-commands.\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 a variadic 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 CAC 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#### command.usage(text)\n\n- Type: `(text: string) =\u003e Command`\n\nAdd a usage text for this command.\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: %s', cli.args.join(' '))\n  process.exit(1)\n})\n```\n\n## FAQ\n\n### How is the name written and pronounced?\n\nCAC, or cac, pronounced `C-A-C`.\n\nThis project is dedicated to our lovely C.C. sama. Maybe CAC stands for C\u0026C as well :P\n\n\u003cimg src=\"http://i.giphy.com/v3FeH4swox9mg.gif\" width=\"400\"/\u003e\n\n### Why not use Commander.js?\n\nCAC is very similar to Commander.js, while the latter does not support dot nested options, i.e. something like `--env.API_SECRET foo`. Besides, you can't use unknown options in Commander.js either.\n\n_And maybe more..._\n\nBasically I made CAC to fulfill my own needs for building CLI apps like [Poi](https://poi.js.org), [SAO](https://sao.vercel.app) and all my CLI apps. It's small, simple but powerful :P\n\n## Project Stats\n\n![Alt](https://repobeats.axiom.co/api/embed/58caf6203631bcdb9bbe22f0728a0af1683dc0bb.svg 'Repobeats analytics image')\n\n## Contributing\n\n1. Fork it!\n2. Create your feature branch: `git checkout -b my-new-feature`\n3. Commit your changes: `git commit -am 'Add some feature'`\n4. Push to the branch: `git push origin my-new-feature`\n5. Submit a pull request :D\n\n## Author\n\n**CAC** © [EGOIST](https://github.com/egoist), Released under the [MIT](./LICENSE) License.\u003cbr\u003e\nAuthored and maintained by egoist with help from contributors ([list](https://github.com/cacjs/cac/contributors)).\n\n\u003e [Website](https://egoist.dev) · GitHub [@egoist](https://github.com/egoist) · Twitter [@\\_egoistlily](https://twitter.com/_egoistlily)\n","funding_links":["https://github.com/sponsors/egoist"],"categories":["TypeScript","Repository","Uncategorized","JavaScript","Modules","源码阅读推荐","cli",":books: Libraries","Table of Contents"],"sub_categories":["Command-line Utilities","Uncategorized","Online Playgrounds","CLI utils","Assistants","独特之处 🦖🦕","Node","Command Line"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcacjs%2Fcac","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcacjs%2Fcac","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcacjs%2Fcac/lists"}