{"id":15978306,"url":"https://github.com/tandrewnichols/simple-cli","last_synced_at":"2025-06-17T02:38:00.249Z","repository":{"id":20163724,"uuid":"23434379","full_name":"tandrewnichols/simple-cli","owner":"tandrewnichols","description":"A simple wrapper for grunt implementations of command line APIs","archived":false,"fork":false,"pushed_at":"2025-02-22T22:16:11.000Z","size":512,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-18T07:08:19.289Z","etag":null,"topics":["cli","grunt","grunt-plugin"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tandrewnichols.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2014-08-28T16:07:32.000Z","updated_at":"2025-02-22T22:16:12.000Z","dependencies_parsed_at":"2024-06-20T07:46:37.374Z","dependency_job_id":"f9ddbc58-5245-4609-926f-ff13a295faac","html_url":"https://github.com/tandrewnichols/simple-cli","commit_stats":{"total_commits":119,"total_committers":4,"mean_commits":29.75,"dds":0.2100840336134454,"last_synced_commit":"c77cfd67cd7f9c014ec291b37583490c6e104bfe"},"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/tandrewnichols/simple-cli","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tandrewnichols%2Fsimple-cli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tandrewnichols%2Fsimple-cli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tandrewnichols%2Fsimple-cli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tandrewnichols%2Fsimple-cli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tandrewnichols","download_url":"https://codeload.github.com/tandrewnichols/simple-cli/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tandrewnichols%2Fsimple-cli/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260278717,"owners_count":22985331,"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","grunt","grunt-plugin"],"created_at":"2024-10-07T23:08:12.949Z","updated_at":"2025-06-17T02:38:00.228Z","avatar_url":"https://github.com/tandrewnichols.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/tandrewnichols/simple-cli.png)](https://travis-ci.org/tandrewnichols/simple-cli) [![downloads](http://img.shields.io/npm/dm/simple-cli.svg)](https://npmjs.org/package/simple-cli) [![npm](http://img.shields.io/npm/v/simple-cli.svg)](https://npmjs.org/package/simple-cli) [![Code Climate](https://codeclimate.com/github/tandrewnichols/simple-cli/badges/gpa.svg)](https://codeclimate.com/github/tandrewnichols/simple-cli) [![Test Coverage](https://codeclimate.com/github/tandrewnichols/simple-cli/badges/coverage.svg)](https://codeclimate.com/github/tandrewnichols/simple-cli) [![dependencies](https://david-dm.org/tandrewnichols/simple-cli.png)](https://david-dm.org/tandrewnichols/simple-cli)\n\n# simple-cli\n\nGruntify command-line APIs with ease.\n\n## Installation\n\n```bash\nnpm install --save simple-cli\n```\n\n## API\n\n### cli(task[, options])\n\n`task` is a string that will be assigned as the name of the grunt task. It is also (by default) the name of the executable being wrapped, but you can override this with [cmd](#cmd-1).\n\n`options` is an object that configures how simple-cli handles the executable. See [options](#options).\n\n## Usage\n\nThis module is intended to be used with grunt to make writing plugin wrappers for command line tools easier to do. In your grunt task declaration, require this module and invoke it as follows:\n\n```js\nvar cli = require('simple-cli');\n\n// Or \"npm\" or \"hg\" or \"bower\" etc.\nmodule.exports = cli('git');\n```\n\nYes, that is _all_ that is necessary to build a fully functioning git plugin for grunt.\n\nThis module allows any command on the executable to be invoked as a target with any options specified (camel-cased) under options. It basically makes it possible to do anything the executable can do _in grunt_. Even options not normally a part of the tool (i.e. from a branch or fork) can be invoked with `simple-cli` because `simple-cli` doesn't allow options from a list of known options like most plugins for executables do. It, instead, assumes that the end-user _actually does know what he or she is doing_ and that he or she knows, or can look up, the available options. Below are the kinds of options that can be specified.\n\n## Options on the executable\n\nOptions provided to the executable are generated by \u003ca href=\"https://github.com/tandrewnichols/opted\" target=\"_blank\"\u003eopted\u003c/a\u003e, so check the documentation there. Practical examples follow:\n\nLet's write a wrapper for the super-awesome (and totally made up) `blerg` executable. First, we write the wrapper and publish it as `grunt-blerg` (or maybe `grunt-simple-blerg` since `grunt-blerg` is probably taken):\n\n```js\nvar cli = require('simple-cli');\n\nmodule.exports = cli('blerg');\n```\n\nDone. Now we can blerg on the command line via grunt! Let's see how an end-user would consume our new library.\n\n#### Long options\n\nYou can specify any long option under options with a corresponding value.\n\n```js\ngrunt.initConfig({\n  blerg: {\n    shazzam: {\n      options: {\n        foo: 'bar'\n      }\n    }\n  }\n});\n```\n\nThis will run `blerg shazzam --foo bar`.\n\n#### Multi-word options\n\nMulti-word options work too.\n\n```js\ngrunt.initConfig({\n  blerg: {\n    awesome: {\n      options: {\n        fooBar: 'baz'\n      }\n    }\n  }\n});\n```\n\nThis will run `blerg awesome --foo-bar baz`. Note the camel-casing for options with hyphens.\n\n#### Boolean options\n\nBut not all options have values. `blerg`, for example, has that super-user `--banana` option.\n\n```js\ngrunt.initConfig({\n  blerg: {\n    jazzhands: {\n      options: {\n        banana: true\n      }\n    }\n  }\n});\n```\n\nThis will run `blerg jazzhands --banana`.\n\n#### Short options\n\nYou can also use short options.\n\n```js\ngrunt.initConfig({\n  blerg: {\n    wasabi: {\n      options: {\n        a: 'foo'\n      }\n    }\n  }\n});\n```\n\nThis will run `blerg wasabi -a foo`.\n\n#### Short boolean options\n\nAnd short options as booleans.\n\n```js\ngrunt.initConfig({\n  blerg: {\n    hashbang: {\n      options: {\n        a: true\n      }\n    }\n  }\n});\n```\n\nThis will run `blerg hashbang -a`.\n\n#### Options with equal signs\n\nSome libraries have weird \"=\"-style options. Like git. And blerg.\n\n```js\ngrunt.initConfig({\n  blerg: {\n    nafblat: {\n      options: {\n        'bloogs=': 'meep'\n      }\n    }\n  }\n});\n```\n\nThis will run `blerg nafblat --bloogs=meep`.\n\n#### Arrays of options\n\nYou can also specify the same option more than once by passing an array.\n\n```js\ngrunt.initConfig({\n  blerg: {\n    murica: {\n      options: {\n        a: ['foo', 'bar'],\n        fruit: ['banana', 'kiwi']\n      }\n    }\n  }\n});\n```\n\nThis will run `blerg murica -a foo -a bar --fruit banana --fruit kiwi`.\n\n## Simple cli options\n\nThere are also some library specific options. Options about how simple cli itself behaves are placed at the top level of a task target.\n\n#### quiet\n\nSet to true to prevent logging during the child process. Regardless of the value of this flag, all stdout and stderr will be collected and passed to [onComplete](#onComplete). However, if it is not `true`, it will _also_ be logged as the process runs (similar to how `stdio: 'inherit'` works with `child_process.spawn`).\n\n```js\ngrunt.initConfig({\n  blerg: {\n    lollipop: {\n      options: {\n        foo: 'bar'\n      },\n      quiet: true\n    }\n  }\n});\n```\n\n#### env\n\nSupply additional environment variables to the child process. These variables are merged with `process.env`.\n\n```js\ngrunt.initConfig({\n  blerg: {\n    hoodoo: {\n      options: {\n        foo: 'bar'\n      },\n      env: {\n        BANANA: 'yellow'\n      }\n    }\n  }\n});\n```\n\nLike running `BANANA=yellow blerg hoodoo --foo bar`.\n\n#### cwd\n\nSet the current working directory for the child process.\n\n```js\ngrunt.initConfig({\n  blerg: {\n    jackwagon: {\n      options: {\n        foo: 'bar'\n      },\n      cwd: './test'\n    }\n  }\n});\n```\n\nRuns `blerg jackwagon --foo bar`, but in the `./test` directory.\n\n#### force\n\nIf the task fails, don't halt the entire task chain. Note that this is different that grunt's own `force` option. Really all this does is consume any error thrown . . . and simply ignore it.\n\n```js\ngrunt.initConfig({\n  blerg: {\n    muncher: {\n      force: true\n    }\n  }\n});\n```\n\n#### onComplete\n\nA callback to handle the stdout and stderr streams. `simple-cli` aggregates the stdout and stderr data output and will supply the final strings to the `onComplete` function. This function should have the signature `function(err, stdout, callback)` where `err` is an error object containing the stderr stream (if any errors were reported) and the code returned by the child process (as `err.code`), `stdout` is a string, and `callback` is a function. The callback must be called with a falsy value to complete the task (calling it with a truthy value - e.g. `1` - will fail the task).\n\n```js\ngrunt.initConfig({\n  blerg: {\n    portmanteau: {\n      onComplete: function(err, stdout, callback) {\n        if (err) {\n          grunt.fail.fatal(err.message, err.code);\n        } else {\n          grunt.config.set('portmanteau', stdout);\n          callback();\n        }\n      }\n    }\n  }\n});\n```\n\n#### cmd\n\nAn alternative sub-command to call on the cli. This is useful when you want to create multiple targets that call the same command with different options/parameters. If this value is present, it will be used instead of the grunt target as the first argument to the executable.\n\n```js\ngrunt.initConfig({\n  // Using git as a real example\n  git: {\n    pushOrigin: {\n      cmd: 'push',\n      args: ['origin', 'master']\n    },\n    pushHeroku: {\n      cmd: 'push',\n      args: 'heroku master'\n    }\n  }\n});\n```\n\nRunning `grunt git:pushOrigin` will run `git push origin master` and running `grunt git:pushHeroku` will run `git push heroku master`.\n\nSome executables do some default action when run without a subcommand (but still support subcommands for other things). To run a default action for an executable of this type, pass `cmd: false` to tell simple-cli to skip the subcommand.\n\n```js\ngrunt.initConfig({\n  mocha: {\n    test: {\n      cmd: false\n    },\n    init: {}\n  }\n});\n```\n\nHere, `grunt mocha:test` will run just `mocha`, while `grunt mocha:init` will run `mocha init`.\n\n#### args\n\nAdditional, non-flag arguments to pass to the executable. These can be passed as an array (as in `git:pushOrigin` above) or as a single string with arguments separated by a space (as in `git:pushHeroku` above). Note that, if you need to use spaces inside an argument, you will need to use the array syntax, since `simple-cli` will split a string on spaces.\n\n#### rawArgs\n\n`rawArgs` is a catch all for any arguments to the executable that can't be handled (for whatever reason) with the options above (e.g. the path arguments in some git commands: `git checkout master -- config/production.json`). Anything in `rawArgs` will be concatenated to the end of all the normal args. It can be a string or an array of strings.\n\n```js\ngrunt.initConfig({\n  git: {\n    checkout: {\n      args: ['master'],\n      rawArgs: '-- config/production.json'\n    }\n  }\n});\n```\n\n#### debug\n\nSimilar to `--dry-run` in many executables. This will log the command that will be spawned in a child process without actually spawning it. Additionally, if you have an onComplete handler, fake stderr and stdout will be passed to this handler, simulating the real task. If you want to use specific stderr/stdout messages, `debug` can also be an object with `stderr` and `stdout` properties that will be passed to the onComplete handler.\n\n```js\ngrunt.initConfig({\n  blerg: {\n    'waffle-iron': {\n      // Invoked with default fake stderr/stdout\n      onComplete: function(err, stdout, callback) {\n        console.log(err.message, stdout);\n        callback();\n      },\n      debug: true\n    },\n    'wilty-salad': {\n      onComplete: function(err, stdout, callback) {\n        console.log(err.message, stdout); // Logs 'foo bar'\n        callback();\n      },\n      debug: {\n        stderr: 'foo',\n        stdout: 'bar'\n      }\n    }\n  }\n});\n```\n\nAdditionally, you can pass the `--debug` option to grunt itself to enable the above behavior in an ad hoc manner (e.g. `grunt blerg:wilty-salad --debug`).\n\n## Dynamic values\n\nSometimes you just don't know what values you want to supply to an executable until you're ready to use it. That makes it hard to put into a task. `simple-cli` supports dynamical values (via interpolation) which can be supplied in any of three ways:\n\n#### via command line options to grunt (e.g. grunt.option)\n\nSupply the value when you call the task itself.\n\n```js\ngrunt.initConfig({\n  git: {\n    push: {\n      // You can also do this as a string, but note that simple-cli splits\n      // string args on space, so you wouldn't be able to put space INSIDE\n      // the interpolation. You'd have to say args: '{{remote}} master'\n      args: ['origin', '{{ branch }}']\n    }\n  }\n});\n```\n\nIf the above was invoked with `grunt git:push --branch master` the final command would be `git push origin master`.\n\n#### via grunt.config\n\nThis is primarily useful if you want the result of another task to determine the value of an argument. For instance, maybe in another task you say `grunt.config.set('branch', 'new-feature')`, then the task above would run `git push origin new-feature`.\n\n#### via prompt\n\nIf `simple-cli` can't find an interpolation value via `grunt.option` or `grunt.config`, it will prompt you for one on the terminal. Thus you could do something like:\n\n```js\ngrunt.initConfig({\n  git: {\n    commit: {\n      options: {\n        message: '{{ message }}'\n      }\n    }\n  }\n});\n```\n\nand automate commits, while still supplying an accurate commit message.\n\n## Shortcut configurations\n\nFor very simple tasks, you can define the task body as an array or string, rather than as an object, as all the above examples have been.\n\n```js\ngrunt.initConfig({\n  git: {\n    // will invoke \"git push origin master\"\n    push: ['origin', 'master'],\n\n    // will invoke \"git pull upstream master\"\n    pull: 'upstream master'\n  }\n});\n```\n\nNote that this _only_ works if the target name is the command you want to run. If you need, for example, multiple `push` targets, you'll have to use the longer syntax with `cmd` and `args`.\n\n## Options\n\nTo setup the wrapper for an executable, require `simple-cli` and invoke the returned function.\n\n```js\nvar cli = require('simple-cli');\n\nmodule.exports = cli('executable');\n```\n\nIf you need finer controller, you can pass a configuration object as the second parameter. E.g.\n\n```js\nconst cli = require('simple-cli');\n\nmodule.exports = cli('task', {\n  cmd: 'something-else',\n  standalone: true\n});\n```\n\nThe available options are below.\n\n### description\n\nOptional.\n\nA description to pass to `grunt.registerMultiTask`. If none is provided, `simple-cli` will build one for you that looks like `A simple grunt wrapper for \u003cexecutable name\u003e`.\n\n```js\nvar cli = require('simple-cli');\n\nmodule.exports = cli('foo', {\n  description: 'Do some foo! With authority.'\n});\n```\n\n### cmd\n\nOptional.\n\n_Prior to version 4.1.0_: The executable to run if different from the task. This can be useful for wrapping node binaries that you want to include as dependencies. Just set cmd equal to path to the local executable, e.g. `\u003cabsolute_path\u003e/node_modules/.bin/blah`. Alternatively, you could use this as an alias if the executable is long and tedious to type (like \"codeclimate-test-reporter\").\n\n_In 4.1.0 and later_: `simple-cli` adds the `node_modules/.bin` to the front of the `PATH` environment variable prior to calling the executable (similar to how `npm run foo` works), so anything installed locally should work fine out of the box. It uses `require.resolve` to figure out the path for this, which allows you (meaning, someone writing a grunt wrapper using simple-cli) to either include the executable as a dependency _or_ as a peer dependency, as `require.resolve` will figure out where the module is located in the dependency tree.\n\n```js\nvar cli = require('simple-cli');\nvar path = require('path');\n\n// v4.0.0 and earlier\nmodule.exports = cli('foo', {\n  cmd: path.resolve(__dirname, '../node_modules/.bin/foo')\n});\n\n// v4.1.0 and later\nmodule.exports = cli('foo'); // If node_modules/.bin/foo exists, this will run it.\n```\n\nNote that the `cmd` option still exists in v4.1.0 and later, but you only need it if, for some reason, you want to name the task something different than the executable.\n\n### singleDash\n\nOptional.\n\nSet to true for executables that use a `find` style syntax, i.e. a single dash prefix for parameters: `find . -name foo`\n\n```js\nvar cli = require('simple-cli');\n\nmodule.exports = cli('foo', {\n  singleDash: true\n});\n```\n\n### callback\n\nOptional.\n\nA function to call after executing the child process. The child process code will be passed to this function. If omitted, this simply calls grunt's `this.async()` method to trigger the task completion. If you supply this options, you will have to call that method yourself. It will be set on the context within the function as `done`. Call this function with false or an Error to fail the task.\n\n```js\nvar cli = require('simple-cil');\n\nmodule.exports = cli('bar', {\n  callback: function(code) {\n    // Do whatever...\n    this.done(code === 0);\n  }\n});\n```\n\nOther properties available on the `this` object within this method are:\n\n* this.grunt -\u003e the grunt object\n* this.context -\u003e the grunt task context\n* this.cmd -\u003e the command executed via child process\n* this.options -\u003e the task options\n* this.config -\u003e the task configuration (e.g. `cmd`, `args`, `rawArgs`, `env`, etc.)\n* this.custom -\u003e custom options parsers provided by your wrapper\n* this.env -\u003e environment variables to supply to the child process\n* this.target -\u003e the command to run on the executable (e.g. \"commit\" in \"git commit\")\n* this.args -\u003e the full array of command line args supplied to the executable\n* this.debugOn -\u003e whether the task is running debug mode\n\n### custom\n\nOptional.\n\nThe options object is actually just a way to extend the `simple-cli` API. Keys in the object are options allowed as part of the task configuration data and the values are the handlers for those options. So if you need more cowbell in your cli wrapper, you can do that:\n\n```js\nvar cli = require('simple-cil');\n\nmodule.exports = cli('foo', {\n  custom: {\n    moreCowbell: function(val, cb) {\n      // val is the user-assigned config value of \"moreCowbell,\" e.g.\n      // grunt.initConfig({\n      //   foo: {\n      //     bar: {\n      //       options: {\n      //         moreCowbell: 'blah'\n      //       }\n      //     }\n      //   }\n      // });\n\n      // Now \"this.target\" is \"halb\" . . . probably not that useful, but it's just an example\n      this.target = val.split('').reverse().join('');\n      cb();\n    }\n  }\n});\n```\n\nThe handlers for custom opts are called immediately before the child process is spawned (so all the arguments have already been aggregated and put in the right form). The parameters passed to the handler are the value supplied by the user and a callback. The context within the function is the simple-cli context, the same as in the `callback` option above.\n\n### flags\n\nOptional.\n\nBy default, any options (things with `--` and `-` at the front) will be passed _after_ any args. So for example:\n\n```js\ngrunt.initConfig({\n  git: {\n    push: {\n      options: {\n        f: true\n      },\n      args: ['origin', 'master']\n    }\n  }\n});\n```\n\nwill generate the command `git push origin master -f`. Most of the time, placement of flags doesn't affect the command, but sometimes it does, like in the case of `nyc` which has flags of its own that should be passed to the `nyc` executable itself, followed by args, which is the executable `nyc` should attempt to run, followed by _that_ executables flags. If the executable you're wrapping works like this, pass `flags: 'before'` in options. E.g.\n\n```js\nconst cli = require('simple-cli');\n\nmodule.exports = cli('nyc', {\n  standalone: true,\n  flags: 'before'\n});\n```\n\nThat will allow users to do this:\n\n```js\ngrunt.initConfig({\n  nyc: {\n    mocha: {\n      options: {\n        cwd: 'app'\n      },\n      args: ['mocha', '--require', 'should']\n    }\n  }\n});\n```\n\nNow, when `grunt nyc:mocha` is run, the command it will generate will be `nyc --cwd app mocha --require should`. Note how options to the sub-executable here are passed under args (you could alternatively pass them as `rawArgs` since those are added last). If they were placed under `options`, they would be passed as flags to `nyc` instead of `mocha`.\n\n### standalone\n\nOptional.\n\nSome executables don't have subcommands, like `mkdir` for example. If you're wrapping an executable of this type, pass `standalone: true` in the options and simple-cli will not include a subcommand in the shell command it generates. Note that this option is only for executables that _always_ and _only_ standalone. Some executables do some default thing when no subcommand is passed, but still support subcommands. `mocha`, for example, runs tests when run by itself, but you can also say `mocha init` to setup a project. For this kind of executable, see `cmd: false` [above](#cmd).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftandrewnichols%2Fsimple-cli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftandrewnichols%2Fsimple-cli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftandrewnichols%2Fsimple-cli/lists"}