@jakobm/cmdabra

中文文档
0.8.0发布于 2026/11/01MITTypeScriptES Module

cmdabra TypeScript library

原始使用文档
文档目录9 节
  1. Environment fallbacks
  2. File inputs
  3. Process behavior
  4. Shell completion
  5. Bash
  6. Zsh
  7. Fish
  8. Completion protocol
  9. TypeScript contracts

Cmdabra

Build command-line interfaces from declarative YAML and an implementation handler or object of methods.

# cmdabra.yaml
name: project
description: Manage a project
commands:
  dependencies:
    description: Manage dependencies
    commands:
      update:
        description: Update one package
        aliases: [up]
        examples: [project dependencies update --package-name yaml]
        named-options:
          package-name:
            type: string
            required: true
            short: p
import { runCli } from '@jakobm/cmdabra';

await runCli('./cmdabra.yaml', {
  dependencies: {
    async update(namedOptions) {
      // The application owns behavior and output.
    },
  },
});

Flat and nested commands map to the same shape in the implementation object. Kebab-case command names become camelCase method and namespace names, and kebab-case option names become camelCase properties. Leaf methods receive positional arguments in declaration order, followed by one named-options object when named options are declared. String, boolean, enum, and file options support required values, defaults, repeated values, short flags, aliases, environment fallbacks, and examples. Enum options require a non-empty choices list.

Use description for the short text shown in command listings. A root or command may also declare multiline details; Cmdabra displays those details only in help for that executable, after its description and before its arguments and options:

commands:
  report:
    description: Build a report
    details: |
      Reports include all matching records.

      Use filters to narrow the result.

A CLI without subcommands declares its inputs directly at the root and uses a function as its implementation:

name: search
description: Search files
named-options:
  pattern: { type: string, required: true, short: p }
  ignore-case: { type: boolean, short: i }
await runCli('./cmdabra.yaml', async (namedOptions) => {
  // namedOptions.pattern and namedOptions.ignoreCase
});

A commandless configuration may declare positional-arguments, named-options, and examples; its handler receives the same positional-arguments-first, named-options-last signature as every other leaf. A configuration or command group with subcommands may declare named-options, which are inherited by every descendant leaf. Positional arguments remain leaf-only, and selecting a group without a leaf still displays that incomplete group's help instead of invoking a handler.

Inherited options are supplied after the complete command path, alongside leaf-specific options:

name: project
named-options:
  config: { type: string, env-var: PROJECT_CONFIG }
commands:
  dependencies:
    named-options:
      format: { type: enum, choices: [text, json], default: text }
    commands:
      audit: {}
project dependencies audit --config project.yaml --format json

An inherited option name or short alias must not collide with another input on the same command path.

Every option name contains at least two characters. Any option type may have an optional, one-letter short alias; aliases are unique within a command, -h and --help are reserved for generated help, and --cmdabra-complete, --cmdabra-completion, and --cmdabra-install-completion are reserved for shell completion. Boolean short options may be grouped in any order, so -Nap is equivalent to -N -a -p. A group may contain only boolean flags. String and enum short options consume a separate value, such as -N -f data.json; attached values such as -fdata.json are not supported.

Commands declare ordered inputs under positional-arguments and name-addressed inputs under named-options. Positional arguments are always required and must declare type: string, type: enum, or type: file. Enum arguments require choices.

All positional arguments must precede all options. Option values are separate tokens: --file data.json is supported, while --file=data.json is not. Values may begin with -. Repeating an option is an error unless it declares repeatable: true. The -- end-of-options marker is not supported.

Environment fallbacks

A non-boolean, non-repeatable named option may declare an environment variable fallback:

named-options:
  file:
    type: file
    env-var: LEDLIGHT_FILE

Explicit command-line values take precedence, followed by non-empty automatic stdin for a default-stdin file option, the environment variable, and finally default. Environment values use the option's normal enum validation and file loading. A declared environment variable that exists but is empty is a usage error. Boolean and repeatable options do not support env-var because their string representations would be ambiguous. Environment fallbacks compose with shell tools such as direnv; Cmdabra does not search for or load environment files itself.

File inputs

A file input accepts a filesystem path or - for stdin. Cmdabra opens filesystem paths before invoking the handler, so a missing or unreadable file is a runtime error. Empty files and empty explicit stdin are valid. read-as controls whether content is text (the default), a Buffer, or a Readable stream:

named-options:
  input:
    type: file
    read-as: text # text, buffer, or stream
    default-stdin: true

Handlers receive the content together with its origin:

export type FileInput<T> =
  | { source: 'file'; path: string; content: T }
  | { source: 'stdin'; content: T };

default-stdin: true assigns non-empty redirected stdin when the option was not explicitly supplied and no other file input uses -. At most one file option per executable may enable it. Automatic stdin is currently supported for read-as: text and read-as: buffer; read-as: stream must use explicit - because stream with default-stdin: true is not yet supported. Explicit - always selects stdin, including empty stdin, and one invocation may assign stdin to only one file input. A file-backed stream is owned by Cmdabra and remains available until the handler settles.

Process behavior

runCli reads command-line arguments from process.argv. For a configuration with commands, an empty command line displays root help; selecting a command group without a subcommand displays that group's help. A commandless configuration instead passes an empty command line to its root handler when its declared inputs permit it. Usage errors and generated help are written to stderr and set process.exitCode to 2. Other errors are written with their stack and set process.exitCode to 1. A closed stdout pipe exits successfully instead of reporting EPIPE.

For controlled in-process execution, pass a CliProcess as the optional third argument to runCli. This narrow, process-shaped contract covers only the command arguments, environment, standard streams, exit code, and immediate exit behavior Cmdabra uses; the Node.js process object satisfies it directly. Omitting the argument uses the real process.

Shell completion

Every Cmdabra CLI provides the global --cmdabra-complete option. Shell adapters pass a zero-based current-word index followed by all tokenized command-line words, including the executable as word zero. Cmdabra reads the current YAML configuration and writes matching candidates to stdout, one per line. It completes nested commands and aliases, positional and option enum choices, filesystem paths for file inputs, and inherited and local options; a non-repeatable option is omitted after use.

Every Cmdabra CLI also provides two standalone options, without extra YAML or application handlers:

project --cmdabra-completion bash          # Print a Bash completion script.
project --cmdabra-install-completion bash  # Install it for the current user.
project --cmdabra-completion zsh           # Print a Zsh autoload completion file.
project --cmdabra-install-completion zsh   # Install it for the current user.
project --cmdabra-completion fish          # Print a Fish completion script.
project --cmdabra-install-completion fish  # Install it for the current user.

Replace project with the executable's configured name, which must be available in PATH. Pass either management option at the start of the command line with exactly one shell argument (bash, zsh, or fish). These framework options work for CLIs with or without subcommands; no completion command is reserved.

The three completion options are shown in generated help by default. To hide them, set show-completion-options-in-help: false at the root of your YAML configuration:

name: project
show-completion-options-in-help: false
commands:
  status:
    description: Show project status

This boolean setting applies to root, command-group, and leaf help, including help printed for usage errors. It controls only help visibility: all three options remain reserved and usable, and shell completion still suggests them. Omit the setting or set it to true to display them. The setting is only allowed at the root.

Installation creates the parent directory and reports the installed path and shell setup instructions. Reinstalling an unchanged script leaves it untouched; a script marked as generated by Cmdabra for that executable and shell can be updated. Existing foreign files, directories, and symbolic links are refused. Installation never edits shell startup files or runs automatically when installing the npm package.

Bash

Bash scripts are installed as <directory>/<name>, where the directory is:

  • $BASH_COMPLETION_USER_DIR/completions when BASH_COMPLETION_USER_DIR is non-empty.
  • $XDG_DATA_HOME/bash-completion/completions when XDG_DATA_HOME is non-empty.
  • $HOME/.local/share/bash-completion/completions otherwise.

With modern bash-completion installed and enabled in the interactive shell, its loader discovers this file on demand. The installer does not install or activate bash-completion, and cannot verify the state of your parent shell. Open a new shell to pick up the integration. Alternatively, source the installed file to register completion immediately, including in Bash setups without bash-completion. The generated adapter uses Bash 3.2-compatible syntax.

Zsh

Zsh scripts are installed as _<name> in $XDG_DATA_HOME/zsh/site-functions, or $HOME/.local/share/zsh/site-functions when XDG_DATA_HOME is empty or unset. Zsh does not search this directory by default. Add it to fpath before the existing compinit call in your .zshrc (using the actual path printed by the installer):

fpath=("${XDG_DATA_HOME:-$HOME/.local/share}/zsh/site-functions" $fpath)
autoload -Uz compinit
compinit

If a shell framework already calls compinit, put the fpath addition before its initialization. Open a new shell afterwards. If an existing completion cache misses the new command, rebuild it with compinit -D.

The generated Zsh script is an autoload completion file with a #compdef header; put it in an fpath directory as _<name> when installing it manually. It is not a script to source directly from .zshrc.

Fish

Fish scripts are installed as <name>.fish in $XDG_CONFIG_HOME/fish/completions, or $HOME/.config/fish/completions when XDG_CONFIG_HOME is empty or unset. Fish discovers this directory automatically through its default fish_complete_path; no startup-file changes or extra completion package are required. If you customize fish_complete_path, keep this directory in it.

Open a new shell after installation, or source the installed file as shown by the installer to register it immediately. For manual installation, save the generated script as <name>.fish in the same directory. The adapter uses Fish's tokenized command line and delegates candidate generation to the executable, including filesystem candidates. It disables Fish's fallback filename suggestions so unrelated files do not appear for command or enum completions.

Completion protocol

The completion engine remains shell-independent. All three adapters translate their shell's words and current-word index into --cmdabra-complete requests. Zsh's one-based CURRENT is converted to a zero-based index; Bash uses COMP_CWORD. Fish uses commandline to tokenize the words before the cursor and computes the index from the words before the current token. Arguments and candidates containing spaces are preserved. Filesystem candidates containing newlines cannot be represented by the line-based protocol and are omitted.

The executable reads its current YAML configuration on every request, so configuration changes take effect on the next completion without reinstalling the shell script. No command tree is baked into the adapters. All configured installation directories must be absolute paths; an empty environment variable is treated as unset.

TypeScript contracts

Generate an implementation interface from the YAML source of truth:

cmdabra generate-types cmdabra.yaml --output src/cmdabra.generated.ts

Implement it with contextual typing and satisfies CmdabraImplementation. When the configuration contains file inputs, the generated module also exports FileInput for helpers that need to name the runtime value. CI can detect drift before running tsc:

cmdabra generate-types cmdabra.yaml --output src/cmdabra.generated.ts --check

版本与发布记录

@jakobm/cmdabra 共发布 11 个版本,首次发布于 2026/10/23;过去 12 个月发布了 11 个版本。

版本发布日期距今
0.8.0latest2026/11/012 天前
0.7.02026/10/304 天前
0.6.02026/10/304 天前
0.5.02026/10/285 天前
0.4.02026/10/286 天前
0.3.02026/10/286 天前

关于 @jakobm/cmdabra 的常见问题

@jakobm/cmdabra 是什么?

cmdabra TypeScript库

如何安装 @jakobm/cmdabra?

在项目目录运行 npm install @jakobm/cmdabra,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 cmdabra,可以用 npx cmdabra 直接运行。

@jakobm/cmdabra 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@jakobm/cmdabra 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@jakobm/cmdabra 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@jakobm/cmdabra 可以商用吗?

@jakobm/cmdabra 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@jakobm/cmdabra 还在维护吗?

最新版本 0.8.0 发布于 2026/11/01(2 天前);至今共发布 11 个版本,其中过去 12 个月发布了 11 个;首次发布于 2026/10/23。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。