$npx -y skills add skilld-dev/skilld --skill unjs-cittyALWAYS use when writing code importing \"citty\". Consult for debugging, best practices, or modifying citty.
| 1 | # unjs/citty `citty` |
| 2 | |
| 3 | **Version:** 0.2.1 (yesterday) |
| 4 | **Tags:** latest: 0.2.1 (yesterday) |
| 5 | |
| 6 | **References:** [package.json](./.skilld/pkg/package.json) • [README](./.skilld/pkg/README.md) • [GitHub Issues](./.skilld/issues/_INDEX.md) • [Releases](./.skilld/releases/_INDEX.md) |
| 7 | |
| 8 | ## Search |
| 9 | |
| 10 | Use `npx -y skilld search` instead of grepping `.skilld/` directories — hybrid semantic + keyword search across all indexed docs, issues, and releases. |
| 11 | |
| 12 | ```bash |
| 13 | npx -y skilld search "query" -p citty |
| 14 | npx -y skilld search "issues:error handling" -p citty |
| 15 | npx -y skilld search "releases:deprecated" -p citty |
| 16 | ``` |
| 17 | |
| 18 | Filters: `docs:`, `issues:`, `releases:` prefix narrows by source type. |
| 19 | |
| 20 | ## API Changes |
| 21 | |
| 22 | ⚠️ **ESM-only** — v0.2.0 ships ESM only, `require('citty')` no longer works [source](./releases/v0.2.0.md) |
| 23 | |
| 24 | ⚠️ **`node:util.parseArgs` internally** — v0.2.0 replaced custom parser with Node.js native `util.parseArgs`, edge cases around arg parsing may differ from v0.1.x [source](./releases/v0.2.0.md) |
| 25 | |
| 26 | ⚠️ **Optional args type `T | undefined`** — v0.2.0 improved type inference: args without `required: true` or `default` now correctly type as `T | undefined` instead of `T` [source](./releases/v0.2.0.md) |
| 27 | |
| 28 | ⚠️ **`--no-` negation conditionally printed** — v0.2.0 only shows `--no-<flag>` in usage when `negativeDescription` is set; previously always shown [source](./releases/v0.2.0.md) |
| 29 | |
| 30 | ✨ `type: "enum"` — new arg type in v0.2.0, requires `options: string[]` array. Typed as union of options values [source](./releases/v0.2.0.md) |
| 31 | |
| 32 | ```ts |
| 33 | args: { |
| 34 | color: { |
| 35 | type: "enum", |
| 36 | options: ["red", "blue", "green"] as const, |
| 37 | description: "Pick a color", |
| 38 | }, |
| 39 | } |
| 40 | // args.color typed as "red" | "blue" | "green" | undefined |
| 41 | |
| 42 | ``` |
| 43 | ✨ `meta.hidden` — v0.2.0, hides a subcommand from usage/help output [source](./releases/v0.2.0.md) |
| 44 | |
| 45 | ✨ `negativeDescription` — v0.2.0, on boolean args, sets description for the `--no-<flag>` variant in usage [source](./releases/v0.2.0.md) |
| 46 | |
| 47 | ✨ `cleanup` hook — v0.1.4, runs after `run()` completes (mirror of `setup`) [source](./releases/v0.1.4.md) |
| 48 | |
| 49 | ✨ `createMain(cmd)` — v0.1.4, returns a reusable `(opts?) => Promise<void>` wrapper around `runMain` [source](./releases/v0.1.4.md) |
| 50 | |
| 51 | ✨ `--version` flag — v0.1.4, auto-handled when `meta.version` is set [source](./releases/v0.1.4.md) |
| 52 | |
| 53 | ✨ `runMain({ showUsage })` — v0.1.5, accepts custom `showUsage` function to override default help rendering [source](./releases/v0.1.5.md) |
| 54 | |
| 55 | ⚠️ `--no-` propagation fix — v0.2.1, `--no-<flag>` now correctly negates aliases too (was broken in v0.2.0) [source](./releases/v0.2.1.md) |
| 56 | |
| 57 | ## Best Practices |
| 58 | |
| 59 | ✅ Use `setup` and `cleanup` hooks for lifecycle management — undocumented in README but fully supported; `cleanup` runs in `finally` block so it executes even on errors [source](./.skilld/pkg/dist/index.mjs) |
| 60 | |
| 61 | ```ts |
| 62 | defineCommand({ |
| 63 | args: { db: { type: "string", default: "mydb" } }, |
| 64 | async setup({ args }) { await connectDb(args.db) }, |
| 65 | async cleanup() { await disconnectDb() }, |
| 66 | async run({ args }) { /* db is connected */ }, |
| 67 | }) |
| 68 | |
| 69 | ``` |
| 70 | ✅ Use `enum` type with `options` for constrained values — validates input and shows allowed values in usage/error messages (v0.2.0+) [source](./.skilld/releases/v0.2.0.md) |
| 71 | |
| 72 | ```ts |
| 73 | args: { |
| 74 | format: { |
| 75 | type: "enum", |
| 76 | options: ["json", "yaml", "toml"], |
| 77 | default: "json", |
| 78 | description: "Output format", |
| 79 | }, |
| 80 | } |
| 81 | ``` |
| 82 | |
| 83 | ✅ Use `meta.hidden: true` to hide subcommands from usage output — keeps internal/debug commands accessible but invisible (v0.2.0+) [source](./.skilld/releases/v0.2.0.md) |
| 84 | |
| 85 | ```ts |
| 86 | subCommands: { |
| 87 | debug: () => defineCommand({ meta: { name: "debug", hidden: true }, run() {} }), |
| 88 | } |
| 89 | ``` |
| 90 | |
| 91 | ✅ Make `subCommands` values lazy via arrow functions — citty resolves them with `resolveValue()`, enabling code-splitting and faster startup [source](./.skilld/pkg/dist/index.mjs) |
| 92 | |
| 93 | ```ts |
| 94 | subCommands: { |
| 95 | deploy: () => import("./commands/deploy").then(m => m.default), |
| 96 | build: () => import("./commands/build").then(m => m.default), |
| 97 | } |
| 98 | ``` |
| 99 | |
| 100 | ✅ Use `negativeDescription` on boolean args that default to `true` — citty auto-generates `--no-*` flags with separate help text (v0.2.0+) [source](./.skilld/pkg/dist/index.mjs) |
| 101 | |
| 102 | ```ts |
| 103 | args: { |
| 104 | color: { |
| 105 | type: "boolean", |
| 106 | default: true, |
| 107 | description: "Colorize output", |
| 108 | negativeDescription: "Disable colored output", |
| 109 | }, |
| 110 | } |
| 111 | ``` |
| 112 | |
| 113 | ✅ Pass custom `showUsage` to `runMain` for branded help screens — citty calls your function instead of the built-in one for `--help` and error display [source](./.skilld/pkg/dist/index.d.mts) |
| 114 | |
| 115 | ```ts |
| 116 | runMain(cmd, { |
| 117 | showUsage: async (cmd, parent) => { |
| 118 | console.log(await renderUsage(cmd, parent)) |
| 119 | console.log("\nDocs: https://example.com/docs") |
| 120 | }, |
| 121 | }) |
| 122 | ``` |
| 123 | |
| 124 | ✅ Arg names auto-alias between camelCase and kebab-case — defining `outputDir` auto-creates `--output-dir` and vice versa; don't add redunda |