{"id":27885002,"url":"https://github.com/toitlang/pkg-cli","last_synced_at":"2026-01-23T18:34:03.220Z","repository":{"id":65339014,"uuid":"534150618","full_name":"toitlang/pkg-cli","owner":"toitlang","description":"Library to parse command line arguments","archived":false,"fork":false,"pushed_at":"2025-11-30T14:46:51.000Z","size":208,"stargazers_count":1,"open_issues_count":7,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-12-02T21:31:50.517Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Toit","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/toitlang.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-09-08T09:57:24.000Z","updated_at":"2025-11-30T14:46:55.000Z","dependencies_parsed_at":"2023-02-10T15:35:16.059Z","dependency_job_id":"a6b834af-fbc2-427d-ba07-b98f149efd2b","html_url":"https://github.com/toitlang/pkg-cli","commit_stats":null,"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/toitlang/pkg-cli","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toitlang%2Fpkg-cli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toitlang%2Fpkg-cli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toitlang%2Fpkg-cli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toitlang%2Fpkg-cli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/toitlang","download_url":"https://codeload.github.com/toitlang/pkg-cli/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toitlang%2Fpkg-cli/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28697428,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-23T17:25:48.045Z","status":"ssl_error","status_checked_at":"2026-01-23T17:25:47.153Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":"2025-05-05T06:44:42.189Z","updated_at":"2026-01-23T18:34:03.207Z","avatar_url":"https://github.com/toitlang.png","language":"Toit","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CLI\n\nTools to create command-line applications.\n\nThis package makes it easier to create powerful command-line applications in Toit.\n\nIt provides:\n* Composable subcommands: `myapp subcommand`\n* Type options/flags that parse arguments: `myapp --int-flag=49 enum_rest_arg`\n* Automatic help generation\n* Command aliases\n* Functionality to cache data between runs\n* Functionality to store configurations\n* A UI class to support output at different verbosity levels and different output formats\n\n## Command\n\nThe `Command` class is the main class of this package. Even programs without sub-commands\ncontain at least one root-command.\n\nA command declares\n- the parameters it takes (options and rest)\n- help\n- examples\n- a lambda to execute if the command is called\n\nFor example:\n\n``` toit\nimport cli show *\n\nmain args/List:\n  command := Command \"my-app\"\n    --help=\"My app does something.\"\n    --options=[\n      Option \"some-option\"\n        --help=\"This is an option.\"\n        --required,\n      Flag \"some-flag\"\n        --short-name=\"f\"\n        --help=\"This is a flag.\",\n    ]\n    --rest=[\n      Option \"rest-arg\"\n        --help=\"This is a rest argument.\"\n        --multi,\n    ]\n    --examples=[\n      Example \"Do something with the flag:\"\n          --arguments=\"--some-option=foo --no-some-flag rest1 rest1\",\n    ]\n    --run=:: | invocation/Invocation |\n      print invocation[\"some-option\"]\n      print invocation[\"some-flag\"]\n      print invocation[\"rest-arg\"]  // A list.\n      invocation.cli.ui.result \"Computed result\"\n\n  command.run args\n```\n\nIn this example, the command is called \"my-app\". It takes an option `some-option` and a\nflag `some-flag`. It also takes multiple rest arguments `rest-arg`.\n\nThe name of the root command is used to compute the location of the cache and config\npaths. For example, if the command is called `my-app`, the cache will be stored in\n`~/.cache/my-app` and the config will be stored in `~/.config/my-app/config`. See\nthe cache/config section, for more details.\n\n## Subcommands\n\nCommands can have subcommands. For example, the `git` command has subcommands like\n`git commit` and `git push`.\n\nTypically, subcommands are defined if the options/rest arguments of different actions\nare different. For example, `git commit` takes a message, but `git push` does not.\n\nSubcommands are defined by adding a `Command` object as child to another command object.\nFor example:\n\n``` toit\nimport cli show *\n\nmain args/List:\n  command := Command \"my-app\"\n    --help=\"My app does something.\"\n\n  sub := Command \"subcommand\"\n    --help=\"This is a subcommand.\"\n    --run=:: | invocation/Invocation |\n      print \"This is a subcommand.\"\n  command.add sub\n\n  command.run args\n```\n\n## Options\n\nOptions are parameters that are passed to the command. This package comes with\nseveral classes to simplify validation and conversion of common types.\n\n### Typed options\n\nTyped options are options that take a value of a specific type. For example, an\noption that takes an integer value.\n\nHere is an incomplete list of the available typed options. See the documentation\nof the library for a complete list.\n\n- `cli.OptionInt`: An option that takes an integer value. If the value is not an\n  integer, an error is returned.\n- `cli.OptionString`: An option that takes a string value. The `cli.Option` constructor\n  is an alias for this class.\n- `cli.Flag`: An option that takes a boolean value. Flags are treated specially, in\n  that they can be negated with a `no-` prefix. For example, if a flag is called\n  `some-flag`, it can be negated with `--no-some-flag`.\n- `cli.OptionEnum`: An option that takes a value from a set of allowed values.\n\nUsers are encouraged to extend the `cli.Option` class and create their own typed options.\n\n## Invocation\n\nA call to `command.run` parses the given arguments and then executes the\nappropriate lambda. The lambda receives one argument: an `Invocation` object.\n\nThe `Invocation` object contains:\n- `cli`: A `Cli` object that contains common functionality for CLI applications, like\n  the `cache`, `config`, and `ui` objects. It is common to pass this object to\n  functions that are called from the lambda.\n- `parameters`: An object that contains the parsed options and rest arguments. The\n  `Invocation` object has a shortcut operator `[]` that forwards to the `parameters`.\n- `path`: A list of strings that contains the path to the command that was called.\n- `command`: The command that was called.\n\n### Cache\n\nThe cache is a simple key-value store that persists between runs. Cached data may\nbe removed at any point without major implications to the user. It is typically\nstored in `~/.cache/\u003ccommand-name\u003e`. Environment variables, such as `$XDG_CACHE_HOME`, or\n`$APP_CACHE_DIR` (where `APP` is the capitalized name) can be used to change the\nlocation of the cache. See the documentation of the `cache` library for more details.\n\nThe cache can either store bytes, or handle paths to cached folders.\n\n#### Bytes\n\nThe cache can store bytes. For example:\n\n``` toit\nimport cli show Cli FileStore\n\nstore-bytes cli/Cli:\n  cache := cli.cache\n\n  data := cache.get \"my-key\": | store/FileStore |\n    // Block that is called when the key is not found.\n    // The returned data is stored in the cache.\n    print \"Data is not cached. Computing it.\"\n    store.save #[0x01, 0x02, 0x03]\n\n  print data  // Prints #[0x01, 0x02, 0x03].\n```\n\nThe `FileStore` class provides convenience methods to store data. For example, it\nallows to store (either copy or move) existing files:\n\n``` toit\nimport cli show Cli FileStore\nimport host.file\n\nstore-from-file cli/Cli:\n  cache := cli.cache\n\n  data := cache.get \"my-file-key\": | store/FileStore |\n    // Block that is called when the key is not found.\n    print \"Data is not cached. Computing it.\"\n    store.with-tmp-directory: | tmp-dir |\n      data-path := \"$tmp-dir/data.txt\"\n      // Create a file with some data.\n      file.write-contents --path=data-path \"Hello world\"\n      store.move data-path\n\n  print data  // Prints the binary representation of \"Hello world\".\n```\n\n#### Paths\n\nWhen caching multiple files, it's more convenient to just get access to a\ndirectory in the cache structure. The cache class has the\n`get-directory-path` method for this use case:\n\n``` toit\nimport cli show Cli DirectoryStore\nimport host.file\n\nstore-directory cli/Cli:\n  cache := cli.cache\n\n  directory := cache.get-directory-path \"my-dir-key\": | store/DirectoryStore |\n    // Block that is called when the key is not found.\n    // The returned directory is stored in the cache.\n    print \"Directory is not cached. Computing it.\"\n    store.with-tmp-directory: | tmp-dir |\n      // Create a few files with some data.\n      file.write-contents --path=\"$tmp-dir/data1.txt\" \"Hello world\"\n      file.write-contents --path=\"$tmp-dir/data2.txt\" \"Bonjour monde\"\n      store.move tmp-dir\n\n  print directory  // Prints the path to the directory.\n```\n\n### Config\n\nThe config is a simple key-value store that persists between runs. It is typically\nstored in `~/.config/\u003ccommand-name\u003e/config`. Environment variables, such as `$XDG_CONFIG_HOME`, or\n`$APP_CONFIG_DIR` (where `APP` is the capitalized name) can be used to change the\nlocation of the config. See the documentation of the `config` library for more details.\n\nThe `Config` class behaves very similar to a `Map` object. The keys must be\nstrings, and the values can be any json-serializable object.\n\nWhen modifying a configuration it is necessary to `write` the changes back to disk.\n\n``` toit\nimport cli show Cli Config\n\nconfig-example cli/Cli:\n  config := cli.config\n\n  print \"old value: $(config.get \"my-key\")\"\n\n  config[\"my-key\"] = \"my-value\"\n  config.write\n```\n\nKeys are split at \".\" to allow for nested values. For example:\n\n``` toit\ndotted-example cli/Cli:\n  config := cli.config\n\n  print \"old value: $(config.get \"super-key.sub-key\")\"\n\n  config[\"super-key.sub-key\"] = \"my-value\"\n  config.write\n```\n\nIn the config file, `super-key` is implemented as a map that contains a key `sub-key`.\n\nAfter running the two examples, the config file will contain (edited for readability):\n\n``` json\n{\n  \"my-key\": \"my-value\",\n  \"super-key\": {\n    \"sub-key\": \"my-value\"\n  }\n}\n```\n\n### UI\n\nThe UI class provides a way to output information to the user. It supports different\nverbosity levels and different output formats.\n\nUnless the `run` method is called with a `UI` object, the CLI parser will automatically\nadd the following options to the root command:\n```\n  --output-format text|json                          Specify the format used when printing to the console. (default: text)\n  --verbose                                          Enable verbose output. Shorthand for --verbosity-level=verbose.\n  --verbosity-level debug|info|verbose|quiet|silent  Specify the verbosity level. (default: info)\n```\n\nA corresponding UI object is then available in the `Cli` object. Whenever the\nprogram wants to output something, it should use the `ui` object.\n\n``` toit\nimport cli show Cli\n\nsome-chatty-method cli/Cli:\n  ui := cli.ui\n  ui.debug \"This is a debug message.\"\n  ui.verbose \"This is a verbose message.\"\n  ui.inform \"This is an information message.\"\n  ui.warn \"This is a warning message.\"\n  ui.error \"This is an error message.\"\n  ui.interactive \"This is an interactive message.\"\n  ui.result \"This is a result message.\"\n```\n\nDepending on the verbosity-level some of these messages will be ignored. If the\nverbosity level is:\n- `debug`: all messages are printed\n- `verbose`: all messages except `debug` are printed\n- `info`: all messages except `debug` and `verbose` are printed\n- `quiet`: only `interactive`, `error` and `result` messages are printed\n- `silent`: only `result` messages are printed\n\nThe \"result\" message is special, in that it is always printed. There should only\nbe one result message per command (if it makes sense).\n\nThe output-format allows the user to change the format of the output. At the moment\n'text' and 'json' are supported. The default is 'text'. When the output-format is\n'json', then all non-result messages are printed on stderr, and the result message\nis printed as a structured object on stdout.\n\nDevelopers are encouraged to use the `ui.emit --structured` method to emit structured\ndata. This is especially true for the result message.\n\n``` toit\nimport cli show *\n\nmain args:\n  cmd := Command \"my-app\"\n    --help=\"My app does something.\"\n    --run=:: run it\n\nrun invocation/Invocation:\n  ui := invocation.cli.ui\n  ui.emit\n      // Block that is invoked if structured data is needed.\n      --structured=: {\n        \"result\": \"Computed result\"\n      }\n      // Block that is invoked if text data is needed.\n      --text=: \"Computed result as text message.\"\n```\n\nThe `Ui` class has furthermore convenience methods to print tables, maps and lists:\n- `emit-table`: Prints a table.\n- `emit-map`: Prints a map.\n- `emit-list`: Prints a list.\n\nTypically, these methods are used for result messages, but they can be used for\nother messages as well.\n\nThe shorthands `ui.info`, `ui.debug`, also dispatch to these methods if they receive a\n  table (list of lists), map or list.\n\nSee the documentation of the `ui` library for more details.\n\n## Features and bugs\n\nPlease file feature requests and bugs at the [issue tracker][tracker].\n\n[tracker]: https://github.com/toitlang/pkg-cli/issues\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftoitlang%2Fpkg-cli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftoitlang%2Fpkg-cli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftoitlang%2Fpkg-cli/lists"}