@maykonpaulo/maestro-cli 0.2.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.
package/README.md ADDED
@@ -0,0 +1,457 @@
1
+ # @maykonpaulo/maestro-cli
2
+
3
+ Command-line interface for the Maestro declarative engine.
4
+
5
+ ## Status: foundation + operational commands
6
+
7
+ The **Phase 5 foundation** shipped the `maestro` binary, `--help`, `--version`, and an extensible
8
+ command architecture. `maestro generate` (wraps the core's Declarative Config Generator),
9
+ `maestro validate` (wraps the core's Declarative File Loader), `maestro diff` (compares two
10
+ declarative config files), `maestro snapshot` (produces a canonical, deterministic snapshot of a
11
+ declarative config file) and `maestro introspect` (validates and canonicalizes a local
12
+ `IntrospectionResult`, **offline**) are the operational commands shipped so far. Connecting to a real
13
+ datasource is a separate, not-yet-implemented step. The CLI is a pure consumer of
14
+ `@maykonpaulo/maestro-core`; it introduces no capability that doesn't already exist there.
15
+
16
+ The package is now **publishable** (`private` removed, `publishConfig.access: public`); its first
17
+ public release is prepared via a Changeset and ships through the normal release flow
18
+ (`next` → `rc` → `latest`). The CLI is **not** the owner of the repo-wide GitHub Release `latest`
19
+ pointer — that stays with `@maykonpaulo/maestro-core` (the CLI's releases are tagged with
20
+ `--latest=false`). Publishing happens only via merge/promotion in the release workflow, never from a
21
+ local command. See [`RELEASE.md`](../../RELEASE.md).
22
+
23
+ ## Usage
24
+
25
+ ```bash
26
+ maestro --help
27
+ maestro --version
28
+ maestro generate --input ./metadata.json --type metadata --format json
29
+ maestro validate --input ./maestro.config.yaml
30
+ maestro diff --from ./maestro.config.old.yaml --to ./maestro.config.new.yaml
31
+ maestro snapshot --input ./maestro.config.yaml --out ./maestro.snapshot.json
32
+ maestro introspect --input ./introspection.json --out ./maestro.introspection.json
33
+ ```
34
+
35
+ ```
36
+ $ maestro --help
37
+ maestro — Maestro CLI
38
+
39
+ Command-line interface for the Maestro declarative engine.
40
+
41
+ Usage:
42
+ maestro <command> [options]
43
+
44
+ Options:
45
+ -h, --help Show this help message
46
+ -v, --version Show the CLI version
47
+
48
+ Available commands:
49
+ generate Generate a declarative config from a local metadata/schema JSON file
50
+ validate Validate a declarative config file (YAML or JSON)
51
+ diff Compare two declarative config files (YAML or JSON)
52
+ snapshot Produce a canonical snapshot of a declarative config file (YAML or JSON)
53
+ introspect Validate and canonicalize a local IntrospectionResult JSON file (offline)
54
+ ```
55
+
56
+ Running an unrecognized command exits with a non-zero status and a message pointing back to
57
+ `--help`:
58
+
59
+ ```bash
60
+ $ maestro unknown-thing
61
+ Unknown command 'unknown-thing'. Run "maestro --help" to see available commands.
62
+ $ echo $?
63
+ 1
64
+ ```
65
+
66
+ ## `maestro generate`
67
+
68
+ Reads a local JSON file containing either `EntityMetadata[]` or `EntitySchema[]` (plus optional
69
+ relations/operations) and generates a declarative config (`EntityDeclaration[]` + optional
70
+ consumers) using the core's `generateDeclarativeConfigFromMetadata`/`generateDeclarativeConfigFromSchema`
71
+ and `serializeDeclarativeConfig`.
72
+
73
+ **What it does NOT do:** no introspection of a live datasource, no database/provider connection, no
74
+ `createMaestro()` call. It only reads a file, transforms it via the core's public APIs, and writes
75
+ text (stdout or a file). Introspecting a real datasource is a separate, not-yet-implemented command
76
+ (`maestro introspect`).
77
+
78
+ Run `maestro generate --help` for the full flag reference and examples inline.
79
+
80
+ ### What input is expected
81
+
82
+ - `--type metadata` expects the JSON file to be an object matching
83
+ `{ entities: EntityMetadata[], relations?: RelationMetadata[], operations?: OperationMetadata[] }`
84
+ — typically produced by serializing `engine.getMetadata()` (or the `entities` subset of it).
85
+ - `--type schema` expects `{ entities: EntitySchema[], relations?: RelationSchema[] }` — the
86
+ low-level config shape you'd otherwise write by hand or get from introspection tooling.
87
+
88
+ Minimal examples of both shapes are checked into
89
+ [`packages/cli/examples/metadata.json`](./examples/metadata.json) and
90
+ [`packages/cli/examples/schema.json`](./examples/schema.json).
91
+
92
+ ### JSON output
93
+
94
+ ```bash
95
+ $ maestro generate --input packages/cli/examples/metadata.json --type metadata --format json
96
+ {
97
+ "entities": [
98
+ {
99
+ "entity": "user",
100
+ "label": "User",
101
+ "pluralLabel": "Users",
102
+ "fields": {
103
+ "email": { "type": "email", "label": "Email", "required": true, "searchable": true },
104
+ "id": { "type": "uuid", "label": "Id", "readonly": true, "primary": true }
105
+ }
106
+ }
107
+ ]
108
+ }
109
+ ```
110
+
111
+ ### YAML output
112
+
113
+ ```bash
114
+ $ maestro generate --input packages/cli/examples/schema.json --type schema --format yaml
115
+ entities:
116
+ - entity: user
117
+ label: User
118
+ pluralLabel: Users
119
+ fields:
120
+ email:
121
+ type: email
122
+ label: Email
123
+ required: true
124
+ searchable: true
125
+ id:
126
+ type: uuid
127
+ label: Id
128
+ readonly: true
129
+ primary: true
130
+ ```
131
+
132
+ ### Writing to a file
133
+
134
+ ```bash
135
+ maestro generate --input ./metadata.json --type metadata --format yaml --out ./maestro.config.yaml
136
+ # Declarative config written to ./maestro.config.yaml
137
+ ```
138
+
139
+ | Flag | Required | Description |
140
+ |---|---|---|
141
+ | `--input <path>` | yes | Path to a local JSON file |
142
+ | `--type <metadata\|schema>` | yes | Whether the input matches `EntityMetadata[]` or `EntitySchema[]` shape |
143
+ | `--format <json\|yaml>` | no (default `json`) | Output format |
144
+ | `--out <path>` | no (default: stdout) | Writes the result to a file instead of printing it |
145
+
146
+ Errors (missing flags, unreadable file, invalid JSON, malformed shape) print a single readable line
147
+ to stderr prefixed with `maestro generate:` and exit with status `1`.
148
+
149
+ ### Recommended flow: metadata/schema → generate → maestro.config → createMaestro
150
+
151
+ ```
152
+ EntityMetadata[] / EntitySchema[] (already exists)
153
+ ↓ maestro generate --input ... --type ... --out maestro.config.yaml
154
+ maestro.config.yaml
155
+ ↓ loadDeclarativeConfigFromFile('./maestro.config.yaml', { yamlParser })
156
+ DeclarativeFileConfig (validated)
157
+
158
+ createMaestro({ datasources, declarations })
159
+ ```
160
+
161
+ The file `maestro generate` writes is a normal declarative config — it round-trips through the
162
+ existing [Declarative File Loader](../../docs/specs/declarative-file-loader.md) and
163
+ `createMaestro({ declarations })` unchanged, exactly like a hand-written `maestro.config.yaml`. See
164
+ [`docs/specs/cli-generate.md`](../../docs/specs/cli-generate.md) for the full walkthrough, including
165
+ how to validate the generated file end-to-end.
166
+
167
+ ## `maestro validate`
168
+
169
+ Reads a local declarative config file (`maestro.config.yaml`/`.yml`/`.json`) and validates its
170
+ structure using the core's `loadDeclarativeConfigFromString`. It is the natural counterpart to
171
+ `maestro generate`: `generate` writes the file, `validate` confirms it is well-formed before you use
172
+ it at runtime.
173
+
174
+ ```bash
175
+ $ maestro validate --input packages/cli/examples/maestro.config.yaml
176
+ Valid declarative config: packages/cli/examples/maestro.config.yaml
177
+ Entities: 2
178
+ Consumers: 1
179
+ ```
180
+
181
+ The format is detected from the file extension (`.json` → JSON, `.yaml`/`.yml` → YAML) unless
182
+ `--format` overrides it. YAML is parsed by the `yaml` package the CLI provides — the core has no
183
+ bundled YAML dependency.
184
+
185
+ **What it does NOT do:** no `createMaestro()` call, no database/provider connection, and it does NOT
186
+ require declared operations to have a real handler binding. It only reads a file and validates its
187
+ declarative structure. Wiring operations to code and starting the runtime is what `createMaestro()`
188
+ does separately — see the [validate spec](../../docs/specs/cli-validate.md#diferença-entre-validar-o-arquivo-e-inicializar-o-engine)
189
+ for the exact difference.
190
+
191
+ | Flag | Required | Description |
192
+ |---|---|---|
193
+ | `--input`, `-i <path>` | yes | Path to a local declarative config file (`.yaml`, `.yml` or `.json`) |
194
+ | `--format <json\|yaml>` | no | Overrides the format detected from the file extension |
195
+
196
+ Errors (missing flag, unreadable file, unknown extension, invalid format, parse failure, invalid
197
+ structure) print a single readable line to stderr prefixed with `maestro validate:` and exit with a
198
+ non-zero status. Run `maestro validate --help` for the full reference, and see
199
+ [`docs/specs/cli-validate.md`](../../docs/specs/cli-validate.md) for the complete walkthrough.
200
+
201
+ ## `maestro diff`
202
+
203
+ Compares two local declarative config files and prints a readable, deterministic report of what
204
+ changed. Both files are loaded and validated with the core's `loadDeclarativeConfigFromString` (the
205
+ same validation as `maestro validate`), then their normalised structures are compared. It's the tool
206
+ for reviewing, promoting or versioning a declarative change: `validate` confirms one file is
207
+ well-formed; `diff` shows exactly what moved between two versions.
208
+
209
+ ```bash
210
+ $ maestro diff --from ./before.json --to ./after.json
211
+ Differences found.
212
+
213
+ Entities:
214
+ + invoice
215
+ - legacyCustomer
216
+ ~ user
217
+ fields:
218
+ + email
219
+ ~ name
220
+ label: "Full name" → "Name"
221
+ operations:
222
+ - archive
223
+
224
+ Consumers:
225
+ + admin:user
226
+ ~ backoffice:user
227
+ list: {"fields":["id"]} → {"fields":["id","name"]}
228
+ ```
229
+
230
+ When the two files are structurally equal it prints `No differences found.`. The format of each file
231
+ is detected from its extension (`.json` → JSON, `.yaml`/`.yml` → YAML) unless `--from-format` /
232
+ `--to-format` override it, so you can diff a `.json` against a `.yaml`.
233
+
234
+ **What it compares:** entities (label/pluralLabel/description/capabilities), fields
235
+ (type/label/required/readonly/description/enumOptions/relationEntity/…), operations, relationships,
236
+ and consumers (list/detail/forms/actions). **What it does NOT do:** no `createMaestro()`, no
237
+ database/provider connection, no operation-binding requirement, and it never compares against a live
238
+ schema — it diffs **declarative files**, not introspection metadata. The core's `DiffEngine` operates
239
+ on `IntrospectionResult` (real DB schema), which is a different, not-yet-wired path.
240
+
241
+ | Flag | Required | Description |
242
+ |---|---|---|
243
+ | `--from`, `-f <path>` | yes | Baseline declarative config file |
244
+ | `--to`, `-t <path>` | yes | Changed declarative config file |
245
+ | `--from-format <json\|yaml>` | no | Overrides the format detected from the `--from` extension |
246
+ | `--to-format <json\|yaml>` | no | Overrides the format detected from the `--to` extension |
247
+
248
+ **Exit codes:** `0` = valid files, no differences; `1` = valid files, with differences; `2` = usage,
249
+ read, parse or validation error. Errors print a single readable line to stderr prefixed with
250
+ `maestro diff:`. Run `maestro diff --help` for the full reference, and see
251
+ [`docs/specs/cli-diff.md`](../../docs/specs/cli-diff.md) for the complete walkthrough.
252
+
253
+ ## `maestro snapshot`
254
+
255
+ Loads a local declarative config file, validates it with the core's `loadDeclarativeConfigFromString`
256
+ (the same validation as `maestro validate`), and emits a **canonical, deterministic JSON snapshot** of
257
+ its declarations. The snapshot is a stable, versionable artifact: commit it alongside your config, review
258
+ it in PRs, and use it as the baseline for future comparison. The same (semantically equivalent) input
259
+ always produces byte-identical output.
260
+
261
+ ```bash
262
+ $ maestro snapshot --input packages/cli/examples/maestro.config.yaml
263
+ {
264
+ "declarations": {
265
+ "consumers": [ ... ],
266
+ "entities": [ ... ],
267
+ "relations": [ { "fromEntity": "order", "fromField": "userId", "toEntity": "user", "toField": "id", "type": "many-to-one" } ]
268
+ },
269
+ "kind": "maestro.declarative.snapshot",
270
+ "schemaVersion": 1,
271
+ "source": { "format": "yaml", "path": "packages/cli/examples/maestro.config.yaml" },
272
+ "summary": { "consumers": 1, "entities": 2, "relations": 1 }
273
+ }
274
+ ```
275
+
276
+ Writing to a file prints a readable summary instead of the JSON:
277
+
278
+ ```bash
279
+ $ maestro snapshot --input packages/cli/examples/maestro.config.yaml --out ./maestro.snapshot.json
280
+ Snapshot written: ./maestro.snapshot.json
281
+ Entities: 2
282
+ Consumers: 1
283
+ Relations: 1
284
+ ```
285
+
286
+ The snapshot is **canonical**: entities are sorted by name, consumers by name, relationships (and the
287
+ flattened top-level `relations` index, each tagged with its `fromEntity`) by derived id, and every object
288
+ key is sorted. It is **deterministic by design** — it never includes a timestamp, an absolute path, a
289
+ random hash or any value that varies between runs of the same input, so re-running it only changes the
290
+ output when the config actually changed.
291
+
292
+ **Declarative snapshot vs. introspection snapshot.** This command snapshots a **declarative file**, not a
293
+ live database or runtime introspection. The core's Snapshot Engine (`IntrospectionSnapshot` /
294
+ `SnapshotRepository`) captures an `IntrospectionResult` from a real datasource and intentionally carries
295
+ volatile fields (`id`, `timestamp`) — a different, not-yet-wired path. `maestro snapshot` is local,
296
+ offline and reproducible.
297
+
298
+ **What it does NOT do:** no `createMaestro()`, no database/provider connection, no operation execution,
299
+ and it does NOT require declared operations to have a real handler binding — operations are captured as
300
+ declared. It never modifies the input file.
301
+
302
+ | Flag | Required | Description |
303
+ |---|---|---|
304
+ | `--input`, `-i <path>` | yes | Path to a local declarative config file (`.yaml`, `.yml` or `.json`) |
305
+ | `--input-format <json\|yaml>` | no | Overrides the format detected from the `--input` extension |
306
+ | `--format json` | no (default `json`) | Snapshot output format. Only `json` is supported for now |
307
+ | `--out <path>` | no (default: stdout) | Writes the snapshot to a file instead of printing it |
308
+
309
+ **Exit codes:** `0` = snapshot produced; `1` = usage, read, parse, validation or write error. Errors
310
+ print a single readable line to stderr prefixed with `maestro snapshot:`. Run `maestro snapshot --help`
311
+ for the full reference, and see [`docs/specs/cli-snapshot.md`](../../docs/specs/cli-snapshot.md) for the
312
+ complete walkthrough, including how `validate`, `diff` and `snapshot` relate.
313
+
314
+ ## `maestro introspect`
315
+
316
+ Reads a local JSON file describing an `IntrospectionResult` — the core's introspection contract
317
+ (`{ entities: EntityIntrospectionSchema[], relations: RelationIntrospectionSchema[] }`) — validates it
318
+ against that contract, and emits a **canonical, deterministic JSON artifact**. The same (semantically
319
+ equivalent) input always produces byte-identical output, so the artifact is a stable, versionable input
320
+ for future comparison, generation or review.
321
+
322
+ ```bash
323
+ $ maestro introspect --input packages/cli/examples/introspection.json
324
+ {
325
+ "kind": "maestro.introspection",
326
+ "result": {
327
+ "entities": [ { "fields": [ ... ], "table": "orders" }, { "fields": [ ... ], "table": "users" } ],
328
+ "relations": [ { "confidence": "definite", "from": { ... }, "id": "orders.user_id->users.id", ... } ]
329
+ },
330
+ "schemaVersion": 1,
331
+ "source": { "path": "packages/cli/examples/introspection.json" },
332
+ "summary": { "entities": 2, "relations": 1 }
333
+ }
334
+ ```
335
+
336
+ Writing to a file prints a readable summary instead of the JSON:
337
+
338
+ ```bash
339
+ $ maestro introspect --input packages/cli/examples/introspection.json --out ./maestro.introspection.json
340
+ Introspection written: ./maestro.introspection.json
341
+ Entities: 2
342
+ Relations: 1
343
+ ```
344
+
345
+ **Offline / local only — this is NOT a database connector (yet).** It does **not** connect to
346
+ PostgreSQL, MySQL, MongoDB or any database, does **not** read a connection string or `.env`, does **not**
347
+ load an ORM/driver, and does **not** execute any query. It operates only on the local JSON file passed
348
+ with `--input`, which is an intermediate/offline representation of an introspection — not a live schema
349
+ read. Connecting to real datasources (via `IntrospectionProvider` implementations) is a separate,
350
+ not-yet-implemented step; keeping the contract stable first is the point of this command.
351
+
352
+ The artifact is **canonical**: entities are sorted by `table`, relations by `id`, and every object key is
353
+ sorted. Field (column) order within an entity is preserved. It is **deterministic by design** — no
354
+ timestamp, absolute path or hash is ever included, so re-running it only changes the output when the input
355
+ actually changed.
356
+
357
+ **`introspect` vs. `snapshot` vs. `diff`.** All three are offline, read-only and never touch a database or
358
+ the engine, but they operate on different inputs:
359
+
360
+ - `introspect` validates/canonicalizes an **`IntrospectionResult`** (the real DB-schema contract), offline.
361
+ - `snapshot` canonicalizes a **declarative config file** (`maestro.config.yaml`/`.json`).
362
+ - `diff` compares **two declarative config files**.
363
+
364
+ The core's Introspection Runtime (`DiffEngine`, Snapshot Engine, `ReportGenerator`) also operates on
365
+ `IntrospectionResult`, but those paths assume a live/real introspection and carry volatile data (e.g.
366
+ `IntrospectionSnapshot`'s `id`/`timestamp`, the report's `completedAt`). `maestro introspect` intentionally
367
+ stays offline and reproducible, so it does not use them yet — see the
368
+ [spec](../../docs/specs/cli-introspect.md#apis-do-core-e-limitações) for the exact gap.
369
+
370
+ **What it does NOT do:** no `createMaestro()`, no database/provider connection, no `.env`/connection-string
371
+ read, no query execution, no operation execution, and no operation-binding requirement. It never modifies
372
+ the input file.
373
+
374
+ | Flag | Required | Description |
375
+ |---|---|---|
376
+ | `--input`, `-i <path>` | yes | Path to a local `IntrospectionResult` JSON file |
377
+ | `--out <path>` | no (default: stdout) | Writes the artifact to a file instead of printing it |
378
+
379
+ **Exit codes:** `0` = artifact produced; `1` = usage, read, parse, validation or write error. Errors print a
380
+ single readable line to stderr prefixed with `maestro introspect:`. Run `maestro introspect --help` for the
381
+ full reference, and see [`docs/specs/cli-introspect.md`](../../docs/specs/cli-introspect.md) for the
382
+ complete walkthrough.
383
+
384
+ ## Architectural rule: the CLI consumes, it doesn't implement
385
+
386
+ The CLI never re-implements a capability that already exists in `@maykonpaulo/maestro-core`. It
387
+ calls `generateDeclarativeConfigFromMetadata`/`generateDeclarativeConfigFromSchema` and
388
+ `serializeDeclarativeConfig` directly — there is no parallel generation or serialization logic in
389
+ this package. `maestro diff` reuses the core's `loadDeclarativeConfigFromString` for loading and
390
+ validation, adding only the small, local, deterministic structural comparison of two
391
+ `DeclarativeFileConfig` objects (the core's `DiffEngine` targets `IntrospectionResult`, not
392
+ declarative files). `maestro snapshot` likewise reuses `loadDeclarativeConfigFromString` for
393
+ load+validation and adds only a small, local, deterministic canonicalizer over the resulting
394
+ `DeclarativeFileConfig` (the core's Snapshot Engine, `IntrospectionSnapshot`/`SnapshotRepository`,
395
+ targets a runtime `IntrospectionResult` with volatile `id`/`timestamp` fields — incompatible with a
396
+ reproducible declarative snapshot). `maestro introspect` consumes the core's `IntrospectionResult` **type**
397
+ (the introspection contract) and adds only a small, local, deterministic validator + canonicalizer over it;
398
+ the core exposes no public `IntrospectionResult` validator yet, and its runtime introspection helpers
399
+ (`DiffEngine`, Snapshot Engine, `ReportGenerator`) all carry volatile fields, so an offline/reproducible
400
+ artifact can't reuse them here — see [`docs/specs/cli-introspect.md`](../../docs/specs/cli-introspect.md).
401
+
402
+ ## Command architecture
403
+
404
+ - `Command` — interface a command implements: `name`, `description`, optional `helpText` (shown for
405
+ `maestro <name> --help`; falls back to the global help when omitted), `run(context)`.
406
+ - `CommandRegistry` — a simple map of registered commands (`register`, `get`, `list`).
407
+ - `parseArgs` — minimal global parser: detects `--help`/`-h` and `--version`/`-v`, and the first
408
+ non-flag argument as the command name; everything else (including a command's own flags) passes
409
+ through untouched.
410
+ - `runCli` — orchestrates parsing → dispatch → exit code; when `--help` is combined with a known
411
+ command, prints that command's own `helpText` instead of the global help. Accepts an injectable
412
+ `stdout`/`stderr` and `CommandRegistry`, so it's fully testable without spawning a process.
413
+ - `createGenerateCommand` — builds the `generate` `Command`; accepts injectable `readFile`/`writeFile`
414
+ for testing without touching the real filesystem.
415
+ - `createValidateCommand` — builds the `validate` `Command`; accepts an injectable `readFile` for
416
+ testing without touching the real filesystem.
417
+ - `createDiffCommand` — builds the `diff` `Command`; accepts an injectable `readFile` for testing
418
+ without touching the real filesystem. The pure comparison lives in `diffDeclarativeConfigs`
419
+ (`diffDeclarativeConfigs` + `formatDeclarativeDiff`), tested in isolation from file I/O.
420
+ - `createSnapshotCommand` — builds the `snapshot` `Command`; accepts injectable `readFile`/`writeFile`
421
+ for testing without touching the real filesystem. The pure canonicalization lives in
422
+ `buildDeclarativeSnapshot` (`buildDeclarativeSnapshot` + `serializeSnapshot`), tested in isolation
423
+ from file I/O.
424
+ - `createIntrospectCommand` — builds the `introspect` `Command`; accepts injectable `readFile`/`writeFile`
425
+ for testing without touching the real filesystem. The pure validation/canonicalization lives in
426
+ `buildIntrospection` (`validateIntrospectionResult` + `buildIntrospectionArtifact` +
427
+ `serializeIntrospection`), tested in isolation from file I/O.
428
+
429
+ Adding a future command means implementing `Command` (with its own `helpText`) and calling
430
+ `defaultRegistry.register(...)` in `runCli.ts` — no change to `runCli`, `parseArgs`, or the
431
+ entrypoint is needed.
432
+
433
+ ## Development
434
+
435
+ ```bash
436
+ pnpm --filter @maykonpaulo/maestro-cli build
437
+ pnpm --filter @maykonpaulo/maestro-cli test
438
+ node packages/cli/dist/cli.js --help
439
+ node packages/cli/dist/cli.js generate --help
440
+ node packages/cli/dist/cli.js generate --input packages/cli/examples/metadata.json --type metadata
441
+ node packages/cli/dist/cli.js validate --help
442
+ node packages/cli/dist/cli.js validate --input packages/cli/examples/maestro.config.yaml
443
+ node packages/cli/dist/cli.js diff --help
444
+ node packages/cli/dist/cli.js diff --from packages/cli/examples/maestro.config.yaml --to packages/cli/examples/maestro.config.yaml
445
+ node packages/cli/dist/cli.js snapshot --help
446
+ node packages/cli/dist/cli.js snapshot --input packages/cli/examples/maestro.config.yaml
447
+ node packages/cli/dist/cli.js introspect --help
448
+ node packages/cli/dist/cli.js introspect --input packages/cli/examples/introspection.json
449
+ ```
450
+
451
+ See [`docs/cli.md`](../../docs/cli.md) for the consolidated CLI overview (recommended flow, command
452
+ table, limitations and next steps), [`docs/specs/cli-foundation.md`](../../docs/specs/cli-foundation.md)
453
+ for the CLI foundation architecture, [`docs/specs/cli-generate.md`](../../docs/specs/cli-generate.md) for the full
454
+ `maestro generate` walkthrough, [`docs/specs/cli-validate.md`](../../docs/specs/cli-validate.md) for
455
+ `maestro validate`, [`docs/specs/cli-diff.md`](../../docs/specs/cli-diff.md) for `maestro diff`,
456
+ [`docs/specs/cli-snapshot.md`](../../docs/specs/cli-snapshot.md) for `maestro snapshot`, and
457
+ [`docs/specs/cli-introspect.md`](../../docs/specs/cli-introspect.md) for `maestro introspect`.