{"id":14128427,"url":"https://github.com/tarsana/command","last_synced_at":"2026-01-16T00:37:59.533Z","repository":{"id":10333260,"uuid":"64089112","full_name":"tarsana/command","owner":"tarsana","description":"A library to build command line applications using PHP","archived":false,"fork":false,"pushed_at":"2022-09-30T20:33:31.000Z","size":295,"stargazers_count":169,"open_issues_count":1,"forks_count":11,"subscribers_count":10,"default_branch":"master","last_synced_at":"2024-11-22T02:09:30.737Z","etag":null,"topics":["cli","command-line-app","filesystem","php","subcommands","syntax","twig"],"latest_commit_sha":null,"homepage":"","language":"PHP","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/tarsana.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-07-24T22:50:33.000Z","updated_at":"2024-01-09T10:25:15.000Z","dependencies_parsed_at":"2022-08-07T05:15:41.784Z","dependency_job_id":null,"html_url":"https://github.com/tarsana/command","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tarsana%2Fcommand","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tarsana%2Fcommand/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tarsana%2Fcommand/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tarsana%2Fcommand/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tarsana","download_url":"https://codeload.github.com/tarsana/command/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228571844,"owners_count":17938772,"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-app","filesystem","php","subcommands","syntax","twig"],"created_at":"2024-08-15T16:01:42.488Z","updated_at":"2026-01-16T00:37:59.510Z","avatar_url":"https://github.com/tarsana.png","language":"PHP","readme":"# Tarsana Command\n\n[![Build Status](https://travis-ci.org/tarsana/command.svg?branch=master)](https://travis-ci.org/tarsana/command)\n[![Coverage Status](https://coveralls.io/repos/github/tarsana/command/badge.svg?branch=master)](https://coveralls.io/github/tarsana/command?branch=master)\n[![Code Quality](http://canllp.ca/scrutinizer/quality/g/tarsana/command)](https://scrutinizer-ci.com/g/tarsana/command)\n[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/webneat)\n[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)](https://github.com/tarsana/command/blob/master/LICENSE)\n\nA library to build command line applications using PHP. This is part of the [Tarsana Project](https://github.com/tarsana/specs).\n\n# Table of Contents\n\n- [Installation](#installation)\n\n- [Your First Command](#your-first-command)\n\n- [Initializing The Command](#initializing-the-command)\n\n- [Showing The Help And Version Of A Command](#showing-the-help-and-version-of-a-command)\n\n- [Reading \u0026 Writing to The Console](#reading--writing-to-the-console)\n\n- [Defining Arguments and Options](#defining-arguments-and-options)\n\n- [Reading Arguments and Options Interactively](#reading-arguments-and-options-interactively) **Since version 1.1.0**\n- [Handeling The Filesystem](#handeling-the-filesystem)\n\n- [Loading Configuration](#loading-configuration) **New on version 1.2.0**\n\n- [Rendering Templates](#rendering-templates)\n\n- [Adding SubCommands](#adding-sub-commands)\n\n- [Testing Commands](#testing-commands)\n\n- [What's Next](#whats-next)\n\n- [Development Notes](#development-notes)\n\n# Installation\n\nInstall it using Composer\n\n```\ncomposer require tarsana/command\n```\n\n# Your First Command\n\nLet's write a \"Hello World\" command. Create a file `hello.php` with the following content:\n\n```php\n\u003c?php\nrequire __DIR__.'/vendor/autoload.php';\n\nuse Tarsana\\Command\\Command;\n\nclass HelloWorld extends Command {\n\n    protected function execute()\n    {\n        $this-\u003econsole-\u003eline('Hello World');\n    }\n\n}\n\n(new HelloWorld)-\u003erun();\n\n```\n\nThen run it from the terminal:\n\n```\n$ php hello.php\nHello World\n```\n\nCongratulations, you have just written your first command :D\n\nAs you see, `Tarsana\\Command\\Command` is a class providing the basic features of a command. Every command should extend it and implement the `execute()` method.\n\n# Initializing The Command\n\nIn addition, `Command` gives the `init()` method which is used the initialize the command general attributes. Let's rewrite our `HelloWorld` command:\n\n```php\nclass HelloWorld extends Command {\n\n\tprotected function init ()\n\t{\n\t\t$this-\u003ename('Hello World')\n\t\t     -\u003eversion('1.0.0-alpha')\n\t\t     -\u003edescription('Shows a \"Hello World\" message');\n\t}\n\n    protected function execute()\n    {\n        $this-\u003econsole-\u003eline('Hello World');\n    }\n\n}\n```\n\nHere we are overriding the `init()` method to define the command **name**, **version** and **description**.\n\nNote that the setter of an attribute `foo` is named `foo()` instead of `setFoo()`. I know that this is not a common convention but it makes sense for me. :P\n\n```php\n$this-\u003ename('blabla'); // will set the name to 'blabla' and return $this\n$this-\u003ename(); // calling it without parameter will get the value of name\n```\n\n# Showing the Help and Version of a Command\n\nTo show the version of a command, we use the `--version` flag (we will learn after that this is actually a sub command). We also have the `--help` to show the help message:\n\n![Show version and help message](https://raw.githubusercontent.com/tarsana/command/master/docs/screenshots/hello-version-help.png)\n\n# Reading \u0026 Writing to the Console\n\nThe attribute `console` is used to handle the reading and writing operations to the console.\n\nLet's update our command to read the user name:\n\n```php\nprotected function execute()\n{\n    $this-\u003econsole-\u003eout('Your name: ');\n    $name = $this-\u003econsole-\u003ereadLine();\n    $this-\u003econsole-\u003eline(\"Hello {$name}\");\n}\n```\n\n```\n$ php hello.php\nYour name: Amine\nHello Amine\n```\n\n- The `readLine()` method reads a line from the stdin and returns it as string.\n- The `out()` method writes some text to `stdout` (without a line break).\n- The `line()` method writes some text to `stdout` and adds a line break.\n- The `error()` method writes some text to `stderr` and adds a line break.\n\nThe `Console` class provides some `tags` to control the output:\n\n```php\n$this-\u003econsole-\u003eline('\u003cbackground:15\u003e\u003ccolor:19\u003eBlue text on white background\u003creset\u003e');\n$this-\u003econsole-\u003eline('\u003cbackground:124\u003e\u003ccolor:15\u003eWhite text on red background\u003creset\u003e');\n```\n\n![Show colors in the console](https://raw.githubusercontent.com/tarsana/command/master/docs/screenshots/background-color.png)\n\nThe `\u003cbackground:$number\u003e` and `\u003ccolor:$number\u003e` tags allows to set the background and foreground colors of the text to be written; the `\u003creset\u003e` tag resets the default values. The colors are given as numbers from the 256-color mode.\n\n## List of supported tags\n\n- `\u003ccolor:$n\u003e`: Sets the foreground text to the color `$n` in 256-color mode.\n- `\u003cbackground:$n\u003e`: Sets the foreground text to the color `$n` in 256-color mode.\n- `\u003creset\u003e`: Resets the formatting default values.\n- `\u003cbold\u003e`: Makes the text bold.\n- `\u003cunderline\u003e`: Underlines the text.\n\n`Console` allows you also to define styles using aliases:\n\n```php\n$this-\u003econsole-\u003ealias('\u003cdanger\u003e', '\u003cbackground:124\u003e\u003ccolor:15\u003e\u003cbold\u003e');\n$this-\u003econsole-\u003ealias('\u003c/danger\u003e', '\u003creset\u003e');\n\n$this-\u003econsole-\u003eline('\u003cdanger\u003eSome text\u003c/danger\u003e');\n// is equivalent to\n$this-\u003econsole-\u003eline('\u003cbackground:124\u003e\u003ccolor:15\u003e\u003cbold\u003eSome text\u003creset\u003e');\n```\n\nPredefined aliases are:\n\n```php\n$this-\u003econsole-\u003eline('\u003cinfo\u003e information text \u003c/info\u003e');\n$this-\u003econsole-\u003eline('\u003cwarn\u003e warning text \u003c/warn\u003e');\n$this-\u003econsole-\u003eline('\u003csuccess\u003e success text \u003c/success\u003e');\n$this-\u003econsole-\u003eline('\u003cerror\u003e error text \u003c/error\u003e');\n$this-\u003econsole-\u003eline('\u003ctab\u003e'); // prints four spaces \"    \"\n$this-\u003econsole-\u003eline('\u003cbr\u003e'); // prints line break  PHP_EOL\n```\n\n![Console output aliases](https://raw.githubusercontent.com/tarsana/command/master/docs/screenshots/aliases.png)\n\n**Note:** tags and aliases can be used in all strings printed to the console, including the command and arguments descriptions.\n\n# Defining Arguments and Options\n\nThe command syntax is defined using the [Syntax](https://github.com/tarsana/syntax) library. Let's start with a command that repeats a word a number of times:\n\n```php\nclass RepeatCommand extends Command {\n\n    protected function init ()\n    {\n        $this-\u003ename('Repeat')\n             -\u003eversion('1.0.0')\n             -\u003edescription('Repeats a word a number of times')\n             -\u003esyntax('word: string, count: (number: 3)')\n             -\u003eoptions(['--upper'])\n             -\u003edescribe('word', 'The word to repeat')\n             -\u003edescribe('count', 'The number of times to repeat the word')\n             -\u003edescribe('--upper', 'Converts the result to uppercase');\n    }\n\n    protected function execute()\n    {\n        $result = str_repeat($this-\u003eargs-\u003eword, $this-\u003eargs-\u003ecount);\n        if ($this-\u003eoption('--upper'))\n            $result = strtoupper($result);\n        $this-\u003econsole-\u003eline($result);\n    }\n\n}\n```\n\nWe are using the method `syntax()` to define the syntax of arguments. The string given to this method follows the [rules described here](https://github.com/tarsana/syntax#rules)\n\nThe `describe()` method is used to describe an argument.\n\nWhen you define the syntax of the command; arguments are parsed automatically and available in the `execute()` method via the `args` attribute.\n\nThe `help` subcommand shows full description of the arguments and options:\n\n![Help message example](https://raw.githubusercontent.com/tarsana/command/master/docs/screenshots/repeat-help-message.png)\n\nAnd the result is:\n\n```\n$ php repeat.php foo 5\nfoofoofoofoofoo\n$ php repeat.php bar --upper\nBARBARBAR\n```\n\nIn the second example, the `count` argument takes automatically its default value.\n\n**Warning: Giving wrong arguments generates an error**\n\n![Parse error example](https://raw.githubusercontent.com/tarsana/command/master/docs/screenshots/repeat-args-missing.png)\n\n# Reading Arguments and Options Interactively\n\nSome commands can have long and complicated list of arguments. Defining the syntax of such command is easy thanks to [Syntax](https://github.com/tarsana/syntax) but typing the arguments in the command line becomes challenging.\n\nLet's take the following command for example:\n\n```php\nclass ClassGenerator extends Command {\n    protected function init()\n    {\n        $this-\u003ename('Class Generator')\n        -\u003eversion('1.0.0')\n        -\u003edescription('Generates basic code for a class.')\n        -\u003esyntax('\n            language: string,\n            name: string,\n            parents: ([string]:[]),\n            interfaces: ([string]:[]),\n            attrs: [{\n                name,\n                type,\n                hasGetter: (boolean:true),\n                hasSetter: (boolean:true),\n                isStatic: (boolean:false)\n            }],\n            methods: ([{\n                name: string,\n                type: string,\n                args: [{ name, type, default: (string:null) |.}],\n                isStatic: (boolean:false)\n            }]:[])\n        ')\n        -\u003edescriptions([\n            'language'          =\u003e 'The programming language in which the code will be generated.',\n            'name'              =\u003e 'The name of the class.',\n            'parents'           =\u003e 'List of parent classes names.',\n            'interfaces'        =\u003e 'List of implemented interfaces.',\n            'attrs'             =\u003e 'List of attributes of the class.',\n            'attrs.name'        =\u003e 'The name of the attribute.',\n            'attrs.type'        =\u003e 'The type of the attribute.',\n            'attrs.hasGetter'   =\u003e 'Generate a getter for the attribute.',\n            'attrs.hasSetter'   =\u003e 'Generate a setter for the attribute.',\n            'attrs.isStatic'    =\u003e 'The attribute is static.',\n            'methods'           =\u003e 'List of methods of the class.',\n            'methods.name'      =\u003e 'The method name.',\n            'methods.type'      =\u003e 'The method return type.',\n            'methods.args'      =\u003e 'List of arguments of the method.',\n            'methods.isStatic'  =\u003e 'This method is static.'\n        ]);\n    }\n\n    protected function execute()\n    {\n        $this-\u003econsole-\u003eline(\"Generate code for the class {$this-\u003eargs-\u003ename} in {$this-\u003eargs-\u003elanguage}...\");\n\n    }\n}\n```\n\nif you run the command using the `-i` flag, it will let you enter the arguments interactively:\n\n![Interactive Arguments Reader](https://raw.githubusercontent.com/tarsana/command/master/docs/screenshots/interactive-args.gif)\n\nAfter reading all args, the command will show the command line version of the entered args:\n\n```\n\u003e  PHP User  Serializable name:string:true:true:false\n```\n\nwhich means that running\n\n```\n$ php class.php  PHP User  Serializable name:string:true:true:false\n```\n\nwould produce the same result.\n\n# Handling The Filesystem\n\nThe `fs` attribute is an instance of `Tarsana\\IO\\Filesystem` that you can use to handle files and directories. [Read the documentation](https://github.com/tarsana/io#handeling-files-and-directories) for the full API.\n\nBy default, the `Filesystem` instance points to the directory from which the command is run. You can also initialize it to any directory you want:\n\n```php\nusing Tarsana\\IO\\Filesystem;\n// ...\nprotected function init()\n{\n\t$this-\u003efs(new Filesystem('path/to/directory/you/want'));\n}\n```\n\n# Loading Configuration\n\nIn addition to the command line arguments, the user can provide data to your command via configuration files. This is useful because it lets you define a default configuration file and lets the user change some values with a custom configuration file.\n\nLet's write an example command which have a global configuration file at `/home/user/.config.json`. It lets the user customize value via the file `config.json` in the current directory:\n\n```php\nclass ConfigCommand extends Command {\n    protected function init()\n    {\n        // ...\n        $this-\u003econfigPaths(['/home/user/.config.json', 'config.json']);\n    }\n\n    protected function execute()\n    {\n        // getting a config value\n        // assuming that $data is the merged content of the config files\n        $this-\u003econfig('name'); // returns $data['name']\n        $this-\u003econfig('foo.bar.baz'); // returns $data['foo']['bar']['baz']\n        $this-\u003econfig(); // returns $data\n    }\n}\n```\n\n- The method `configPaths` take a list of paths, loads them and merges them into one configuration (it use `array_replace_recursive` internally).\n\n- The method `config` is used to retreive configuration values.\n\nNote that:\n\n- Only `json` files are supported as configuration files for the moment. Please open an issue or make a Pull Request to add other formats.\n\n- `configPaths` will silently ignore paths which does not exist in the filesystem.\n\n- A subcommand will always have the same configuration data as its parent command, unless `configPaths` is used to override it.\n\n# Rendering Templates\n\nThe `Command` class gives also possibility to render templates. The default template engine is [Twig](https://twig.symfony.com) but you can use your favorite one by implementing the interfaces `TemplateLoaderInterface` and `TemplateInterface`.\n\nLet's make a command which renders a simple template. For this we will create two files:\n\n```\nrender-hello.php\ntemplates/\n    hello.twig\n```\n\n**hello.twig**\n\n```\nHello {{name}}\n```\n\nThis is a simple template that print a hello message.\n\n**render-hello.php**\n\n```php\n\u003c?php\nrequire __DIR__.'vendor/autoload.php';\n\nuse Tarsana\\Command\\Command;\nuse Tarsana\\Command\\Templates\\TwigTemplateLoader;\n\n\nclass RenderHelloCommand extends Command {\n\n    protected function init ()\n    {\n        $this\n            -\u003ename('Renders Simple Template')\n            -\u003edescription('Renders a simple twig template')\n            -\u003esyntax('name: (string:You)')\n            -\u003edescribe('name', 'Your name')\n            -\u003etemplatesPath(__DIR__.'/templates'); // defines the path to the templates\n    }\n\n    protected function execute()\n    {\n        $message = $this-\u003etemplate('hello')\n            -\u003erender([\n                'name' =\u003e $this-\u003eargs-\u003ename\n            ]);\n\n        $this-\u003econsole-\u003eline($message);\n    }\n\n}\n\n(new RenderHelloCommand)-\u003erun();\n```\n\n**Result**\n\n```\n$ php render-hello.php Foo\nHello Foo\n\n$ php render-hello.php\nHello You\n```\n\n# Adding SubCommands\n\nYou can add subcommands while initializing your command.\n\n```php\n// ...\nprotected function init()\n{\n    //...\n    // Assuming that FooCommand and BarCommand are already defined\n    $this-\u003ecommand('foo', new FooCommand)\n         -\u003ecommand('bar', new BarCommand); // this erases the subcommand with key 'bar' if exists\n    // Or set all subcommands at once (this will erase any previous subcommands)\n    $this-\u003ecommands([\n        'foo' =\u003e new FooCommand,\n        'bar' =\u003e new BarCommand\n    ]);\n\n    // Later on you can get subcommands\n    $this-\u003ecommands(); // returns all the subcommands as key-value array\n    $this-\u003ecommand('name'); // gets the subcommand with the given name\n    // will throw an exception if the subcommand is missing\n    $this-\u003ehasCommand('name'); // checks if a subcommand with the given name exists\n}\n```\n\nNow when you run\n\n```\n$ php your-script.php foo other arguments here\n```\n\nThe `FooCommand` will be run with `other arguments here` as arguments.\n\n**Note:** subcommands will always have the attributes `console`, `fs` and `templatesLoader` pointing to the same objects as their parent, as long as you don't change them explicitly in the subcommand's code.\n\n# Testing Commands\n\nThe class `Tarsana\\Tester\\CommandTestCase` extends `PHPUnit\\Framework\\TestCase` and adds useful methods to test Tarsana Commands.\n\n## Testing the Input and Output\n\nLet's write a test for our `HelloWorld` command above which reads the user name than shows the hello message.\n\n```php\nuse Tarsana\\Tester\\CommandTestCase;\n\nclass HelloWorldTest extends CommandTestCase {\n\n    public function test_it_prints_hello()\n    {\n        $this-\u003ewithStdin(\"Amine\\n\")\n             -\u003ecommand(new HelloWorld)\n             -\u003eprints(\"Your name:\")\n             -\u003eprints(\"Hello Amine\u003cbr\u003e\");\n    }\n\n    public function test_it_shows_hello_world_version()\n    {\n        $this-\u003ecommand(new HelloWorld, ['--version'])\n             -\u003eprintsExactly(\"\u003cinfo\u003eHello World\u003c/info\u003e version \u003cinfo\u003e1.0.0-alpha\u003c/info\u003e\u003cbr\u003e\");\n    }\n\n}\n```\n\n```php\nwithStdin(string $content) : CommandTestCase;\n```\n\nSets the content of the standard input of the command.\n\n```php\ncommand(Command $c, array $args = []) : CommandTestCase;\n```\n\nRuns the command `$c` with the standard input and `$args` then stores its outputs for further assertions.\n\n```php\nprintsExactly(string $text) : CommandTestCase;\nprints(string $text) : CommandTestCase;\nprintsError(string $text) : CommandTestCase;\n```\n\n- `printsExactly` asserts that the standard output of the command equals `$text`. Note that [tags](#list-of-supported-tags) are not applied to allow testing them easily.\n\n- `prints` asserts that the standard output of the command contains `$text`.\n\n- `printsError` asserts that error output of the command contains `$text`.\n\n## Testing the Arguments and Options\n\nLet's now test the `RepeatCommand` above.\n\n```php\nclass RepeatCommandTest extends CommandTestCase {\n\n    public function test_it_repeats_word_three_times()\n    {\n        $this-\u003ecommand(new RepeatCommand, ['foo'])\n             -\u003eargsEqual((object) [\n                'word' =\u003e 'foo',\n                'count' =\u003e 3\n             ])\n             -\u003eoptionsEqual([\n                '--upper' =\u003e false\n             ])\n             -\u003eprintsExactly(\"foofoofoo\u003cbr\u003e\");\n    }\n\n    public function test_it_repeats_word_n_times_uppercase()\n    {\n        $this-\u003ecommand(new RepeatCommand, ['bar', '5', '--upper'])\n             -\u003eargsEqual((object) [\n               'word' =\u003e 'bar',\n               'count' =\u003e 5\n             ])\n             -\u003eoptionsEqual([\n               '--upper' =\u003e true\n             ])\n             -\u003eprintsExactly(\"BARBARBARBARBAR\u003cbr\u003e\");\n    }\n}\n```\n\n```php\nargsEqual(object $args) : CommandTestCase;\noptionsEqual(array $options) : CommandTestCase;\n```\n\nAssert that the parsed arguments and options of the command are equal to the given values.\n\n## Testing the Filesystem\n\nLet's take the following command:\n\n```php\nclass ListCommand extends Command {\n\n    protected function init ()\n    {\n        $this-\u003ename('List')\n             -\u003eversion('1.0.0-alpha')\n             -\u003edescription('Lists files and directories in the current directory.');\n    }\n\n    protected function execute()\n    {\n        foreach($this-\u003efs-\u003efind('*')-\u003easArray() as $file) {\n            $this-\u003econsole-\u003eline($file-\u003ename());\n        }\n    }\n\n}\n```\n\nThe test can be written as follows:\n\n```php\nclass ListCommandTest extends CommandTestCase {\n\n    public function test_it_lists_files_and_directories()\n    {\n        $this-\u003ehavingFile('demo.txt', 'Some text here!')\n             -\u003ehavingFile('doc.pdf')\n             -\u003ehavingDir('src')\n             -\u003ecommand(new ListCommand)\n             -\u003eprintsExactly('demo.txt\u003cbr\u003edoc.pdf\u003cbr\u003esrc\u003cbr\u003e');\n    }\n\n    public function test_it_prints_nothing_when_no_files()\n    {\n        $this-\u003ecommand(new ListCommand)\n             -\u003eprintsExactly('');\n    }\n}\n```\n\n```php\nhavingFile(string $path, string $content = '') : CommandTestCase;\nhavingDir(string $path) : CommandTestCase;\n```\n\nThe `CommandTestCase` run the command with a virtual filesystem. The methods `havingFile` and `havingDir` can be used to create files and directories on that filesystem before running the command.\n\n# What's Next\n\nPlease take a look at the examples in the `examples` directory, and try using the library to build some awesome commands. Any feedback is welcome!\n\n# Development Notes\n\n- **Version 2.0.0** Tarsana Command now uses PHPUnit 9 and thus requires PHP 7.3 or PHP 7.4.\n\n- **Version 1.2.1** The `CommandTestCase` is now an abstract class to avoid PHPUnit warnings.\n\n- **Version 1.2.0** Commands can now load configuration from multiple JSON files.\n\n- **Version 1.1.1** Fixed a bug with subcommands not having the default `--help`, `--version` and `-i` subcommands.\n\n- **Version 1.1.0** The flag `-i` added to commands to enable interactive reading of arguments and options.\n\n- **Version 1.0.1** Fixed a bug of subcommands having different instances of `fs` and `templatesLoader` from their parent.\n\n- **Version 1.0.0** The first version is finally out; have fun!\n","funding_links":["https://www.paypal.me/webneat"],"categories":["PHP"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftarsana%2Fcommand","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftarsana%2Fcommand","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftarsana%2Fcommand/lists"}