jan-cli 0.20.0

YAML-defined CLI trees with progressive help, optional exec aliases, merged extra specs, and SQLite audit logging keyed by git branch
Documentation
# Typed inputs

Declare named flags on a script (or leaf). jan parses `--name value` / `--name=value` from trailing args, applies defaults, type-checks, and interpolates `${{ inputs.name }}` into `env.public` values and `exec.argv` strings.

## YAML

```yaml
backup:
  about: Backup a path
  inputs:
    path:
      description: Source directory
      required: true
      type: dir
    dest:
      default: ~/Backups
      type: path
    mode:
      type: enum
      choices: [full, incremental]
      default: full
  env:
    public:
      SRC: ${{ inputs.path }}
  commands:
    run:
      exec:
        argv:
          - bash
          - -lc
          - rsync -a "$SRC" "${{ inputs.dest }}"
```

```bash
jan scripts misc backup run --path ~/Documents
jan scripts misc backup run --path ~/Documents --dest /mnt/backup --mode incremental
jan scripts misc backup run --help
```

## Fields

| Field | Meaning |
|-------|---------|
| `description` | Shown in `--help` |
| `required` | Fail if unset and no default |
| `default` | Used when the flag is omitted (non-empty defaults are type-checked at spec load) |
| `type` | See table below. Unknown types fail at spec load |
| `choices` | If non-empty, value must be one of these strings (after type checks). Required for `type: enum` |

Input **names** must start with a letter or `_`, then letters, digits, `_`, or `-`.

Deeper nodes override earlier input defs for the same name.

## Types

| `type` | Also accepted | Check |
|--------|---------------|--------|
| `string` (default) | `str`, `text` | none |
| `url` | | parseable URL |
| `https` | `https-url` | URL with `https` scheme |
| `int` | `integer` | signed 64-bit integer |
| `uint` | `unsigned` | non-negative integer |
| `float` | `number`, `double` | finite number |
| `bool` | `boolean` | `true`/`false`, `1`/`0`, `yes`/`no`, `on`/`off` |
| `path` | | non-empty path shape (`~` allowed) |
| `file` | | existing file (relative to `--cwd` at run) |
| `dir` | `directory` | existing directory |
| `port` | | integer 1–65535 |
| `pid` | | integer ≥ 1 |
| `email` | | `local@host` shape |
| `hostname` | `host` | DNS hostname |
| `ipv4` / `ipv6` / `ip` | | parseable address (`[…]` ok for v6) |
| `uuid` | | 8-4-4-4-12 hex |
| `hex` | | hex digits only |
| `duration` | | `30`, `30s`, `5m`, `1h`, `2d` (also `ns`/`us`/`ms`) |
| `date` | | `YYYY-MM-DD` |
| `json` | | `serde_json` parse |
| `enum` | | must set `choices:` |

Bad CLI values fail **before** the script runs. Spec-load of defaults does not require `file` / `dir` to exist (`cwd` is unset at load).

## Interpolation

Only `${{ inputs.<name> }}` is supported (whitespace inside the braces is tolerated). Unknown names fail. Interpolation runs after defaults and type checks, in public env values and each `exec.argv` string.

## Passthrough interaction

Unknown long flags are left for `passthrough` when enabled; otherwise they error as unexpected trailing args. Use `--` to stop input parsing and forward the rest.