@ontrails/commander 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/CHANGELOG.md ADDED
@@ -0,0 +1,355 @@
1
+ # @ontrails/commander
2
+
3
+ ## 0.2.0
4
+
5
+ ### Patch Changes
6
+
7
+ - [`664e8bb`](https://github.com/outfitter-dev/trails/commit/664e8bb049e61f1d47cec1dd246606707af5d1a8): Point public installation examples at exact approved 0.2.0 versions and distinguish the prepared source release from pending npm publication.
8
+ - [`b3ddf91`](https://github.com/outfitter-dev/trails/commit/b3ddf918ada8211f44983512e2bbdfbc5b66d722): Prepare the first normal Trails release at `0.2.0` on `latest`, replacing the unpublished 1.0.0 source release. The target advances the original `0.1.0` source minor, which was never published under the current package names. Public packages remain in lockstep. Update consumer installation guidance and provide a temporary manifest bridge for old 1.0 beta sources. Published beta versions remain unchanged; minor 0.x releases may carry documented breaking changes.
9
+
10
+ The `1.0.0` section retained below records an unpublished preparation, not an npm release. Its accumulated changes are included in `0.2.0`; the section remains as source history alongside the published beta entries.
11
+
12
+ ## 1.0.0
13
+
14
+ ### Minor Changes
15
+
16
+ - [`e991a5b`](https://github.com/outfitter-dev/trails/commit/e991a5b2e8b9057d8e33a067e29fb0aca641d5ad): Add generic enum value aliases for CLI flags and migrate Warden command aliases onto the shared alias model.
17
+ - [`25f3c5c`](https://github.com/outfitter-dev/trails/commit/25f3c5ca3e4e7d5ec105f06384111a2ec37c7b72): Add the dedicated `@ontrails/commander` adapter package and move the Commander runtime out of the `@ontrails/cli/commander` subpath. Extend the repo-local package-source guardrails to cover adapter package source as the Commander runtime moves under `adapters/`.
18
+
19
+ ### Patch Changes
20
+
21
+ - [`e41c382`](https://github.com/outfitter-dev/trails/commit/e41c3829c2d692683b78c730e67fd5b17ac0ff4e): Document beta-channel install guidance in package and adapter README install snippets so consumers use explicit `@beta` (or pinned `1.0.0-beta.N`) tags instead of accidental `latest` resolution during the prerelease line. Adds the policy doc at `docs/releases/beta-channel-policy.md`, prints both `latest` and `beta` dist-tags in `bun run publish:registry-check`, and aligns plugin/skill install snippets.
22
+ - [`ed5926b`](https://github.com/outfitter-dev/trails/commit/ed5926bddebed7be19a902d69be58f2d5e8b4c51): Add missing TSDoc for public adapter and sink boundary types.
23
+ - [`f42ca6e`](https://github.com/outfitter-dev/trails/commit/f42ca6e40b29155acec446e5bf44e52e014466bd): Hard cutover: the CLI consumes `cli` bindings from the app-authored surfaces overlay. Scalar bindings behave identically to the removed cliAliases (parity-tested) — the binding name splits on `.` into a transparent synonym command path for exactly one trail. List bindings arrive as command groups: each expanded member trail gets a group-prefixed route that dispatches the member trail with its identity preserved, and a singleton list stays a group. Expansion is fail-fast boundary validation: a scalar binding resolving to zero or multiple trails, or a group with an empty member union, is a `ValidationError` naming the binding. `DeriveTopoGraphOptions.cliAliases`, the `cliAliases`/`trailsCliAliases` app-module export convention, and the per-kind compile lift are deleted; `deriveCliCommands`/`createProgram` take `overlays` instead of `aliases`, and both topo-graph derivation pipelines expand the same bindings through one shared helper so runtime CLI routes and lock routes come from one semantic. A leftover legacy export is now a Warden error (`no-legacy-cli-alias-export`) naming the `surfaceOverlay({ cli: { ... } })` rewrite.
24
+
25
+ This is a breaking API removal shipped under the lockstep beta patch convention (pre-1.0 hard-cutover posture, zero external adoption); the removed options have no deprecation window by design.
26
+
27
+ - [`454e935`](https://github.com/outfitter-dev/trails/commit/454e935088782a181df89a205c0ff6f2eb936434): Define bounded multiselect argv normalization in the framework CLI model and apply it automatically in the Commander adapter, accepting both contiguous and repeated forms while preserving child routes after the first explicit value.
28
+ - [`60caabf`](https://github.com/outfitter-dev/trails/commit/60caabf5901c3366ce1585823a6f42675876b7ab): Render operator-actionable detail lines after CLI execution errors: validation failures list their topo issues (message plus trail id) and permission failures name the required permit scopes with a copyable `--permit` form. Non-internal Trails error context only, passed through the shared redactor; internal errors keep the redacted generic message.
29
+ - [`1eb5bdc`](https://github.com/outfitter-dev/trails/commit/1eb5bdc06142d8886f3870801b2ef71a0c5f3844): Rename first-class trail composition from the `cross` API family to the `compose` family across core contracts, testing helpers, topo projections, Warden rules, CLI scaffolds, and docs. `composes`, `ctx.compose`, `composeInput`, and `Compose*` type names are now the public authoring vocabulary; topo persistence migrates legacy composition rows and graph keys forward.
30
+ - [`20d7a5c`](https://github.com/outfitter-dev/trails/commit/20d7a5c8e675fd3ecd8c29441bbd8a99b5c64ed0): Enforce the shared safe error projection policy for public error bodies, diagnostics, serialized payloads, and CLI stderr.
31
+ - [`88a6a62`](https://github.com/outfitter-dev/trails/commit/88a6a62a9e9e230ca6d368fa78dc3ece6c816204): Complete the v1 classification-first cutover from projection/project vocabulary
32
+ to derive/derived for contract-owned fact production and render/rendered for
33
+ surface presentation. Public type, helper, rule, relation, and report names move
34
+ without compatibility aliases; ordinary repository/project nouns remain
35
+ explicit preserves or structured review inventory.
36
+ - [`dbf4ff4`](https://github.com/outfitter-dev/trails/commit/dbf4ff4a73255e65e55e734b6796b6fcf7f4a07a): Emit structured CLI error envelopes for JSON/JSONL command failures and map compile-time Trails DB lock contention to a retryable timeout instead of a generic internal error.
37
+ - [`f1e6efa`](https://github.com/outfitter-dev/trails/commit/f1e6efa4f383287f0b2196f48185699e7476b18c): Prevent executable parent command defaults from leaking into nested child commands.
38
+ - [`a8e4dc3`](https://github.com/outfitter-dev/trails/commit/a8e4dc35cbc88a419dafa9082b31c51ae735526b): Clean up the Wayfinder navigation grammar before RC, including explicit pattern/query/file selectors, target-bound dependency and impact flags, drift-first provenance fields, stricter fires declaration diagnostics, and updated operator dogfood coverage.
39
+ - [`945cb4b`](https://github.com/outfitter-dev/trails/commit/945cb4b0bef40ddb098c2a3816f9adad6f135410): Honor explicit structured input values over CLI flag defaults when commands merge
40
+ `--input-json` or `--input` payloads.
41
+
42
+ Commander now forwards user-supplied flag metadata so explicit flag values that
43
+ match a default still keep normal CLI precedence over structured input.
44
+
45
+ - [`b1fbe57`](https://github.com/outfitter-dev/trails/commit/b1fbe574e6f44d1fecb5e3a000270955c0a77b7b): Publish Bun-validated package tarballs through an npm trusted-publishing adapter
46
+ binding, add exact repository metadata for each public workspace package, and
47
+ correct the native Bun release descriptor to its pack-only runtime boundary.
48
+ - [`f9533a4`](https://github.com/outfitter-dev/trails/commit/f9533a4ef7392201c71d7f751361b4f7177eeacb): Keep public error projection shared and redacted while using transport-neutral CLI vocabulary and preserving safe topo diagnostics in structured output.
49
+ - [`4030698`](https://github.com/outfitter-dev/trails/commit/40306984467625844564f0f84156530d7118a79c): Keep structured input on nested child commands from being reinterpreted as a
50
+ bare child-name positional fallback, while preserving schema-authored
51
+ `inputJson` flags as ordinary trail input, including through the public Trails
52
+ CLI. Optional numeric flags now consume negative values with Commander's own
53
+ parsing semantics, and variadic flags consume every following value, before
54
+ nested command routing is resolved.
55
+ - [`1d3ae74`](https://github.com/outfitter-dev/trails/commit/1d3ae743c5f4ab64e6ae7bff4a98f64a6427ae84): Materialize resolved CLI command aliases through the Commander surface while
56
+ preserving the same trail contract and execution path.
57
+ - [`df9a7d0`](https://github.com/outfitter-dev/trails/commit/df9a7d00fe4d9ebec948b6ebed6dc4525fc8e0dc): Add project-aware public export-map governance for @ontrails workspace docs,
58
+ imports, root barrels, and bin-only package surfaces.
59
+ - [`61497c5`](https://github.com/outfitter-dev/trails/commit/61497c54deaaae2d067af88d0be6db0a5acb5faf): Add v1-minimum public API examples for shipped surface entrypoints.
60
+
61
+ ## 1.0.0-beta.50
62
+
63
+ ## 1.0.0-beta.49
64
+
65
+ ## 1.0.0-beta.48
66
+
67
+ ## 1.0.0-beta.47
68
+
69
+ ## 1.0.0-beta.46
70
+
71
+ ## 1.0.0-beta.45
72
+
73
+ ### Patch Changes
74
+
75
+ - [`f9533a4`](https://github.com/outfitter-dev/trails/commit/f9533a4ef7392201c71d7f751361b4f7177eeacb): Keep public error projection shared and redacted while using transport-neutral CLI vocabulary and preserving safe topo diagnostics in structured output.
76
+
77
+ ## 1.0.0-beta.44
78
+
79
+ ### Patch Changes
80
+
81
+ - [`b1fbe57`](https://github.com/outfitter-dev/trails/commit/b1fbe574e6f44d1fecb5e3a000270955c0a77b7b): Publish Bun-validated package tarballs through an npm trusted-publishing adapter
82
+ binding, add exact repository metadata for each public workspace package, and
83
+ correct the native Bun release descriptor to its pack-only runtime boundary.
84
+
85
+ ## 1.0.0-beta.43
86
+
87
+ ### Patch Changes
88
+
89
+ - [`88a6a62`](https://github.com/outfitter-dev/trails/commit/88a6a62a9e9e230ca6d368fa78dc3ece6c816204): Complete the v1 classification-first cutover from projection/project vocabulary
90
+ to derive/derived for contract-owned fact production and render/rendered for
91
+ surface presentation. Public type, helper, rule, relation, and report names move
92
+ without compatibility aliases; ordinary repository/project nouns remain
93
+ explicit preserves or structured review inventory.
94
+
95
+ ## 1.0.0-beta.42
96
+
97
+ ### Patch Changes
98
+
99
+ - [`454e935`](https://github.com/outfitter-dev/trails/commit/454e935088782a181df89a205c0ff6f2eb936434): Define bounded multiselect argv normalization in the framework CLI model and apply it automatically in the Commander adapter, accepting both contiguous and repeated forms while preserving child routes after the first explicit value.
100
+
101
+ ## 1.0.0-beta.41
102
+
103
+ ## 1.0.0-beta.40
104
+
105
+ ### Patch Changes
106
+
107
+ - [`4030698`](https://github.com/outfitter-dev/trails/commit/40306984467625844564f0f84156530d7118a79c): Keep structured input on nested child commands from being reinterpreted as a
108
+ bare child-name positional fallback, while preserving schema-authored
109
+ `inputJson` flags as ordinary trail input, including through the public Trails
110
+ CLI. Optional numeric flags now consume negative values with Commander's own
111
+ parsing semantics, and variadic flags consume every following value, before
112
+ nested command routing is resolved.
113
+
114
+ ## 1.0.0-beta.39
115
+
116
+ ### Patch Changes
117
+
118
+ - [`f42ca6e`](https://github.com/outfitter-dev/trails/commit/f42ca6e40b29155acec446e5bf44e52e014466bd): Hard cutover: the CLI consumes `cli` bindings from the app-authored surfaces overlay. Scalar bindings behave identically to the removed cliAliases (parity-tested) — the binding name splits on `.` into a transparent synonym command path for exactly one trail. List bindings arrive as command groups: each expanded member trail gets a group-prefixed route that dispatches the member trail with its identity preserved, and a singleton list stays a group. Expansion is fail-fast boundary validation: a scalar binding resolving to zero or multiple trails, or a group with an empty member union, is a `ValidationError` naming the binding. `DeriveTopoGraphOptions.cliAliases`, the `cliAliases`/`trailsCliAliases` app-module export convention, and the per-kind compile lift are deleted; `deriveCliCommands`/`createProgram` take `overlays` instead of `aliases`, and both topo-graph derivation pipelines expand the same bindings through one shared helper so runtime CLI routes and lock routes come from one semantic. A leftover legacy export is now a Warden error (`no-legacy-cli-alias-export`) naming the `surfaceOverlay({ cli: { ... } })` rewrite.
119
+
120
+ This is a breaking API removal shipped under the lockstep beta patch convention (pre-1.0 hard-cutover posture, zero external adoption); the removed options have no deprecation window by design.
121
+
122
+ ## 1.0.0-beta.38
123
+
124
+ ## 1.0.0-beta.37
125
+
126
+ ## 1.0.0-beta.36
127
+
128
+ ## 1.0.0-beta.35
129
+
130
+ ## 1.0.0-beta.34
131
+
132
+ ## 1.0.0-beta.33
133
+
134
+ ### Patch Changes
135
+
136
+ - [`945cb4b`](https://github.com/outfitter-dev/trails/commit/945cb4b0bef40ddb098c2a3816f9adad6f135410): Honor explicit structured input values over CLI flag defaults when commands merge
137
+ `--input-json` or `--input` payloads.
138
+
139
+ Commander now forwards user-supplied flag metadata so explicit flag values that
140
+ match a default still keep normal CLI precedence over structured input.
141
+
142
+ ## 1.0.0-beta.32
143
+
144
+ ### Patch Changes
145
+
146
+ - Updated dependencies [3e5c0fc]
147
+ - Updated dependencies [f3c4fef]
148
+ - Updated dependencies [cb0a9d8]
149
+ - Updated dependencies [21c6dda]
150
+ - Updated dependencies [860ef32]
151
+ - Updated dependencies [fe72b84]
152
+ - @ontrails/core@1.0.0-beta.32
153
+ - @ontrails/cli@1.0.0-beta.32
154
+
155
+ ## 1.0.0-beta.31
156
+
157
+ ### Patch Changes
158
+
159
+ - Updated dependencies [4cd5d4e]
160
+ - Updated dependencies [38907cc]
161
+ - @ontrails/core@1.0.0-beta.31
162
+ - @ontrails/cli@1.0.0-beta.31
163
+
164
+ ## 1.0.0-beta.30
165
+
166
+ ### Patch Changes
167
+
168
+ - @ontrails/cli@1.0.0-beta.30
169
+ - @ontrails/core@1.0.0-beta.30
170
+
171
+ ## 1.0.0-beta.29
172
+
173
+ ### Patch Changes
174
+
175
+ - @ontrails/cli@1.0.0-beta.29
176
+ - @ontrails/core@1.0.0-beta.29
177
+
178
+ ## 1.0.0-beta.28
179
+
180
+ ### Patch Changes
181
+
182
+ - @ontrails/cli@1.0.0-beta.28
183
+ - @ontrails/core@1.0.0-beta.28
184
+
185
+ ## 1.0.0-beta.27
186
+
187
+ ### Patch Changes
188
+
189
+ - @ontrails/cli@1.0.0-beta.27
190
+ - @ontrails/core@1.0.0-beta.27
191
+
192
+ ## 1.0.0-beta.26
193
+
194
+ ### Patch Changes
195
+
196
+ - Updated dependencies [1307568]
197
+ - Updated dependencies [371d19e]
198
+ - @ontrails/core@1.0.0-beta.26
199
+ - @ontrails/cli@1.0.0-beta.26
200
+
201
+ ## 1.0.0-beta.25
202
+
203
+ ### Patch Changes
204
+
205
+ - 60caabf: Render operator-actionable detail lines after CLI execution errors: validation failures list their topo issues (message plus trail id) and permission failures name the required permit scopes with a copyable `--permit` form. Non-internal Trails error context only, passed through the shared redactor; internal errors keep the redacted generic message.
206
+ - dbf4ff4: Emit structured CLI error envelopes for JSON/JSONL command failures and map compile-time Trails DB lock contention to a retryable timeout instead of a generic internal error.
207
+ - f1e6efa: Prevent executable parent command defaults from leaking into nested child commands.
208
+ - a8e4dc3: Clean up the Wayfinder navigation grammar before RC, including explicit pattern/query/file selectors, target-bound dependency and impact flags, drift-first provenance fields, stricter fires declaration diagnostics, and updated operator dogfood coverage.
209
+ - 1d3ae74: Materialize resolved CLI command aliases through the Commander surface while
210
+ preserving the same trail contract and execution path.
211
+ - Updated dependencies [c36aca9]
212
+ - Updated dependencies [3befcf1]
213
+ - Updated dependencies [f1e6efa]
214
+ - Updated dependencies [a4f9cf6]
215
+ - Updated dependencies [9bcf34e]
216
+ - Updated dependencies [f7d97fc]
217
+ - @ontrails/core@1.0.0-beta.25
218
+ - @ontrails/cli@1.0.0-beta.25
219
+
220
+ ## 1.0.0-beta.24
221
+
222
+ ### Patch Changes
223
+
224
+ - @ontrails/cli@1.0.0-beta.24
225
+ - @ontrails/core@1.0.0-beta.24
226
+
227
+ ## 1.0.0-beta.23
228
+
229
+ ### Patch Changes
230
+
231
+ - @ontrails/cli@1.0.0-beta.23
232
+ - @ontrails/core@1.0.0-beta.23
233
+
234
+ ## 1.0.0-beta.22
235
+
236
+ ### Patch Changes
237
+
238
+ - @ontrails/cli@1.0.0-beta.22
239
+ - @ontrails/core@1.0.0-beta.22
240
+
241
+ ## 1.0.0-beta.21
242
+
243
+ ### Patch Changes
244
+
245
+ - Updated dependencies [99523f2]
246
+ - @ontrails/core@1.0.0-beta.21
247
+ - @ontrails/cli@1.0.0-beta.21
248
+
249
+ ## 1.0.0-beta.20
250
+
251
+ ### Patch Changes
252
+
253
+ - Updated dependencies [851a2a3]
254
+ - @ontrails/core@1.0.0-beta.20
255
+ - @ontrails/cli@1.0.0-beta.20
256
+
257
+ ## 1.0.0-beta.19
258
+
259
+ ### Patch Changes
260
+
261
+ - e41c382: Document beta-channel install guidance in package and adapter README install snippets so consumers use explicit `@beta` (or pinned `1.0.0-beta.N`) tags instead of accidental `latest` resolution during the prerelease line. Adds the policy doc at `docs/releases/beta-channel-policy.md`, prints both `latest` and `beta` dist-tags in `bun run publish:registry-check`, and aligns plugin/skill install snippets.
262
+ - ed5926b: Add missing TSDoc for public adapter and sink boundary types.
263
+ - 1eb5bdc: Rename first-class trail composition from the `cross` API family to the `compose` family across core contracts, testing helpers, topo projections, Warden rules, CLI scaffolds, and docs. `composes`, `ctx.compose`, `composeInput`, and `Compose*` type names are now the public authoring vocabulary; topo persistence migrates legacy composition rows and graph keys forward.
264
+ - Updated dependencies [e41c382]
265
+ - Updated dependencies [a2f1825]
266
+ - Updated dependencies [a2f1825]
267
+ - Updated dependencies [1eb5bdc]
268
+ - Updated dependencies [f8d80b9]
269
+ - Updated dependencies [846a597]
270
+ - Updated dependencies [223aaad]
271
+ - Updated dependencies [3125f4d]
272
+ - Updated dependencies [2494dc6]
273
+ - Updated dependencies [2d53717]
274
+ - Updated dependencies [16cb740]
275
+ - Updated dependencies [8894ecb]
276
+ - Updated dependencies [fdf7ec9]
277
+ - Updated dependencies [92e709b]
278
+ - Updated dependencies [d76be13]
279
+ - Updated dependencies [84f56a5]
280
+ - Updated dependencies [431b04c]
281
+ - Updated dependencies [5d88104]
282
+ - Updated dependencies [f04a9ef]
283
+ - @ontrails/core@1.0.0-beta.19
284
+ - @ontrails/cli@1.0.0-beta.19
285
+
286
+ ## 1.0.0-beta.18
287
+
288
+ ### Patch Changes
289
+
290
+ - @ontrails/cli@1.0.0-beta.18
291
+ - @ontrails/core@1.0.0-beta.18
292
+
293
+ ## 1.0.0-beta.17
294
+
295
+ ### Patch Changes
296
+
297
+ - 61497c5: Add v1-minimum public API examples for shipped surface entrypoints.
298
+ - Updated dependencies [3dc8254]
299
+ - Updated dependencies [61497c5]
300
+ - @ontrails/core@1.0.0-beta.17
301
+ - @ontrails/cli@1.0.0-beta.17
302
+
303
+ ## 1.0.0-beta.16
304
+
305
+ ### Minor Changes
306
+
307
+ - e991a5b: Add generic enum value aliases for CLI flags and migrate Warden command aliases onto the shared alias model.
308
+ - 25f3c5c: Add the dedicated `@ontrails/commander` adapter package and move the Commander runtime out of the `@ontrails/cli/commander` subpath. Extend the repo-local package-source guardrails to cover adapter package source as the Commander runtime moves under `adapters/`.
309
+
310
+ ### Patch Changes
311
+
312
+ - 20d7a5c: Enforce the shared safe error projection policy for public error bodies, diagnostics, serialized payloads, and CLI stderr.
313
+ - df9a7d0: Add project-aware public export-map governance for @ontrails workspace docs,
314
+ imports, root barrels, and bin-only package surfaces.
315
+ - Updated dependencies [73622ae]
316
+ - Updated dependencies [e991a5b]
317
+ - Updated dependencies [25f3c5c]
318
+ - Updated dependencies [6300f70]
319
+ - Updated dependencies [d172013]
320
+ - Updated dependencies [c3fc5c3]
321
+ - Updated dependencies [20d7a5c]
322
+ - Updated dependencies [be5fb46]
323
+ - Updated dependencies [e898cc4]
324
+ - Updated dependencies [3395234]
325
+ - Updated dependencies [bcdc484]
326
+ - Updated dependencies [ed171d5]
327
+ - Updated dependencies [49c2e7d]
328
+ - Updated dependencies [331e3a9]
329
+ - Updated dependencies [4399fdb]
330
+ - Updated dependencies [4b8d13b]
331
+ - Updated dependencies [fbd42fc]
332
+ - Updated dependencies [63d1aef]
333
+ - Updated dependencies [112b9f2]
334
+ - Updated dependencies [893025e]
335
+ - Updated dependencies [ed888e2]
336
+ - Updated dependencies [2e05e27]
337
+ - Updated dependencies [c8caa5e]
338
+ - Updated dependencies [f4b90c9]
339
+ - Updated dependencies [eec5e9d]
340
+ - Updated dependencies [4e75129]
341
+ - Updated dependencies [47505fe]
342
+ - Updated dependencies [ebd4434]
343
+ - Updated dependencies [863d473]
344
+ - Updated dependencies [344f2f7]
345
+ - Updated dependencies [26f9ffd]
346
+ - Updated dependencies [66056ac]
347
+ - Updated dependencies [0bad534]
348
+ - Updated dependencies [10eae9a]
349
+ - Updated dependencies [22c6c06]
350
+ - @ontrails/core@1.0.0-beta.16
351
+ - @ontrails/cli@1.0.0-beta.16
352
+
353
+ ## 1.0.0-beta.15
354
+
355
+ Initial package placeholder.
package/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # @ontrails/commander
2
+
3
+ Commander adapter for Trails. Use this package when you want to expose a topo as a Commander-powered command-line program while keeping `@ontrails/cli` focused on framework-agnostic command derivation.
4
+
5
+ ## Usage
6
+
7
+ ```typescript
8
+ import { surface } from '@ontrails/commander';
9
+ import { graph } from './app';
10
+
11
+ await surface(graph);
12
+ ```
13
+
14
+ For program construction without parsing argv:
15
+
16
+ ```typescript
17
+ import { createProgram } from '@ontrails/commander';
18
+ import { graph } from './app';
19
+
20
+ const program = createProgram(graph, { name: 'myapp' });
21
+ ```
22
+
23
+ For lower-level adapter wiring, derive the command model with `@ontrails/cli` and materialize it with `toCommander()`:
24
+
25
+ ```typescript
26
+ import { deriveCliCommands } from '@ontrails/cli';
27
+ import { toCommander } from '@ontrails/commander';
28
+ import { graph } from './app';
29
+
30
+ const commands = deriveCliCommands(graph);
31
+ if (commands.isErr()) {
32
+ throw commands.error;
33
+ }
34
+
35
+ const program = toCommander(commands.value, { name: 'myapp' });
36
+ ```
37
+
38
+ ## Multiselect flags
39
+
40
+ Schema fields such as `z.array(z.enum(['cli', 'mcp', 'http']))` derive a bounded multiselect flag. The shared CLI argv normalizer lets adapters accept both contiguous and repeated forms; Commander applies it automatically:
41
+
42
+ ```bash
43
+ myapp create --surfaces cli mcp http
44
+ myapp create --surfaces cli --surfaces mcp --surfaces http
45
+ ```
46
+
47
+ The first matching token after the flag is its explicit value. After that first value, additional collection stops before known child routes or values outside the declared choices. Adopters do not need custom parsing or surface configuration for either form.
48
+
49
+ ## Installation
50
+
51
+ These commands target stable `0.2.0`. Run them after that version is published to npm.
52
+
53
+ ```bash
54
+ bun add --exact @ontrails/cli@0.2.0 @ontrails/commander@0.2.0
55
+ ```
56
+
57
+ ## Migration
58
+
59
+ <!-- warden-ignore-next-line -->
60
+ This package replaces the old `@ontrails/cli/commander` subpath.
61
+
62
+ <!-- warden-ignore-next-line -->
63
+ - Before: `import { surface } from '@ontrails/cli/commander'`
64
+ - After: `import { surface } from '@ontrails/commander'`
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@ontrails/commander",
3
+ "version": "0.2.0",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/outfitter-dev/trails.git",
7
+ "directory": "adapters/commander"
8
+ },
9
+ "files": [
10
+ "src/**/*.ts",
11
+ "!src/**/__tests__/**",
12
+ "!src/**/*.test.ts",
13
+ "!src/**/*.test-d.ts",
14
+ "README.md",
15
+ "CHANGELOG.md"
16
+ ],
17
+ "type": "module",
18
+ "exports": {
19
+ ".": "./src/index.ts",
20
+ "./package.json": "./package.json"
21
+ },
22
+ "scripts": {
23
+ "build": "tsc -b",
24
+ "test": "bun test",
25
+ "typecheck": "tsc --noEmit",
26
+ "lint": "oxlint ./src",
27
+ "clean": "rm -rf dist *.tsbuildinfo"
28
+ },
29
+ "dependencies": {
30
+ "@ontrails/cli": "^0.2.0",
31
+ "@ontrails/core": "^0.2.0",
32
+ "commander": "^14.0.3"
33
+ },
34
+ "peerDependencies": {
35
+ "zod": "^4.3.5"
36
+ }
37
+ }
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export { toCommander } from './to-commander.js';
2
+ export type { ToCommanderOptions } from './to-commander.js';
3
+
4
+ export { createProgram, surface } from './surface.js';
5
+ export type { CreateProgramOptions, SurfaceCliResult } from './surface.js';
@@ -0,0 +1,182 @@
1
+ import { Command } from 'commander';
2
+ import type { ParseOptions, Option } from 'commander';
3
+ import { normalizeCliArgv } from '@ontrails/cli';
4
+ import type { CliCommand } from '@ontrails/cli';
5
+
6
+ type EffectiveParseOptions = Omit<ParseOptions, 'from'> & {
7
+ readonly from?: ParseOptions['from'] | 'eval' | undefined;
8
+ };
9
+
10
+ export const visibleOptionsFor = (command: Command): readonly Option[] => {
11
+ const commands: Command[] = [];
12
+ let current: Command | null = command;
13
+ while (current !== null) {
14
+ commands.push(current);
15
+ current = current.parent;
16
+ }
17
+ return commands.toReversed().flatMap((owner) => owner.options);
18
+ };
19
+
20
+ export interface InvocationOptionMatch {
21
+ readonly inlineValue: boolean;
22
+ readonly option: Option;
23
+ }
24
+
25
+ const findShortOption = (
26
+ options: readonly Option[],
27
+ short: string
28
+ ): Option | undefined => options.find((candidate) => candidate.short === short);
29
+
30
+ export const invocationOptionMatches = (
31
+ options: readonly Option[],
32
+ token: string
33
+ ): readonly InvocationOptionMatch[] => {
34
+ const exact = options.filter(
35
+ (option) => token === option.long || token === option.short
36
+ );
37
+ if (exact.length > 0) {
38
+ return exact.map((option) => ({ inlineValue: false, option }));
39
+ }
40
+
41
+ const longWithValue = options.filter(
42
+ (option) =>
43
+ option.long !== undefined &&
44
+ (option.required || option.optional) &&
45
+ token.startsWith(`${option.long}=`)
46
+ );
47
+ if (longWithValue.length > 0) {
48
+ return longWithValue.map((option) => ({ inlineValue: true, option }));
49
+ }
50
+
51
+ if (token.length <= 2 || token[0] !== '-' || token[1] === '-') {
52
+ return [];
53
+ }
54
+
55
+ const matches: InvocationOptionMatch[] = [];
56
+ let group = token.slice(1);
57
+ while (group.length > 0) {
58
+ const option = findShortOption(options, `-${group[0]}`);
59
+ if (option === undefined) {
60
+ break;
61
+ }
62
+ const inlineValue =
63
+ (option.required || option.optional) && group.length > 1;
64
+ matches.push({ inlineValue, option });
65
+ if (option.required || option.optional) {
66
+ break;
67
+ }
68
+ group = group.slice(1);
69
+ }
70
+ return matches;
71
+ };
72
+
73
+ export const isNegativeNumberArg = (
74
+ command: Command,
75
+ token: string
76
+ ): boolean => {
77
+ if (!/^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/.test(token)) {
78
+ return false;
79
+ }
80
+
81
+ for (
82
+ let current: Command | null = command;
83
+ current !== null;
84
+ current = current.parent
85
+ ) {
86
+ if (current.options.some((option) => /^-\d$/.test(option.short ?? ''))) {
87
+ return false;
88
+ }
89
+ }
90
+
91
+ return true;
92
+ };
93
+
94
+ export const optionConsumesFollowingValue = (
95
+ command: Command,
96
+ match: InvocationOptionMatch,
97
+ nextToken: string | undefined
98
+ ): boolean =>
99
+ !match.inlineValue &&
100
+ (match.option.required ||
101
+ (match.option.optional &&
102
+ nextToken !== undefined &&
103
+ (!nextToken.startsWith('-') || isNegativeNumberArg(command, nextToken))));
104
+
105
+ const argvUserStart = (
106
+ parseOptions?: EffectiveParseOptions | undefined
107
+ ): number => {
108
+ if (parseOptions?.from === 'user') {
109
+ return 0;
110
+ }
111
+ if (parseOptions?.from === 'eval') {
112
+ return 1;
113
+ }
114
+ if (parseOptions?.from === 'electron') {
115
+ const electronProcess = process as NodeJS.Process & {
116
+ readonly defaultApp?: boolean | undefined;
117
+ };
118
+ return electronProcess.defaultApp ? 2 : 1;
119
+ }
120
+ return 2;
121
+ };
122
+
123
+ const effectiveParseOptions = (
124
+ argv: readonly string[] | undefined,
125
+ parseOptions: ParseOptions | undefined
126
+ ): EffectiveParseOptions | undefined => {
127
+ if (
128
+ argv === undefined &&
129
+ parseOptions?.from === undefined &&
130
+ process.execArgv.some((arg) =>
131
+ ['-e', '--eval', '-p', '--print'].includes(arg)
132
+ )
133
+ ) {
134
+ // Commander supports this origin internally but does not publish it in
135
+ // ParseOptions. Preserve its one-token offset while normalizing argv.
136
+ return { from: 'eval' };
137
+ }
138
+ if (
139
+ argv === undefined &&
140
+ parseOptions?.from === undefined &&
141
+ process.versions['electron'] !== undefined
142
+ ) {
143
+ return { from: 'electron' };
144
+ }
145
+ return parseOptions;
146
+ };
147
+
148
+ export class TrailsCommanderProgram extends Command {
149
+ readonly #commands: readonly CliCommand[];
150
+
151
+ constructor(commands: readonly CliCommand[]) {
152
+ super();
153
+ this.#commands = commands;
154
+ }
155
+
156
+ #normalizeArgv(
157
+ argv: readonly string[] | undefined,
158
+ parseOptions: EffectiveParseOptions | undefined
159
+ ): readonly string[] {
160
+ const input = argv ?? process.argv;
161
+ const start = argvUserStart(parseOptions);
162
+ return [
163
+ ...input.slice(0, start),
164
+ ...normalizeCliArgv(this.#commands, input.slice(start)),
165
+ ];
166
+ }
167
+
168
+ override parse(argv?: readonly string[], parseOptions?: ParseOptions): this {
169
+ const options = effectiveParseOptions(argv, parseOptions);
170
+ const normalized = this.#normalizeArgv(argv, options);
171
+ return super.parse(normalized, options as ParseOptions | undefined);
172
+ }
173
+
174
+ override parseAsync(
175
+ argv?: readonly string[],
176
+ parseOptions?: ParseOptions
177
+ ): Promise<this> {
178
+ const options = effectiveParseOptions(argv, parseOptions);
179
+ const normalized = this.#normalizeArgv(argv, options);
180
+ return super.parseAsync(normalized, options as ParseOptions | undefined);
181
+ }
182
+ }