@moostjs/event-cli 0.5.33 → 0.6.1

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.
@@ -0,0 +1,202 @@
1
+ # Advanced — @moostjs/event-cli
2
+
3
+ > Manual adapter setup, Wooks composables, DI scopes, multi-adapter patterns, and cliKind.
4
+
5
+ ## Concepts
6
+
7
+ `CliApp` handles the common case. For advanced scenarios — sharing a Moost instance across adapters, using Wooks composables directly, or fine-tuning DI — use `MoostCli` as a standalone adapter.
8
+
9
+ Wooks composables are functions that access the current CLI event context (via AsyncLocalStorage). They work anywhere in the handler call chain — in handlers, services, or interceptors.
10
+
11
+ ## API Reference
12
+
13
+ ### `MoostCli`
14
+
15
+ Low-level CLI adapter class implementing `TMoostAdapter<TCliHandlerMeta>`.
16
+
17
+ Constructor options (`TMoostCliOpts`):
18
+ - `wooksCli?: WooksCli | TWooksCliOptions` — a WooksCli instance or configuration options
19
+ - `debug?: boolean` — enable internal logging (default: `false`)
20
+ - `globalCliOptions?: { keys: string[]; description?: string; type?: TFunction }[]` — options shown in help for every command
21
+
22
+ ```ts
23
+ import { MoostCli, cliHelpInterceptor } from '@moostjs/event-cli'
24
+ import { Moost } from 'moost'
25
+
26
+ const app = new Moost()
27
+
28
+ app.applyGlobalInterceptors(
29
+ cliHelpInterceptor({ colors: true, lookupLevel: 3 }),
30
+ )
31
+
32
+ app.registerControllers(AppController)
33
+
34
+ app.adapter(new MoostCli({
35
+ wooksCli: {
36
+ cliHelp: { name: 'my-cli' },
37
+ },
38
+ globalCliOptions: [
39
+ { keys: ['help'], description: 'Display instructions for the command.' },
40
+ ],
41
+ }))
42
+
43
+ void app.init()
44
+ ```
45
+
46
+ ### When to use MoostCli vs CliApp
47
+
48
+ | Use case | Recommendation |
49
+ |----------|---------------|
50
+ | Standard CLI app | `CliApp` — less boilerplate |
51
+ | Pre-configured WooksCli instance | `MoostCli` — pass your own instance |
52
+ | Multiple adapters (CLI + HTTP) | `MoostCli` — attach to existing Moost instance |
53
+ | Custom error handling on WooksCli | `MoostCli` — configure `wooksCli.onError` |
54
+
55
+ ### `cliKind`
56
+
57
+ Event type identifier for CLI events, re-exported from `@wooksjs/event-cli`. Useful when writing adapters or composables that distinguish event types.
58
+
59
+ ```ts
60
+ import { cliKind } from '@moostjs/event-cli'
61
+ ```
62
+
63
+ ## Wooks composables
64
+
65
+ These are from `@wooksjs/event-cli` and `@wooksjs/event-core`. They work inside any handler or service during a CLI event.
66
+
67
+ ### `useCliOption(name: string)`
68
+
69
+ Read a single option value. This is what `@CliOption()` uses under the hood.
70
+
71
+ ```ts
72
+ import { useCliOption } from '@wooksjs/event-cli'
73
+
74
+ @Cli('build')
75
+ build() {
76
+ const verbose = useCliOption('verbose')
77
+ if (verbose) console.log('Verbose mode on')
78
+ return 'Building...'
79
+ }
80
+ ```
81
+
82
+ ### `useCliOptions()`
83
+
84
+ Read all parsed CLI options at once.
85
+
86
+ ```ts
87
+ import { useCliOptions } from '@wooksjs/event-cli'
88
+
89
+ @Cli('build')
90
+ build() {
91
+ const opts = useCliOptions()
92
+ // opts: { verbose: true, target: 'production', ... }
93
+ return `Building with ${JSON.stringify(opts)}`
94
+ }
95
+ ```
96
+
97
+ ### `useRouteParams()`
98
+
99
+ Read positional arguments. This is what `@Param()` uses under the hood.
100
+
101
+ ```ts
102
+ import { useRouteParams } from '@wooksjs/event-core'
103
+
104
+ @Cli('deploy/:env')
105
+ deploy() {
106
+ const params = useRouteParams()
107
+ return `Deploying to ${params.get('env')}`
108
+ }
109
+ ```
110
+
111
+ ### `useCliHelp()`
112
+
113
+ Access the help renderer programmatically.
114
+
115
+ ```ts
116
+ import { useCliHelp } from '@wooksjs/event-cli'
117
+
118
+ @Cli('info')
119
+ info() {
120
+ const { print } = useCliHelp()
121
+ print(true) // print help with colors
122
+ }
123
+ ```
124
+
125
+ ## Common Patterns
126
+
127
+ ### Pattern: Multi-adapter CLI + HTTP
128
+
129
+ A single Moost instance serving both CLI commands and HTTP routes:
130
+
131
+ ```ts
132
+ import { Cli, Controller, Param } from '@moostjs/event-cli'
133
+ import { Get } from '@moostjs/event-http'
134
+
135
+ @Controller('health')
136
+ export class HealthController {
137
+ @Cli('check')
138
+ @Get('check')
139
+ check() {
140
+ return { status: 'ok', uptime: process.uptime() }
141
+ }
142
+ }
143
+ ```
144
+
145
+ Wire up both adapters:
146
+
147
+ ```ts
148
+ import { MoostCli } from '@moostjs/event-cli'
149
+ import { MoostHttp } from '@moostjs/event-http'
150
+ import { Moost } from 'moost'
151
+
152
+ const app = new Moost()
153
+ app.registerControllers(HealthController)
154
+
155
+ app.adapter(new MoostCli())
156
+ app.adapter(new MoostHttp()).listen(3000)
157
+
158
+ void app.init()
159
+ ```
160
+
161
+ Now `my-cli health check` and `GET /health/check` both invoke the same handler.
162
+
163
+ ### Pattern: DI scopes in CLI
164
+
165
+ ```ts
166
+ import { Injectable } from 'moost'
167
+
168
+ @Injectable('SINGLETON')
169
+ export class ConfigService {
170
+ readonly env = process.env.NODE_ENV ?? 'development'
171
+ }
172
+
173
+ @Injectable('FOR_EVENT')
174
+ export class CommandState {
175
+ startedAt = Date.now()
176
+ }
177
+ ```
178
+
179
+ - `SINGLETON` — one instance for the app lifetime (shared config, DB connections)
180
+ - `FOR_EVENT` — new instance per CLI command execution (command-specific state)
181
+
182
+ Controllers default to `SINGLETON` scope, which is correct for most CLI apps.
183
+
184
+ ## Integration
185
+
186
+ - Wooks composables (`useCliOption`, `useCliOptions`, etc.) are imported from `@wooksjs/event-cli`
187
+ - Route param composables (`useRouteParams`) come from `@wooksjs/event-core`
188
+ - DI decorators (`@Injectable`, `@Inject`, `@Provide`) come from `moost`
189
+ - HTTP decorators (`@Get`, `@Post`, etc.) come from `@moostjs/event-http`
190
+
191
+ ## Best Practices
192
+
193
+ - Use `MoostCli` only when `CliApp` isn't flexible enough
194
+ - When `debug` is `false` (default), DI container logging is suppressed for clean terminal output
195
+ - In multi-adapter setups, decorate shared methods with both `@Cli()` and `@Get()`/`@Post()`
196
+ - Composables work in interceptors and services too — not just handlers
197
+
198
+ ## Gotchas
199
+
200
+ - `MoostCli` calls `app.init()` — don't call `init()` yourself after attaching the adapter in `CliApp.start()`
201
+ - Wooks composables only work inside an active event context (during handler execution)
202
+ - When using a custom `WooksCli` instance with `MoostCli`, the `onNotFound` callback is overridden by the adapter
@@ -0,0 +1,152 @@
1
+ # Commands — @moostjs/event-cli
2
+
3
+ > Defining CLI commands, command paths, positional arguments, aliases, and examples.
4
+
5
+ ## Concepts
6
+
7
+ Every CLI command is a method decorated with `@Cli()`. The decorator argument defines the command path — the words a user types to invoke it. Command paths support positional arguments (`:param` segments), space or slash separation, and escaped colons.
8
+
9
+ ## API Reference
10
+
11
+ ### `@Cli(path?: string)`
12
+
13
+ Method decorator. Registers the method as a CLI command handler.
14
+
15
+ - `path` — command path with segments separated by spaces or `/`. Segments starting with `:` are positional arguments. If omitted, the method name is used as the command.
16
+
17
+ ```ts
18
+ import { Cli, Controller } from '@moostjs/event-cli'
19
+
20
+ @Controller()
21
+ export class AppController {
22
+ @Cli('deploy/:env')
23
+ deploy(@Param('env') env: string) {
24
+ return `Deploying to ${env}...`
25
+ }
26
+ }
27
+ ```
28
+
29
+ ### `@CliAlias(alias: string)`
30
+
31
+ Method decorator. Defines an alternative name for a command. Stack multiple decorators for multiple aliases.
32
+
33
+ ```ts
34
+ import { Cli, CliAlias, Controller, Param } from '@moostjs/event-cli'
35
+
36
+ @Controller()
37
+ export class AppController {
38
+ @Cli('install/:package')
39
+ @CliAlias('i/:package')
40
+ @CliAlias('add/:package')
41
+ install(@Param('package') pkg: string) {
42
+ return `Installing ${pkg}...`
43
+ }
44
+ }
45
+ ```
46
+
47
+ All three invoke the same handler:
48
+ ```bash
49
+ my-cli install lodash
50
+ my-cli i lodash
51
+ my-cli add lodash
52
+ ```
53
+
54
+ ### `@CliExample(cmd: string, description?: string)`
55
+
56
+ Method decorator. Adds a usage example displayed in `--help` output. Stack multiple decorators for multiple examples.
57
+
58
+ ```ts
59
+ import { Cli, CliExample, Controller } from '@moostjs/event-cli'
60
+
61
+ @Controller()
62
+ export class DeployController {
63
+ @Cli('deploy/:env')
64
+ @CliExample('deploy dev -p my-app', 'Deploy to development')
65
+ @CliExample('deploy prod --verbose', 'Deploy with verbose logging')
66
+ deploy(@Param('env') env: string) {
67
+ return `Deploying to ${env}`
68
+ }
69
+ }
70
+ ```
71
+
72
+ ### `@Param(name: string)`
73
+
74
+ Parameter decorator (re-exported from `moost`). Extracts a positional argument from a `:name` segment in the command path.
75
+
76
+ ```ts
77
+ @Cli('copy/:source/:dest')
78
+ copy(
79
+ @Param('source') source: string,
80
+ @Param('dest') dest: string,
81
+ ) {
82
+ return `Copying ${source} to ${dest}`
83
+ }
84
+ ```
85
+
86
+ ```bash
87
+ my-cli copy fileA.txt fileB.txt
88
+ ```
89
+
90
+ ## Common Patterns
91
+
92
+ ### Pattern: Space-separated vs slash-separated paths
93
+
94
+ Both notations are equivalent. The user always types space-separated words:
95
+
96
+ ```ts
97
+ // These are identical:
98
+ @Cli('config set')
99
+ @Cli('config/set')
100
+ ```
101
+
102
+ ```bash
103
+ my-cli config set
104
+ ```
105
+
106
+ ### Pattern: Default path from method name
107
+
108
+ When `@Cli()` is called without arguments, the method name becomes the command:
109
+
110
+ ```ts
111
+ @Cli()
112
+ status() {
113
+ return 'All systems operational'
114
+ }
115
+ ```
116
+
117
+ ```bash
118
+ my-cli status
119
+ ```
120
+
121
+ ### Pattern: Escaped colons
122
+
123
+ If a command contains a literal colon (like `build:dev`), escape it:
124
+
125
+ ```ts
126
+ @Cli('build\\:dev')
127
+ buildDev() {
128
+ return 'Building for dev...'
129
+ }
130
+ ```
131
+
132
+ ```bash
133
+ my-cli build:dev
134
+ ```
135
+
136
+ ### Pattern: Return values
137
+
138
+ Whatever a handler returns is printed to stdout. Return a string for plain text, or an object/array for JSON:
139
+
140
+ ```ts
141
+ @Cli('info')
142
+ info() {
143
+ return { name: 'my-app', version: '1.0.0' }
144
+ }
145
+ ```
146
+
147
+ ## Gotchas
148
+
149
+ - Command paths with `:` that are NOT parameters must be escaped with `\\:` (e.g. `'build\\:dev'`)
150
+ - Space-separated and slash-separated paths are equivalent internally — `'config set'` becomes `'config/set'`
151
+ - If you omit the path in `@Cli()`, the method name is used as the command name
152
+ - Multiple `@Cli()` decorators on the same method register multiple commands pointing to the same handler
@@ -0,0 +1,142 @@
1
+ # Controllers — @moostjs/event-cli
2
+
3
+ > Organizing commands into logical groups with prefixes and nesting.
4
+
5
+ ## Concepts
6
+
7
+ Controllers group related commands under a shared prefix, creating natural command hierarchies like `git remote add` or `docker compose up`. A controller is a class with `@Controller(prefix?)`. The prefix is prepended to all command paths inside it.
8
+
9
+ Controllers can be nested via `@ImportController()` — the child's prefix appends to the parent's, building multi-level command trees.
10
+
11
+ ## API Reference
12
+
13
+ ### `@Controller(prefix?: string)`
14
+
15
+ Class decorator (re-exported from `moost`). Marks a class as a CLI controller. The optional `prefix` sets a command prefix for all methods inside.
16
+
17
+ ```ts
18
+ import { Cli, Controller, Param } from '@moostjs/event-cli'
19
+
20
+ @Controller('user')
21
+ export class UserController {
22
+ @Cli('create/:name')
23
+ create(@Param('name') name: string) {
24
+ return `Created user: ${name}`
25
+ }
26
+
27
+ @Cli('delete/:name')
28
+ delete(@Param('name') name: string) {
29
+ return `Deleted user: ${name}`
30
+ }
31
+ }
32
+ ```
33
+
34
+ ```bash
35
+ my-cli user create Alice
36
+ my-cli user delete Bob
37
+ ```
38
+
39
+ Without a prefix (`@Controller()`), commands are registered at the root level.
40
+
41
+ ### `@ImportController(ctrl: Function)`
42
+
43
+ Class decorator (from `moost`). Nests a child controller inside the parent. The child's prefix appends to the parent's. Register only the top-level controller — imported children are registered automatically.
44
+
45
+ ```ts
46
+ import { Cli, Controller, Param } from '@moostjs/event-cli'
47
+ import { ImportController } from 'moost'
48
+
49
+ @Controller('view')
50
+ export class ViewCommand {
51
+ @Cli(':id')
52
+ view(@Param('id') id: string) {
53
+ return `Viewing profile ${id}`
54
+ }
55
+ }
56
+
57
+ @Controller('profile')
58
+ @ImportController(ViewCommand)
59
+ export class ProfileController {
60
+ @Cli('list')
61
+ list() {
62
+ return 'Listing profiles...'
63
+ }
64
+ }
65
+ ```
66
+
67
+ ```bash
68
+ my-cli profile list # ProfileController.list()
69
+ my-cli profile view 42 # ViewCommand.view("42")
70
+ ```
71
+
72
+ ## Common Patterns
73
+
74
+ ### Pattern: Registering controllers
75
+
76
+ With `CliApp`:
77
+ ```ts
78
+ new CliApp()
79
+ .controllers(UserController, ConfigController)
80
+ .useHelp({ name: 'my-cli' })
81
+ .start()
82
+ ```
83
+
84
+ With standard Moost:
85
+ ```ts
86
+ const app = new Moost()
87
+ app.registerControllers(UserController, ConfigController)
88
+ ```
89
+
90
+ ### Pattern: Multi-level nesting
91
+
92
+ ```ts
93
+ @Controller('add')
94
+ class RemoteAddController {
95
+ @Cli(':name/:url')
96
+ add(@Param('name') name: string, @Param('url') url: string) {
97
+ return `Adding remote ${name} -> ${url}`
98
+ }
99
+ }
100
+
101
+ @Controller('remote')
102
+ @ImportController(RemoteAddController)
103
+ class RemoteController {
104
+ @Cli('list')
105
+ list() { return 'Listing remotes...' }
106
+ }
107
+
108
+ @Controller()
109
+ @ImportController(RemoteController)
110
+ class GitController {
111
+ @Cli('status')
112
+ status() { return 'On branch main' }
113
+ }
114
+ ```
115
+
116
+ ```bash
117
+ my-cli status # GitController
118
+ my-cli remote list # RemoteController
119
+ my-cli remote add origin git@... # RemoteAddController
120
+ ```
121
+
122
+ ## Path composition
123
+
124
+ The final command path is: **controller prefix** + **child prefix** + **@Cli() path**.
125
+
126
+ | Parent prefix | Child prefix | `@Cli()` path | Final command |
127
+ |--------------|-------------|---------------|---------------|
128
+ | `''` (root) | — | `status` | `status` |
129
+ | `remote` | — | `list` | `remote list` |
130
+ | `remote` | `add` | `:name/:url` | `remote add :name :url` |
131
+
132
+ ## Best Practices
133
+
134
+ - Use `@Controller(prefix)` to create command namespaces — `user`, `config`, `remote`
135
+ - Only register top-level controllers with `.controllers()` — nested children auto-register
136
+ - Keep nesting to 2-3 levels max for usability
137
+ - Use `@Controller()` (no prefix) for root-level commands
138
+
139
+ ## Gotchas
140
+
141
+ - Registering a child controller directly AND via `@ImportController` can cause duplicate command registrations
142
+ - The controller prefix uses the same space/slash equivalence as command paths
@@ -0,0 +1,114 @@
1
+ # Core concepts & setup — @moostjs/event-cli
2
+
3
+ > Installation, project scaffolding, and the mental model for building CLI apps with Moost.
4
+
5
+ ## Concepts
6
+
7
+ `@moostjs/event-cli` is a Moost adapter that turns decorated TypeScript classes into CLI applications. It wraps `@wooksjs/event-cli` (the Wooks CLI engine) and integrates with Moost's decorator-driven DI, interceptors, and pipes.
8
+
9
+ The core mental model:
10
+ - **Commands** are methods decorated with `@Cli('path')` inside controller classes
11
+ - **Controllers** group commands under shared prefixes (like `git remote add`)
12
+ - **Options** are method parameters decorated with `@CliOption('flag')`
13
+ - **Arguments** are extracted from `:param` segments in command paths via `@Param('name')`
14
+ - **CliApp** is a convenience class that wires everything together with one fluent API
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @moostjs/event-cli moost @wooksjs/event-core wooks
20
+ # or
21
+ pnpm add @moostjs/event-cli moost @wooksjs/event-core wooks
22
+ ```
23
+
24
+ Peer dependencies: `moost`, `@wooksjs/event-core`, `wooks`.
25
+
26
+ ## Project scaffolding
27
+
28
+ ```bash
29
+ npm create moost -- --cli
30
+ # or with a name:
31
+ npm create moost my-cli -- --cli
32
+ ```
33
+
34
+ Creates:
35
+ ```
36
+ my-cli/
37
+ ├── src/
38
+ │ ├── controllers/
39
+ │ │ └── app.controller.ts
40
+ │ ├── main.ts
41
+ │ └── bin.ts
42
+ ├── package.json
43
+ └── tsconfig.json
44
+ ```
45
+
46
+ ## CliApp — quick setup
47
+
48
+ `CliApp` extends `Moost` and provides a fluent API for the common case:
49
+
50
+ ```ts
51
+ import { CliApp } from '@moostjs/event-cli'
52
+ import { AppController } from './controllers/app.controller'
53
+
54
+ new CliApp()
55
+ .controllers(AppController) // register controller classes
56
+ .useHelp({ name: 'my-cli' }) // enable --help with app name
57
+ .useOptions([ // global options shown in all commands
58
+ { keys: ['help'], description: 'Display instructions for the command.' },
59
+ ])
60
+ .start() // wire adapters + interceptors, call init()
61
+ ```
62
+
63
+ ### `CliApp` methods
64
+
65
+ | Method | Description |
66
+ |--------|-------------|
67
+ | `.controllers(...ctrls)` | Register one or more controller classes (shortcut for `registerControllers`) |
68
+ | `.useHelp(opts)` | Configure the help system (name, title, colors, lookupLevel, maxWidth, maxLeft, mark) |
69
+ | `.useOptions(opts)` | Set global CLI options that appear in every command's help |
70
+ | `.start()` | Creates `MoostCli`, attaches adapter, applies help interceptor, calls `init()` |
71
+
72
+ ## Exports
73
+
74
+ All imports come from `'@moostjs/event-cli'`:
75
+
76
+ | Export | Kind | Purpose |
77
+ |--------|------|---------|
78
+ | `CliApp` | class | Quick-setup CLI application factory |
79
+ | `MoostCli` | class | Low-level adapter (implements `TMoostAdapter`) |
80
+ | `Cli` | decorator | Define a CLI command on a method |
81
+ | `CliAlias` | decorator | Add an alias for a command |
82
+ | `CliExample` | decorator | Add a usage example for help output |
83
+ | `CliOption` | decorator | Bind a parameter to a `--flag` |
84
+ | `CliGlobalOption` | decorator | Define a global option on a controller class |
85
+ | `cliHelpInterceptor` | function | Factory for the help interceptor |
86
+ | `CliHelpInterceptor` | decorator | Decorator form of the help interceptor |
87
+ | `cliKind` | object | Event type identifier for CLI events |
88
+ | `Controller` | decorator | Re-exported from `moost` |
89
+ | `Param` | decorator | Re-exported from `moost` |
90
+ | `Intercept` | decorator | Re-exported from `moost` |
91
+ | `Description` | decorator | Re-exported from `moost` |
92
+ | `Optional` | decorator | Re-exported from `moost` |
93
+ | `defineBeforeInterceptor` | function | Re-exported from `moost` |
94
+ | `defineAfterInterceptor` | function | Re-exported from `moost` |
95
+ | `defineInterceptor` | function | Re-exported from `moost` |
96
+ | `TInterceptorPriority` | type | Re-exported from `moost` |
97
+
98
+ ## Running the app
99
+
100
+ ```bash
101
+ # Development
102
+ npx tsx src/bin.ts greet World
103
+
104
+ # Production (after compiling)
105
+ node dist/bin.js greet World
106
+ ```
107
+
108
+ The return value of a command handler is printed to stdout.
109
+
110
+ ## Best Practices
111
+
112
+ - Use `CliApp` for standard CLI apps; use `MoostCli` only when you need full control or multi-adapter setups
113
+ - Keep `tsconfig.json` with `"experimentalDecorators": true` and `"emitDecoratorMetadata": true`
114
+ - Register only top-level controllers — nested children are auto-registered via `@ImportController`