@wooksjs/event-cli 0.6.6 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,541 +1,222 @@
1
- # Commands & Help — @wooksjs/event-cli
1
+ # Commands & help — @wooksjs/event-cli
2
2
 
3
- > Covers command registration, command path syntax (arguments, aliases, options, examples), flag/option composables, help generation, and route parameters in CLI context.
3
+ > Command registration with options/args/aliases, help generation, and CLI composables.
4
4
 
5
- ## Command Registration
5
+ ## Concepts
6
6
 
7
- ### `app.cli(path, handler)`
7
+ Commands can be registered with rich metadata (description, options, args, aliases, examples) that drives auto-generated help output. The help system is powered by `@prostojs/cli-help`.
8
8
 
9
- Register a command with a simple handler:
9
+ CLI composables (`useCliOptions`, `useCliOption`, `useCliHelp`, `useAutoHelp`) provide access to parsed flags and help rendering from within handlers.
10
10
 
11
- ```ts
12
- import { createCliApp } from '@wooksjs/event-cli'
13
-
14
- const app = createCliApp()
11
+ ## API Reference
15
12
 
16
- app.cli('deploy', () => {
17
- return 'Deploying...'
18
- })
19
-
20
- app.run()
21
- // $ mycli deploy → "Deploying..."
22
- ```
23
-
24
- ### `app.cli(path, options)`
25
-
26
- Register a command with full metadata for help generation:
13
+ ### Command registration with options
27
14
 
28
15
  ```ts
29
16
  app.cli('deploy/:env', {
30
- description: 'Deploy to a target environment',
17
+ description: 'Deploy the application to the specified environment',
31
18
  args: {
32
19
  env: 'Target environment (staging, production)',
33
20
  },
34
21
  options: [
35
- { keys: ['force', 'f'], description: 'Skip confirmation prompt' },
36
- { keys: ['tag', 't'], description: 'Docker image tag', value: 'latest' },
22
+ { keys: ['verbose', 'v'], description: 'Enable verbose output' },
23
+ { keys: ['dry-run', 'd'], description: 'Run without making changes' },
24
+ { keys: ['config', 'c'], description: 'Path to config file', value: 'path' },
37
25
  ],
38
- aliases: ['d'],
26
+ aliases: ['dep'],
39
27
  examples: [
40
28
  {
41
- description: 'Deploy to production with a specific tag',
42
- cmd: 'production -t=v2.1.0',
29
+ description: 'Deploy to production with verbose output',
30
+ cmd: 'production --verbose',
43
31
  },
44
32
  ],
45
33
  handler: () => {
46
- const { get } = useRouteParams<{ env: string }>()
47
- const flags = useCliOptions()
48
- return `Deploying to ${get('env')} (force=${flags.force || false})`
34
+ const { params } = useRouteParams<{ env: string }>()
35
+ const verbose = useCliOption('verbose')
36
+ return `Deploying to ${params.env}${verbose ? ' (verbose)' : ''}`
49
37
  },
50
38
  })
51
39
  ```
52
40
 
53
- ### Options object shape
54
-
55
- ```ts
56
- interface TWooksCliEntry<T> {
57
- handler: TWooksHandler<T> // the command handler function
58
- description?: string // command description for help text
59
- args?: Record<string, string> // { argName: 'description' }
60
- options?: Array<{
61
- keys: string[] // ['verbose', 'v'] → --verbose or -v
62
- description?: string // option description for help
63
- value?: string // default/example value shown in help
64
- }>
65
- aliases?: string[] // alternative command names
66
- examples?: Array<{
67
- description: string // example description
68
- cmd: string // example command (without CLI name)
69
- }>
70
- onRegister?: (path: string, aliasType: number, route?: any) => void
71
- }
72
- ```
73
-
74
- ## Command Path Syntax
75
-
76
- Command paths use the same `@prostojs/router` syntax as HTTP routes. Space and `/` separators are equivalent.
77
-
78
- ### Static commands
79
-
80
- ```ts
81
- app.cli('deploy', handler) // $ mycli deploy
82
- app.cli('db migrate', handler) // $ mycli db migrate
83
- app.cli('db/migrate', handler) // same as above
84
- app.cli('config set', handler) // $ mycli config set
85
- ```
86
-
87
- ### Named arguments (`:argName`)
88
-
89
- Captures a single positional argument:
90
-
91
- ```ts
92
- import { useRouteParams } from '@wooksjs/event-core'
41
+ **`TWooksCliEntry<T>` fields:**
93
42
 
94
- app.cli('greet/:name', {
95
- args: { name: 'Person to greet' },
96
- handler: () => {
97
- const { get } = useRouteParams<{ name: string }>()
98
- return `Hello, ${get('name')}!`
99
- },
100
- })
101
- // $ mycli greet Alice → "Hello, Alice!"
102
- ```
43
+ | Field | Type | Description |
44
+ | ------------- | ----------------------------------- | -------------------------------------------------------- |
45
+ | `handler` | `TWooksHandler<T>` | The command handler function |
46
+ | `description` | `string` | Command description for help |
47
+ | `args` | `Record<string, string>` | Argument descriptions (auto-populated from route params) |
48
+ | `options` | `TCliOption[]` | Flag/option definitions |
49
+ | `aliases` | `string[]` | Alternative command names |
50
+ | `examples` | `TCliExample[]` | Usage examples |
51
+ | `onRegister` | `(path, aliasType, route?) => void` | Callback when command/alias is registered |
103
52
 
104
- ### Multiple arguments
53
+ **Option definition:**
105
54
 
106
55
  ```ts
107
- app.cli('copy/:source/:dest', {
108
- args: {
109
- source: 'Source file path',
110
- dest: 'Destination file path',
111
- },
112
- handler: () => {
113
- const { params } = useRouteParams<{ source: string; dest: string }>()
114
- return `Copying ${params.source} to ${params.dest}`
115
- },
116
- })
117
- // $ mycli copy file.txt backup/file.txt
56
+ { keys: ['verbose', 'v'], description: 'Enable verbose output' }
57
+ { keys: ['config', 'c'], description: 'Config file path', value: 'file' }
118
58
  ```
119
59
 
120
- ### Optional arguments (`:arg?`)
60
+ - `keys`: Array of flag names (first is primary, rest are aliases)
61
+ - `description`: Help text
62
+ - `value`: If present, the option expects a value (shown in help as `--config <file>`)
121
63
 
122
- Append `?` to make an argument optional. Optional args must be at the end:
64
+ ### `useCliOptions(): Record<string, boolean | string>`
123
65
 
124
- ```ts
125
- app.cli('logs/:service/:lines?', {
126
- args: {
127
- service: 'Service name',
128
- lines: 'Number of lines (default: 50)',
129
- },
130
- handler: () => {
131
- const { get } = useRouteParams<{ service: string; lines?: string }>()
132
- const lines = get('lines') || '50'
133
- return `Showing last ${lines} lines of ${get('service')}`
134
- },
135
- })
136
- // $ mycli logs api → "Showing last 50 lines of api"
137
- // $ mycli logs api 100 → "Showing last 100 lines of api"
138
- ```
139
-
140
- ### Wildcards (`*`)
141
-
142
- Capture arbitrary remaining arguments:
143
-
144
- ```ts
145
- app.cli('exec/*', {
146
- handler: () => {
147
- const { get } = useRouteParams<{ '*': string }>()
148
- return `Running: ${get('*')}`
149
- },
150
- })
151
- // $ mycli exec npm install → "Running: npm/install"
152
- ```
153
-
154
- ### Regex-constrained arguments
155
-
156
- Restrict what an argument matches:
157
-
158
- ```ts
159
- app.cli('migrate/:version(\\d+)', {
160
- args: { version: 'Migration version number' },
161
- handler: () => {
162
- const { get } = useRouteParams<{ version: string }>()
163
- return `Migrating to version ${get('version')}`
164
- },
165
- })
166
- // $ mycli migrate 42 → matches
167
- // $ mycli migrate abc → does NOT match (unknown command)
168
- ```
169
-
170
- ### Hyphen-separated arguments
171
-
172
- ```ts
173
- app.cli('schedule/:from-:to', {
174
- handler: () => {
175
- const { get } = useRouteParams<{ from: string; to: string }>()
176
- return `Scheduled from ${get('from')} to ${get('to')}`
177
- },
178
- })
179
- // $ mycli schedule 09:00-17:00
180
- ```
181
-
182
- ## Command Aliases
183
-
184
- Aliases register additional paths that invoke the same handler:
185
-
186
- ```ts
187
- app.cli('deploy/:env', {
188
- aliases: ['d'],
189
- args: { env: 'Target environment' },
190
- handler: () => {
191
- const { get } = useRouteParams<{ env: string }>()
192
- return `Deploying to ${get('env')}`
193
- },
194
- })
195
- // $ mycli deploy staging → works
196
- // $ mycli d staging → also works (alias)
197
- ```
198
-
199
- Aliases automatically inherit the command's arguments. The alias `'d'` becomes `'d/:env'`.
200
-
201
- ## Accessing Flags and Options
202
-
203
- ### `useCliOptions()`
204
-
205
- Returns all parsed flags as an object (uses `minimist` under the hood):
66
+ Returns all parsed CLI flags (via `minimist`). Includes positional args in `_`.
206
67
 
207
68
  ```ts
208
69
  import { useCliOptions } from '@wooksjs/event-cli'
209
70
 
210
71
  app.cli('build', () => {
211
- const flags = useCliOptions()
212
- // $ mycli build --env production --verbose -p 8080
213
- // flags = { _: ['build'], env: 'production', verbose: true, p: 8080 }
214
- return `Building for ${flags.env}`
72
+ const opts = useCliOptions()
73
+ // For: $ mycli build --verbose --target=production
74
+ // opts = { _: ['build'], verbose: true, target: 'production' }
215
75
  })
216
76
  ```
217
77
 
218
- The `_` property contains all positional arguments (including command segments).
78
+ ### `useCliOption(name: string): boolean | string | undefined`
219
79
 
220
- ### `useCliOption(name)`
221
-
222
- Get a single option value. Resolves aliases — if you defined `keys: ['verbose', 'v']`, calling `useCliOption('verbose')` also checks `-v`:
80
+ Returns a single option value, resolving aliases from the command's option definitions.
223
81
 
224
82
  ```ts
225
83
  import { useCliOption } from '@wooksjs/event-cli'
226
84
 
227
- app.cli('build', {
228
- options: [
229
- { keys: ['env', 'e'], description: 'Target environment', value: 'dev' },
230
- { keys: ['verbose', 'v'], description: 'Verbose output' },
231
- ],
85
+ app.cli('deploy', {
86
+ options: [{ keys: ['verbose', 'v'], description: 'Verbose output' }],
232
87
  handler: () => {
233
- const env = useCliOption('env') // checks --env and -e
234
- const verbose = useCliOption('verbose') // checks --verbose and -v
235
- return `Building for ${env || 'dev'} (verbose: ${!!verbose})`
88
+ const verbose = useCliOption('verbose')
89
+ // Returns true for both --verbose and -v
236
90
  },
237
91
  })
238
- // $ mycli build -e production -v
239
- ```
240
-
241
- ### Minimist parsing options
242
-
243
- Control how flags are parsed by passing options to `app.run()`:
244
-
245
- ```ts
246
- // Ensure -A is parsed as boolean (true/false), not string
247
- await app.run(['build', '-cA'], { boolean: ['A'] })
248
-
249
- // Negate boolean flags with --no- prefix
250
- await app.run(['build', '--no-cache'], { boolean: ['cache'] })
251
- // → { cache: false }
252
-
253
- // Default values
254
- await app.run(['build'], { default: { env: 'development' } })
255
- // → { env: 'development' }
256
- ```
257
-
258
- ## Help System
259
-
260
- ### Registering help metadata
261
-
262
- Help metadata is defined alongside the command:
263
-
264
- ```ts
265
- app.cli('db migrate/:direction?', {
266
- description: 'Run database migrations',
267
- args: {
268
- direction: 'Migration direction: up or down (default: up)',
269
- },
270
- options: [
271
- { keys: ['seed', 's'], description: 'Run seeds after migration' },
272
- { keys: ['dry-run'], description: 'Preview changes without applying' },
273
- ],
274
- examples: [
275
- { description: 'Run all pending migrations', cmd: 'up' },
276
- { description: 'Rollback last migration', cmd: 'down' },
277
- { description: 'Preview migration with seeding', cmd: 'up -s --dry-run' },
278
- ],
279
- handler: () => { /* ... */ },
280
- })
281
92
  ```
282
93
 
283
94
  ### `useCliHelp()`
284
95
 
285
- Access the help system from within a handler:
96
+ Provides access to the help renderer for the current command.
286
97
 
287
98
  ```ts
288
99
  import { useCliHelp } from '@wooksjs/event-cli'
289
100
 
290
- app.cli('help', () => {
291
- const { print, render, getEntry, getCliHelp } = useCliHelp()
292
-
293
- print(true) // print help to stdout (with colors)
294
- print(false) // print without colors
295
-
296
- const lines = render(80, true) // render as string array (width, colors)
297
-
298
- const entry = getEntry() // get the matched help entry
299
- // entry.description, entry.options, entry.args, entry.examples
300
-
301
- const cliHelp = getCliHelp() // access the CliHelpRenderer directly
302
- })
101
+ const { print, render, getEntry, getCliHelp } = useCliHelp()
303
102
  ```
304
103
 
104
+ | Method | Description |
105
+ | ----------------------------- | ------------------------------------------ |
106
+ | `print(withColors?)` | Print help to stdout |
107
+ | `render(width?, withColors?)` | Render help as string |
108
+ | `getEntry()` | Get the help entry for the current command |
109
+ | `getCliHelp()` | Get the full `CliHelpRenderer` instance |
110
+
305
111
  ### `useAutoHelp(keys?, colors?)`
306
112
 
307
- Automatically prints help when `--help` is passed. Returns `true` if help was printed:
113
+ Checks if `--help` (or custom flag) was passed; if so, prints help and returns `true`.
308
114
 
309
115
  ```ts
310
116
  import { useAutoHelp } from '@wooksjs/event-cli'
311
117
 
312
- app.cli('deploy/:env', {
313
- description: 'Deploy to environment',
118
+ app.cli('build', {
119
+ description: 'Build the project',
314
120
  handler: () => {
315
- if (useAutoHelp()) return // prints help and returns if --help was passed
121
+ if (useAutoHelp()) return // prints help and returns true for --help
122
+ return 'Building...'
123
+ },
124
+ })
316
125
 
317
- // Normal handler logic
318
- const { get } = useRouteParams<{ env: string }>()
319
- return `Deploying to ${get('env')}`
126
+ // Custom trigger flags
127
+ app.cli('test', {
128
+ handler: () => {
129
+ if (useAutoHelp(['help', 'h'], false)) return // -h, --help, no colors
320
130
  },
321
131
  })
322
- // $ mycli deploy --help → prints formatted help
323
- // $ mycli deploy staging → "Deploying to staging"
324
132
  ```
325
133
 
326
- Customize the trigger keys and color setting:
134
+ **Parameters:**
327
135
 
328
- ```ts
329
- // Trigger on --help or -h, without colors
330
- if (useAutoHelp(['help', 'h'], false)) {
331
- process.exit(0)
332
- }
333
- ```
136
+ - `keys` (default: `['help']`) — option names that trigger help
137
+ - `colors` (default: `true`) — whether to use ANSI colors
334
138
 
335
139
  ### `useCommandLookupHelp(lookupDepth?)`
336
140
 
337
- Searches for similar valid commands when a wrong command is entered. Throws an error with suggestions if found. Best used in `onUnknownCommand`:
141
+ Provides "did you mean?" suggestions for unknown commands. Best used in `onUnknownCommand`:
338
142
 
339
143
  ```ts
340
- import { createCliApp, useCommandLookupHelp } from '@wooksjs/event-cli'
144
+ import { createCliApp } from '@wooksjs/event-cli'
145
+ import { useCommandLookupHelp } from '@wooksjs/event-cli'
341
146
 
342
147
  const app = createCliApp({
343
- onUnknownCommand: (path, raiseError) => {
344
- useCommandLookupHelp() // throws with suggestions
345
- raiseError() // fallback if no suggestions found
148
+ onUnknownCommand: (params, raiseError) => {
149
+ useCommandLookupHelp() // throws with suggestions if found
150
+ raiseError() // fallback: standard "unknown command" error
346
151
  },
347
152
  })
348
153
  ```
349
154
 
350
- The lookup works backwards through the command path:
351
-
352
- ```
353
- For command "run test:drive dir":
354
- lookup 1: "run test:drive dir" (depth 0)
355
- lookup 2: "run test:drive" (depth 1)
356
- lookup 3: "run test" (depth 2)
357
- lookup 4: "run" (depth 3)
358
- ```
359
-
360
- Default `lookupDepth` is 3. If a partial match with children is found, it suggests child commands. If arguments are expected, it says what arguments are missing.
361
-
362
- ### Help Renderer Configuration
363
-
364
- Customize the help renderer when creating the app:
365
-
366
- ```ts
367
- import { CliHelpRenderer } from '@prostojs/cli-help'
155
+ For a command like `run test:drive dir`, it searches backwards:
368
156
 
369
- // Option 1: Pass options
370
- const app = createCliApp({
371
- cliHelp: {
372
- name: 'mycli', // CLI name shown in help and examples
373
- // marks, width, etc.
374
- },
375
- })
157
+ 1. `run test:drive dir` (depth 0)
158
+ 2. `run test:drive` (depth 1)
159
+ 3. `run test` (depth 2)
160
+ 4. `run` (depth 3)
376
161
 
377
- // Option 2: Pass a pre-configured renderer
378
- const renderer = new CliHelpRenderer({ name: 'mycli' })
379
- const app = createCliApp({ cliHelp: renderer })
380
- ```
162
+ If a match has children, it suggests them. If a match expects args, it says which args are expected.
381
163
 
382
- ## Route Parameters in CLI
164
+ ## Common Patterns
383
165
 
384
- CLI commands use the same `useRouteParams()` from `@wooksjs/event-core` as HTTP routes:
166
+ ### Pattern: Auto-help with exit
385
167
 
386
168
  ```ts
387
- import { useRouteParams } from '@wooksjs/event-core'
388
-
389
- app.cli('user/:action/:id?', {
169
+ app.cli('serve', {
170
+ description: 'Start the development server',
171
+ options: [{ keys: ['port', 'p'], description: 'Port number', value: 'number' }],
390
172
  handler: () => {
391
- const { params, get } = useRouteParams<{
392
- action: string
393
- id?: string
394
- }>()
395
-
396
- get('action') // 'create', 'delete', etc.
397
- get('id') // '42' or undefined
398
- params // { action: 'create', id: '42' }
173
+ if (useAutoHelp()) process.exit(0)
174
+ const port = useCliOption('port') || '3000'
175
+ return `Server running on port ${port}`
399
176
  },
400
177
  })
401
178
  ```
402
179
 
403
- Parameters are always `string` (or `string[]` for repeated params). Cast numerics yourself: `Number(get('id'))`.
404
-
405
- ## Common Patterns
406
-
407
- ### Pattern: Multi-command CLI with help
180
+ ### Pattern: Boolean and value flags
408
181
 
409
182
  ```ts
410
- const app = createCliApp({
411
- onUnknownCommand: (path, raiseError) => {
412
- useCommandLookupHelp()
413
- raiseError()
414
- },
415
- })
416
-
417
- app.cli('init/:name?', {
418
- description: 'Initialize a new project',
419
- args: { name: 'Project name (default: current directory)' },
420
- options: [
421
- { keys: ['template', 't'], description: 'Project template', value: 'default' },
422
- ],
423
- handler: () => {
424
- if (useAutoHelp()) return
425
- const { get } = useRouteParams<{ name?: string }>()
426
- const template = useCliOption('template') || 'default'
427
- return `Initialized ${get('name') || '.'} with template ${template}`
428
- },
429
- })
430
-
431
183
  app.cli('build', {
432
- description: 'Build the project',
433
184
  options: [
434
- { keys: ['watch', 'w'], description: 'Watch mode' },
435
- { keys: ['minify', 'm'], description: 'Minify output' },
185
+ { keys: ['watch', 'w'], description: 'Watch mode' }, // boolean
186
+ { keys: ['output', 'o'], description: 'Output dir', value: 'path' }, // value
436
187
  ],
437
188
  handler: () => {
438
- if (useAutoHelp()) return
439
- const flags = useCliOptions()
440
- return `Building... (watch=${!!flags.watch}, minify=${!!flags.minify})`
189
+ const watch = useCliOption('watch') // true | undefined
190
+ const output = useCliOption('output') // 'dist' | undefined
441
191
  },
442
192
  })
443
-
444
- app.cli('serve', {
445
- description: 'Start development server',
446
- options: [
447
- { keys: ['port', 'p'], description: 'Port number', value: '3000' },
448
- { keys: ['host', 'h'], description: 'Host address', value: 'localhost' },
449
- ],
450
- handler: () => {
451
- if (useAutoHelp()) return
452
- const port = useCliOption('port') || '3000'
453
- const host = useCliOption('host') || 'localhost'
454
- return `Serving at http://${host}:${port}`
455
- },
456
- })
457
-
458
- app.run()
459
193
  ```
460
194
 
461
- ### Pattern: Subcommands with shared logic
462
-
463
- ```ts
464
- // Shared composable for database connection
465
- function useDbConnection() {
466
- const { store } = useCliContext<{ db?: { conn?: any } }>()
467
- const { init } = store('db')
468
- return {
469
- getConnection: () => init('conn', () => {
470
- const flags = useCliOptions()
471
- return connectToDb(flags['db-url'] as string || 'localhost:5432')
472
- }),
473
- }
474
- }
475
-
476
- app.cli('db migrate', {
477
- description: 'Run pending migrations',
478
- handler: async () => {
479
- const { getConnection } = useDbConnection()
480
- const db = getConnection()
481
- await db.migrate()
482
- return 'Migrations complete'
483
- },
484
- })
485
-
486
- app.cli('db seed', {
487
- description: 'Run database seeds',
488
- handler: async () => {
489
- const { getConnection } = useDbConnection()
490
- const db = getConnection()
491
- await db.seed()
492
- return 'Seeding complete'
493
- },
494
- })
495
- ```
195
+ ### Pattern: Shared CLI and HTTP adapters
496
196
 
497
- ### Pattern: Global flags
197
+ Both adapters can share the same `Wooks` instance:
498
198
 
499
199
  ```ts
500
- // Check global flags in every handler
501
- function useGlobalFlags() {
502
- const flags = useCliOptions()
503
- if (flags.verbose || flags.v) {
504
- const logger = useEventLogger('cli')
505
- logger.log('Verbose mode enabled')
506
- }
507
- return {
508
- verbose: !!(flags.verbose || flags.v),
509
- quiet: !!(flags.quiet || flags.q),
510
- dryRun: !!(flags['dry-run']),
511
- }
512
- }
200
+ import { createCliApp } from '@wooksjs/event-cli'
201
+ import { createHttpApp } from '@wooksjs/event-http'
513
202
 
514
- app.cli('deploy/:env', {
515
- handler: () => {
516
- const { verbose, dryRun } = useGlobalFlags()
517
- const { get } = useRouteParams<{ env: string }>()
518
- if (dryRun) return `[DRY RUN] Would deploy to ${get('env')}`
519
- return `Deploying to ${get('env')}`
520
- },
521
- })
203
+ const httpApp = createHttpApp()
204
+ const cliApp = createCliApp({}, httpApp)
205
+
206
+ // CLI commands and HTTP routes share the same router
207
+ cliApp.cli('start', () => httpApp.listen(3000))
522
208
  ```
523
209
 
524
210
  ## Best Practices
525
211
 
526
- - **Use `app.cli(path, options)` with metadata** — Always provide `description` and `args` so help generation works out of the box.
527
- - **Use `useAutoHelp()` at the top of every handler** — Gives users consistent `--help` behavior across all commands.
528
- - **Use `useCliOption(name)` over `useCliOptions()[name]`** — `useCliOption` resolves key aliases (e.g., `--verbose` / `-v`), so it respects your option definitions.
529
- - **Use `onUnknownCommand` with `useCommandLookupHelp()`** — Provides a much better user experience than a generic "unknown command" error.
530
- - **Return values from handlers** — Don't call `console.log` directly; the framework formats and outputs return values automatically. This also makes testing easier.
531
- - **Type your route params** — Use `useRouteParams<{ env: string }>()` for type-safe access.
532
- - **Use regex constraints for numeric args** — `:version(\\d+)` prevents non-numeric values from matching.
212
+ - Always provide `description` and `options` for production CLI tools — it powers `--help`
213
+ - Use `useAutoHelp()` at the top of every command handler
214
+ - Use `useCommandLookupHelp()` in `onUnknownCommand` for better UX
215
+ - Use aliases for common abbreviations: `aliases: ['dep']` for `deploy`
533
216
 
534
217
  ## Gotchas
535
218
 
536
- - **Spaces and slashes are equivalent** — `'cmd test'` and `'cmd/test'` register the same command path. When displayed, they appear as spaces.
537
- - **Flags containing colons** — If a command segment contains a colon that isn't a parameter, escape it: `'config set\\:key'` → matches `$ mycli config set:key`.
538
- - **`useCliOptions()` includes `_` array** — The `_` property from minimist contains all positional args, including command segments. Use `useRouteParams()` for named arguments instead.
539
- - **Aliases inherit arguments** — An alias like `'d'` for `'deploy/:env'` automatically becomes `'d/:env'`. You don't need to add the `:env` yourself.
540
- - **Boolean flag negation** — `--no-cache` with `{ boolean: ['cache'] }` sets `cache: false`. Without the boolean option, it becomes `{ 'no-cache': true }`.
541
- - **Route precedence** — Static segments match before parametric, parametric before wildcard. `'deploy staging'` is preferred over `'deploy/:env'` when the input is `deploy staging`.
219
+ - `useCliOptions()` returns the raw `minimist` output — `_` contains positional args, everything else is flags
220
+ - `useCliOption(name)` resolves aliases from the option definitions — `useCliOptions()[name]` does not
221
+ - Help is auto-registered from `app.cli()` metadata — no separate help registration needed
222
+ - Colons in command names must be escaped: `'use\\:dev'` for command `use:dev`