@crustjs/core 0.3.1 → 0.3.3

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,2059 @@
1
+ import { BaseValueType } from "@crustjs/utils/primitive";
2
+ import { InferOutput, StandardSchema } from "@crustjs/utils/schema";
3
+ import { JsonCompatible, JsonValue } from "@crustjs/utils/json";
4
+ //#region src/identity.d.ts
5
+ declare const brand: unique symbol;
6
+ /** Stable identity shared by Extensions and documentation section renderers. */
7
+ type ExtensionId = string & {
8
+ readonly [brand]: true;
9
+ };
10
+ /** Mint an Extension identity from any non-blank, trimmed string. */
11
+ declare function defineExtensionId(id: string): ExtensionId;
12
+ //#endregion
13
+ //#region src/validation/shared.d.ts
14
+ type Awaitable<T> = T | Promise<T>;
15
+ type Simplify<T> = { [K in keyof T]: T[K]; };
16
+ type MergeContext<A, B> = A & B;
17
+ /** Provider replacement is last-write-wins; an open name may leave any earlier value in place. */
18
+ type MergeProviders<A, B> = keyof A extends never ? B : keyof B extends never ? A : string extends keyof B ? Record<string, A[keyof A] | B[string]> : [keyof A & keyof B] extends [never] ? A & B : Omit<A, keyof B> & B;
19
+ /**
20
+ * Extract the narrowed canonical `name` literal from a definition.
21
+ * Open name domains carry no spelling proof; attachment must retain
22
+ * their uncertainty rather than treating this absence as an empty namespace.
23
+ */
24
+ type DefName<T> = T extends {
25
+ name: infer N extends string;
26
+ } ? IsClosedName<N> extends true ? N : never : never;
27
+ /**
28
+ * Statically known `name` members of a definition (or definition union), for spelling grammar.
29
+ * Filtered per variant: combining names first would let an open variant's `string` absorb
30
+ * a literal sibling before {@link ClosedMembers} can see it.
31
+ */
32
+ type DefNameMembers<T> = T extends {
33
+ name: infer N extends string;
34
+ } ? ClosedMembers<N> : never;
35
+ type UnionToIntersection<U> = (U extends unknown ? (x: U) => void : never) extends ((x: infer I) => void) ? I : never;
36
+ type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true;
37
+ /**
38
+ * `true` only for a single statically known fixed-length tuple whose members
39
+ * are not unions. A conditionally assembled collection (`cond ? [a] : [b]` or
40
+ * `[cond ? a : b]`) infers as a union at the tuple or member level, and a
41
+ * variable-length array (`const xs: (typeof a)[]`) may be empty or partially
42
+ * populated at runtime; such contributions must stay runtime-only.
43
+ */
44
+ type IsStaticTuple<Cs extends readonly unknown[]> = number extends Cs["length"] ? false : IsUnion<Cs> extends true ? false : true extends { [I in keyof Cs]: IsUnion<Cs[I]>; }[number] ? false : true;
45
+ /** Whether a fixed tuple has one closed canonical name per slot. */
46
+ type HasClosedNames<Ds extends readonly unknown[]> = number extends Ds["length"] ? false : IsUnion<Ds> extends true ? false : false extends { [I in keyof Ds]: Ds[I] extends {
47
+ name: infer N extends string;
48
+ } ? IsUnion<N> extends true ? false : IsClosedName<N> : false; }[number] ? false : true;
49
+ /** Brand statically known spelling collisions while allowing open names. */
50
+ type CollisionBrand<S extends string, Existing extends string, Key extends string, Before extends string, After extends string> = string extends S | Existing ? {} : [S & Existing] extends [never] ? {} : { readonly [K in Key]: `${Before}"${S & Existing}"${After}`; };
51
+ /**
52
+ * The statically known members of a name union; open members stay runtime-owned.
53
+ * Only for local spelling grammar: a literal beside an open template is still
54
+ * independently invalid, but must never become key or collision evidence.
55
+ */
56
+ type ClosedMembers<N extends string> = N extends unknown ? IsClosedName<N> extends true ? N : never : never;
57
+ /** Brand a statically known empty literal member while allowing widened and generic names. */
58
+ type EmptyLiteralNameBrand<Name extends string, Err> = "" extends ClosedMembers<Name> ? Err : {};
59
+ /**
60
+ * Brand a definition whose custom parser can return a Promise — parse results
61
+ * are consumed synchronously during argv parsing. `Extract` keeps the check
62
+ * union-aware (a sometimes-async `cond ? Promise.resolve(x) : x` parser is
63
+ * caught) while `any`-returning parsers stay unbranded.
64
+ */
65
+ type AsyncParseBrand<T> = T extends {
66
+ parse?: (...args: never[]) => infer R;
67
+ } ? Extract<R, Promise<unknown>> extends never ? {} : {
68
+ readonly FIX_ASYNC_PARSE: "parse must be synchronous; do async work in run()";
69
+ } : {};
70
+ /** Brand literal defaults that fall outside a literal `choices` tuple. */
71
+ type DefaultWithinChoicesBrand<T> = T extends {
72
+ choices: readonly (infer Choice extends string)[];
73
+ default: infer Default;
74
+ } ? string extends Choice ? {} : Default extends readonly string[] ? string extends Default[number] ? {} : Exclude<Default[number], Choice> extends never ? {} : {
75
+ readonly FIX_DEFAULT_CHOICE: "default must be one of choices";
76
+ } : Default extends string ? string extends Default ? {} : Exclude<Default, Choice> extends never ? {} : {
77
+ readonly FIX_DEFAULT_CHOICE: "default must be one of choices";
78
+ } : {} : {};
79
+ /** Finite literal domains have required record keys; infinite templates and branded strings do not.
80
+ * Distribute first so a finite union member cannot hide an open member's index signature.
81
+ */
82
+ type IsClosedName<N extends string> = false extends (N extends unknown ? ({} extends Record<N, true> ? false : true) : never) ? false : true;
83
+ /** Reject independently provable invalid local values, including members of uncertain definitions. */
84
+ type LocalValueBrand<T> = UnionToIntersection<T extends unknown ? AsyncParseBrand<T> & DefaultWithinChoicesBrand<T> : never>;
85
+ //#endregion
86
+ //#region src/validation/args.brands.d.ts
87
+ type ArgNames<A extends readonly object[]> = DefName<A[number]>;
88
+ type DuplicateArgBrand<A, Existing extends string> = CollisionBrand<DefName<A>, Existing, "FIX_DUPLICATE_ARG", "Argument name ", " is already defined">;
89
+ type EmptyArgNameError = {
90
+ readonly FIX_EMPTY_NAME: "Argument names must be non-empty";
91
+ };
92
+ /** Reject empty argument names, including empty members of a name union. */
93
+ type EmptyArgNameBrand<Name extends string> = EmptyLiteralNameBrand<Name, EmptyArgNameError>;
94
+ type EmptyArgDefinitionNameBrand<A> = EmptyArgNameBrand<DefNameMembers<A>>;
95
+ type ArgChecks<A, Existing extends string> = A & DuplicateArgBrand<A, Existing> & LocalValueBrand<A> & EmptyArgDefinitionNameBrand<A>;
96
+ /**
97
+ * Per-arg validation tuple type. Resolves to `A` when the constraints are
98
+ * satisfied: only the last arg is variadic, names are unique, and custom
99
+ * parsers are synchronous. Invalid definitions receive a branded property.
100
+ *
101
+ * Generalized to work with any ordered tuple of object-typed definitions.
102
+ * Uses `readonly object[]` to avoid TypeScript's weak type detection
103
+ * (all-optional constraint rejection).
104
+ *
105
+ * ```
106
+ * Property 'FIX_VARIADIC_POSITION' is missing in type '{ name: "files"; ... variadic: true }'
107
+ * but required in type
108
+ * '{ readonly FIX_VARIADIC_POSITION: "Only the last positional argument can be variadic" }'.
109
+ * ```
110
+ */
111
+ type ValidateVariadicArgs<A extends readonly object[], Existing extends string = never> = A extends readonly [infer Head, ...infer Tail extends readonly object[]] ? Tail extends readonly [unknown, ...unknown[]] ? Head extends {
112
+ variadic: true;
113
+ } ? readonly [ArgChecks<Head, Existing> & {
114
+ readonly FIX_VARIADIC_POSITION: "Only the last positional argument can be variadic";
115
+ }, ...ValidateVariadicArgs<Tail, Existing | DefName<Head>>] : readonly [ArgChecks<Head, Existing>, ...ValidateVariadicArgs<Tail, Existing | DefName<Head>>] : readonly [ArgChecks<Head, Existing>] : { [I in keyof A]: ArgChecks<A[I], Existing>; };
116
+ type BrandVariadicPosition<A extends readonly object[]> = { [I in keyof A]: A[I] & {
117
+ readonly FIX_VARIADIC_POSITION: "Only the last positional argument can be variadic";
118
+ }; };
119
+ type AppendArgsChecks<A extends ArgsDef, NewA extends ArgsDef> = A extends readonly [...unknown[], infer Last] ? Last extends {
120
+ variadic: true;
121
+ } ? BrandVariadicPosition<ValidateVariadicArgs<NewA, ArgNames<A>>> : ValidateVariadicArgs<NewA, ArgNames<A>> : ValidateVariadicArgs<NewA>;
122
+ /** Conditional collections and uncertain canonical identities cannot promise every alternative output key. */
123
+ type AttachedArgs<A extends ArgsDef> = HasClosedNames<A> extends true ? A : ArgsDef;
124
+ //#endregion
125
+ //#region src/validation/commands.brands.d.ts
126
+ /** Preserve configured aliases; only a genuinely absent field proves an empty set. */
127
+ type AliasesOf<C> = C extends {
128
+ readonly aliases: infer A extends readonly string[];
129
+ } ? A : "aliases" extends keyof C ? readonly string[] : readonly [];
130
+ type NarrowAliases<A extends readonly string[]> = IsClosedName<A[number]> extends true ? A[number] : never;
131
+ type AliasMembers<A extends readonly string[]> = ClosedMembers<A[number]>;
132
+ type AliasShapeError<Name extends string, Alias extends string> = Alias extends "" ? `Subcommand "${Name}" has an invalid alias: must be a non-empty string` : Alias extends `${string} ${string}` | `${string}\t${string}` | `${string}\n${string}` | `${string}\r${string}` | `${string}\v${string}` | `${string}\f${string}` ? `Subcommand "${Name}" alias "${Alias}" must not contain whitespace` : Alias extends `-${string}` ? `Subcommand "${Name}" alias "${Alias}" must not start with "-" (reserved for flags)` : string extends Name ? never : Alias extends Name ? `Subcommand "${Name}" alias "${Alias}" must not equal its own canonical name` : never;
133
+ type AliasShapeErrors<Name extends string, C> = AliasMembers<AliasesOf<C>> extends (infer Alias) ? Alias extends string ? AliasShapeError<Name, Alias> : never : never;
134
+ type AliasShapeBrand<Name extends string, C> = [AliasShapeErrors<Name, C>] extends [never] ? {} : {
135
+ readonly FIX_ALIAS_SHAPE: AliasShapeErrors<Name, C>;
136
+ };
137
+ type RootVersionBrand<C> = "version" extends keyof C ? {
138
+ readonly FIX_ROOT_VERSION: "Command config \"version\" belongs on the root Crust constructor";
139
+ } : {};
140
+ /** Brand command config containing statically known invalid metadata. */
141
+ type ValidateCommandConfig<Name extends string, C> = AliasShapeBrand<Name, C> & RootVersionBrand<C>;
142
+ type EmptyNameError = {
143
+ readonly FIX_EMPTY_NAME: "Command name must be a non-empty string";
144
+ };
145
+ type TrimWhitespace = " " | "\t" | "\n" | "\r" | "\v" | "\f" | " " | " " | " " | " " | " " | " " | " " | " " | " " | " " | " " | " " | " " | "
" | "
" | " " | " " | " " | "";
146
+ type BlankName<Name extends string> = Name extends `${TrimWhitespace}${infer Tail}` ? BlankName<Tail> : Name extends "" ? true : false;
147
+ /** Runtime checks own open members; every statically known member is validated, even beside an open one. */
148
+ type CommandNameBrand<Name extends string> = true extends BlankName<ClosedMembers<Name>> ? EmptyNameError : "__proto__" extends ClosedMembers<Name> ? {
149
+ readonly FIX_RESERVED_NAME: "Command name \"__proto__\" is reserved";
150
+ } : {};
151
+ type DefinitionAliases<D> = CommandDefinitionData<D> extends {
152
+ readonly _aliases?: infer A extends readonly string[];
153
+ } ? A : readonly string[];
154
+ /** All statically known canonical and alias spellings carried by a command definition. */
155
+ type CommandDefinitionSpellings<D> = D extends unknown ? D extends {
156
+ name: infer N extends string;
157
+ } ? IsUnion<N> extends true ? never : DefName<D> extends (infer Name extends string) ? [Name] extends [never] ? never : Name | NarrowAliases<DefinitionAliases<D>> : never : never : never;
158
+ type SelfAliasBrand<D> = UnionToIntersection<D extends unknown ? DefNameMembers<D> & AliasMembers<DefinitionAliases<D>> extends (infer Dup extends string) ? [Dup] extends [never] ? {} : {
159
+ readonly FIX_ALIAS_SHAPE: `Command "${Dup}" must not list its own canonical name as an alias`;
160
+ } : never : never>;
161
+ type CommandCollisionBrand<Spellings extends string, Existing extends string> = CollisionBrand<Spellings, Existing, "FIX_COMMAND_COLLISION", "Command name or alias ", " collides with a sibling command">;
162
+ /**
163
+ * Validate definitions against existing siblings and definitions earlier in
164
+ * the same `.add()` call. Widened names opt out because their spellings are
165
+ * not statically knowable; their literal aliases opt out with them
166
+ * (see {@link CommandDefinitionSpellings}).
167
+ */
168
+ type ValidateCommandDefinitions<Ds extends readonly unknown[], Existing extends string = never> = Ds extends readonly [infer Head, ...infer Tail] ? CommandDefinitionSpellings<Head> extends (infer Spellings extends string) ? readonly [Head & CommandCollisionBrand<Spellings, Existing> & CommandNameBrand<DefNameMembers<Head>> & SelfAliasBrand<Head>, ...ValidateCommandDefinitions<Tail, Existing | Spellings>] : never : Ds;
169
+ type ExtensionCommandDefs<E> = [E] extends [never] ? readonly [] : DefiningOf<E> extends {
170
+ readonly commands?: infer Cs extends readonly unknown[];
171
+ } ? Cs : readonly [];
172
+ /** An uncertain command collection opens only the child namespace. */
173
+ type ExtensionCommandSpellings<E> = AttachedCommandSpellings<ExtensionCommandDefs<E>>;
174
+ type ExtensionsCommandSpellings<Es extends readonly unknown[]> = IsStaticTuple<Es> extends true ? { [I in keyof Es]: ExtensionCommandSpellings<Es[I]>; }[number] : ExtensionCommandDefs<Es[number]>[number] extends never ? never : string;
175
+ type ExtensionCommandCollisionBrand<E, Existing extends string> = CollisionBrand<ExtensionCommandSpellings<E>, Existing, "FIX_COMMAND_COLLISION", "Extension command ", " collides with an existing command">;
176
+ /**
177
+ * Validate each Extension's contributed command spellings against existing
178
+ * root commands and against Extensions earlier in the same `.extend()` call.
179
+ * Runtime preparation resolves collisions last-write-wins, so a statically
180
+ * known collision would silently retype `run()` against a command that
181
+ * dispatch replaces.
182
+ */
183
+ type ValidateExtensionCommands<Es extends readonly unknown[], Existing extends string> = Es extends readonly [infer H, ...infer T extends readonly unknown[]] ? readonly [H & ExtensionCommandCollisionBrand<H, Existing>, ...ValidateExtensionCommands<T, Existing | ExtensionCommandSpellings<H>>] : Es;
184
+ /** Local metadata checks; unrelated description/version/usage text has no grammar. */
185
+ type SectionTextBrand<S> = S extends {
186
+ title: infer T extends string;
187
+ body: infer B extends string;
188
+ } ? true extends BlankName<T> | BlankName<B> ? {
189
+ readonly FIX_SECTION_TEXT: "Section title/body must be nonblank";
190
+ } : Extract<T, `${string}\r${string}` | `${string}\n${string}`> extends never ? {} : {
191
+ readonly FIX_SECTION_TEXT: "Section title must be a single line";
192
+ } : {};
193
+ type SectionAudienceBrand<S> = S extends {
194
+ only: readonly [];
195
+ } | {
196
+ except: readonly [];
197
+ } ? {
198
+ readonly FIX_SECTION_AUDIENCE: "Section audience must be nonempty";
199
+ } : {};
200
+ type LocalSectionsBrand<C> = "sections" extends keyof C ? C extends {
201
+ sections: infer S extends readonly unknown[];
202
+ } ? {
203
+ readonly sections: { [I in keyof S]: S[I] & UnionToIntersection<SectionTextBrand<S[I]>> & UnionToIntersection<SectionAudienceBrand<S[I]>>; };
204
+ } : {} : {};
205
+ type LocalCommandConfigBrand<N extends string, C> = ValidateCommandConfig<N, C> & LocalSectionsBrand<C>;
206
+ type AttachedCommandSpellings<Ds extends readonly unknown[]> = [Ds] extends [readonly []] ? never : IsStaticTuple<Ds> extends true ? HasClosedNames<Ds> extends true ? false extends { [I in keyof Ds]: IsClosedName<DefinitionAliases<Ds[I]>[number]>; }[number] ? string : CommandDefinitionSpellings<Ds[number]> : string : string;
207
+ //#endregion
208
+ //#region src/validation/contexts.brands.d.ts
209
+ /** Canonical names claimed by more than one instance in the same `.provide()` call. */
210
+ type DuplicateContextNames<Cs extends readonly AnyContextInstance[], Seen extends string = never> = Cs extends readonly [infer Head, ...infer Tail extends readonly AnyContextInstance[]] ? (DefName<Head> & Seen) | DuplicateContextNames<Tail, Seen | DefName<Head>> : never;
211
+ type DuplicateContextBrand<C, Existing extends string> = CollisionBrand<DefName<C>, Existing, "FIX_DUPLICATE_CONTEXT", "Context ", " is already provided on this command path">;
212
+ /**
213
+ * Brand instances whose name is already provided on this builder chain or
214
+ * repeated within the same `.provide()` call. The accumulated Context value
215
+ * map doubles as the name registry (its keys are the provided names), so no
216
+ * separate accumulator is needed. Wrappers generic over the builder type
217
+ * use `any`, which opts out via the
218
+ * `string extends keyof Ctx` guard instead of deferring. Widened names opt
219
+ * out via `DefName`; a parent-provided Context is not in the definition's
220
+ * `Ctx` and therefore cannot be checked at this call site.
221
+ */
222
+ type ValidateContextNames<Ctx extends ContextMap, Cs extends readonly AnyContextInstance[], Existing extends string = string extends keyof Ctx ? never : keyof Ctx & string, Dups extends string = DuplicateContextNames<Cs>> = { [I in keyof Cs]: Cs[I] & DuplicateContextBrand<Cs[I], Existing | Dups>; };
223
+ type InstanceNames<P extends readonly unknown[]> = P extends readonly [infer H, ...infer T extends readonly unknown[]] ? DefName<H> | InstanceNames<T> : never;
224
+ /** Statically known names of an Extension's provided Contexts; widened Extensions opt out. */
225
+ type ExtensionProvidedNames<E> = DefiningOf<E> extends {
226
+ readonly provides?: infer P extends readonly unknown[];
227
+ } ? InstanceNames<P> : never;
228
+ type ExtensionContextBrand<E, Existing extends string> = CollisionBrand<ExtensionProvidedNames<E>, Existing, "FIX_DUPLICATE_CONTEXT", "Extension-provided Context ", " is already provided on this command path">;
229
+ type ValidateExtensionProvidesWorker<Es extends readonly unknown[], Existing extends string> = Es extends readonly [infer H, ...infer T extends readonly unknown[]] ? readonly [H & ExtensionContextBrand<H, Existing>, ...ValidateExtensionProvidesWorker<T, Existing | ExtensionProvidedNames<H>>] : Es;
230
+ /**
231
+ * Brand Extensions whose provided Context names replace one already on the
232
+ * command path (or one provided by an earlier Extension in the same call).
233
+ * The resolver is last-write-wins, so a silent replacement would hand actions
234
+ * bound before `.extend()` a value of a different static type.
235
+ */
236
+ type ValidateExtensionProvides<Es extends readonly unknown[], Ctx extends ContextMap> = ValidateExtensionProvidesWorker<Es, string extends keyof Ctx ? never : keyof Ctx & string>;
237
+ type ProvidedDepsOf<C> = IsAny<C> extends true ? {} : IsAny<ContextDepsOf<C>> extends true ? {} : string extends keyof ContextDepsOf<C> ? {} : ContextDepsOf<C>;
238
+ type MissingDependencyBrand<C, Known extends string> = Exclude<keyof ProvidedDepsOf<C> & string, Known> extends (infer Missing extends string) ? [Missing] extends [never] ? {} : {
239
+ readonly FIX_MISSING_DEPENDENCY: `Context "${DefName<C>}" uses Context "${Missing}" which is not provided on this command path`;
240
+ } : never;
241
+ type MismatchedDependencyNames<Deps, KnownValues> = keyof Deps extends never ? never : KnownValues extends unknown ? { [K in keyof Deps & keyof KnownValues & string]: IsAny<KnownValues[K]> extends true ? never : IsAny<Deps[K]> extends true ? never : [unknown, string] extends [KnownValues[K], keyof KnownValues] ? never : KnownValues[K] extends Deps[K] ? never : K; }[keyof Deps & keyof KnownValues & string] : never;
242
+ type MismatchedDependencyBrand<C, KnownValues> = MismatchedDependencyNames<ProvidedDepsOf<C>, KnownValues> extends (infer Mismatched extends string) ? [Mismatched] extends [never] ? {} : {
243
+ readonly FIX_DEPENDENCY_TYPE: `Context "${DefName<C>}" uses Context "${Mismatched}" whose provided value does not satisfy the declared dependency type`;
244
+ } : never;
245
+ /** Brand provided instances whose transitive dependency closure is unsatisfied. */
246
+ type ValidateContextDeps<Ctx extends ContextMap, Cs extends readonly AnyContextInstance[], Known extends string = (keyof Ctx & string) | DefName<Cs[number]>, KnownValues extends ContextMap = Ctx & ContextsOutput<Cs>> = { [I in keyof Cs]: Cs[I] & MissingDependencyBrand<Cs[I], Known> & MismatchedDependencyBrand<Cs[I], KnownValues>; };
247
+ /** Dependency closure carried by command definitions and Extensions. */
248
+ type IsAny<T> = 0 extends 1 & T ? true : false;
249
+ type DeclaredDepsOf<T> = IsAny<T> extends true ? Record<string, ContextValue> : CommandDefinitionData<DefiningOf<T>> extends {
250
+ readonly _deps?: infer D extends ContextMap;
251
+ } ? IsAny<D> extends true ? Record<string, ContextValue> : D : {};
252
+ /** Missing-dependency brand shared by `ValidateDeclaredDeps` and inline `.command()`. */
253
+ type MissingDeclaredDependencyBrand<T, Known extends string> = string extends keyof DeclaredDepsOf<T> ? {} : Exclude<keyof DeclaredDepsOf<T> & string, Known> extends (infer Missing extends string) ? [Missing] extends [never] ? {} : {
254
+ readonly FIX_MISSING_DEPENDENCY: `Uses Context "${Missing}" which is not provided`;
255
+ } : never;
256
+ /** Brand sealed units whose declared dependencies are absent at a composition site. */
257
+ type ValidateDeclaredDeps<Ctx extends ContextMap, Items extends readonly unknown[]> = { [I in keyof Items]: Items[I] & MissingDeclaredDependencyBrand<Items[I], keyof Ctx & string> & DeclaredDependencyValuesBrand<DeclaredDepsOf<Items[I]>, Ctx>; };
258
+ /** Callback values stay TypeScript-owned, including at dynamic composition. */
259
+ type DeclaredDependencyValuesBrand<Deps, Values> = MismatchedDependencyNames<Deps, Values> extends (infer Names extends string) ? [Names] extends [never] ? {} : {
260
+ readonly FIX_DEPENDENCY_TYPE: `Provided Context "${Names}" does not satisfy its declared value type`;
261
+ } : never;
262
+ /** Structural provider copies retain their defining name. */
263
+ type KnownContextInstances<Cs extends readonly AnyContextInstance[]> = { [I in keyof Cs]: Cs[I] & Pick<DefiningOf<Cs[I]>, "name">; };
264
+ //#endregion
265
+ //#region src/validation/flags.brands.d.ts
266
+ /** Brand an incoming definition when one of its spellings is already claimed. */
267
+ type ExistingFlagCollisionBrand<F, Existing extends string> = CollisionBrand<DefName<F> | ExtractAllAliases<F>, Existing, "FIX_ALIAS_COLLISION", "Flag spelling ", " collides with an existing flag">;
268
+ /**
269
+ * Every statically known canonical, short, and long-alias member, including literals
270
+ * beside an open member. Spelling grammar only: collision evidence stays with
271
+ * {@link ExtractAllAliases}, which must not leak literals out of an open domain.
272
+ * Each field is filtered on its own so a `string`-typed field cannot absorb a
273
+ * sibling field's invalid literal before the filter runs.
274
+ */
275
+ type SpellingMembers<F> = DefNameMembers<F> | ClosedMembers<F extends {
276
+ short: infer S extends string;
277
+ } ? S : never> | ClosedMembers<F extends {
278
+ aliases: infer A extends readonly string[];
279
+ } ? A[number] : never>;
280
+ /** Reject `__proto__`, which mutates the prototype of plain-object flag registries. */
281
+ type ReservedSpellingBrand<F> = "__proto__" extends SpellingMembers<F> ? {
282
+ readonly FIX_RESERVED_SPELLING: "Flag spelling \"__proto__\" is reserved";
283
+ } : {};
284
+ type EmptySpellingError = {
285
+ readonly FIX_EMPTY_SPELLING: "Flag names and aliases must be non-empty strings";
286
+ };
287
+ /** Reject empty flag names, including an empty member of a name union beside an open member. */
288
+ type EmptyFlagSpellingBrand<Name extends string> = EmptyLiteralNameBrand<Name, EmptySpellingError>;
289
+ /** Reject empty spellings: their CLI tokens (`--`, `-`) are unparseable, so the flag can never be supplied. */
290
+ type EmptySpellingBrand<F> = "" extends SpellingMembers<F> ? EmptySpellingError : {};
291
+ type RepeatedAliases<Aliases extends readonly string[], Seen extends string> = Aliases extends readonly [infer Head extends string, ...infer Tail extends readonly string[]] ? (Head & Seen) | RepeatedAliases<Tail, Seen | Head> : never;
292
+ type OwnAliasesBrand<F> = F extends {
293
+ aliases: infer Aliases extends readonly string[];
294
+ } ? RepeatedAliases<Aliases, ExtractShort<F>> extends (infer Duplicate extends string) ? [Duplicate] extends [never] ? {} : {
295
+ readonly FIX_ALIAS_COLLISION: "Flag repeats one of its own spellings";
296
+ } : never : {};
297
+ type InvalidShort<S extends string> = S extends `${infer _First}${infer Rest}` ? Rest extends "" ? never : S : S;
298
+ type ShortLengthBrand<F> = F extends {
299
+ short: infer Short extends string;
300
+ } ? string extends Short ? {} : [InvalidShort<Short>] extends [never] ? {} : {
301
+ readonly FIX_SHORT_LENGTH: "Short flags must be one character";
302
+ } : {};
303
+ /**
304
+ * Extract the `short` alias literal from a flag definition.
305
+ * Resolves to `never` when the field is absent or its spelling domain is open.
306
+ */
307
+ type ExtractShort<F> = F extends {
308
+ short: infer S;
309
+ } ? S extends string ? IsClosedName<S> extends true ? S : never : never : never;
310
+ /**
311
+ * Extract alias string literals from the `aliases` array of a flag definition.
312
+ * Resolves to `never` when the field is absent or its element domain is open.
313
+ */
314
+ type ExtractLongAliases<F> = F extends {
315
+ aliases: infer A;
316
+ } ? A extends readonly string[] ? IsClosedName<A[number]> extends true ? A[number] : never : never : never;
317
+ /**
318
+ * Extract all alias identifiers (short + long) from a flag definition.
319
+ *
320
+ * Generalized to work with any shape; values without `short`/`aliases`
321
+ * fields resolve to `never`.
322
+ *
323
+ * Closed-name proof excludes open domains from literal collision evidence.
324
+ * Attachment separately keeps their spelling namespace open.
325
+ */
326
+ type ExtractAllAliases<F> = ExtractShort<F> | ExtractLongAliases<F>;
327
+ /** All narrowed canonical, short, and long-alias spellings in a flags record. */
328
+ type SpellingsOf<F extends FlagsDef> = string extends keyof F ? never : (keyof F & string) | { [K in keyof F & string]: ExtractAllAliases<F[K]>; }[keyof F & string];
329
+ type NoPrefixBrand<S extends string> = [Extract<S, `no-${string}`>] extends [never] ? {} : {
330
+ readonly FIX_NO_PREFIX: "Names must not start with no-";
331
+ };
332
+ type ContextOwnedFlags<C> = C extends unknown ? DefiningOf<C> extends {
333
+ readonly _ownedFlags?: infer OF extends FlagsDef;
334
+ } ? OF : {} : never;
335
+ type ContextFlagCollisionBrand<C, Existing extends string> = CollisionBrand<LocalSpellingsOf<ContextOwnedFlags<C>>, Existing, "FIX_ALIAS_COLLISION", "Flag spelling ", " collides with an existing flag">;
336
+ /** Declared flag literals carried by an Extension's `_flagDefs` phantom; widened Extensions opt out. */
337
+ type ExtensionFlagDefsOf<E> = [E] extends [never] ? readonly [] : DefiningOf<E> extends {
338
+ readonly _flagDefs?: infer D extends readonly NamedFlagDef[];
339
+ } ? D : readonly NamedFlagDef[];
340
+ /** All statically known owned-flag spellings across a tuple of Context instances. */
341
+ type ProvidedContextSpellings<P extends readonly unknown[]> = P extends readonly [infer H, ...infer T extends readonly unknown[]] ? LocalSpellingsOf<ContextOwnedFlags<H>> | ProvidedContextSpellings<T> : [P[number]] extends [never] ? never : LocalSpellingsOf<ContextOwnedFlags<P[number]>>;
342
+ /** All statically known flag spellings an Extension contributes: declared flags plus provided Context-owned flags. */
343
+ type ExtensionSpellings<E> = AttachedSpellings<ExtensionFlagDefsOf<E>> | ([E] extends [never] ? never : DefiningOf<E> extends {
344
+ readonly provides?: infer P extends readonly unknown[];
345
+ } ? ProvidedContextSpellings<P> : never);
346
+ type ExtensionFlagCollisionBrand<E, Existing extends string> = CollisionBrand<ExtensionSpellings<E>, Existing, "FIX_ALIAS_COLLISION", "Extension flag spelling ", " collides with an existing flag">;
347
+ /**
348
+ * Validate each Extension's contributed flag spellings against accumulated
349
+ * existing spellings and against Extensions earlier in the same `.extend()`
350
+ * call. Extensions must not override application flags: a silent overwrite
351
+ * would retype an already-bound action's flag at parse time.
352
+ */
353
+ type ValidateExtensionFlags<Es extends readonly unknown[], Existing extends string> = Es extends readonly [infer H, ...infer T extends readonly unknown[]] ? readonly [H & ExtensionFlagCollisionBrand<H, Existing>, ...ValidateExtensionFlags<T, Existing | ExtensionSpellings<H>>] : Es;
354
+ type ShapeSpellings<S> = 0 extends 1 & S ? string : S extends {
355
+ readonly flags: infer F extends FlagsDef;
356
+ readonly children: infer C;
357
+ } ? LocalSpellingsOf<F> | TreeSpellings<C> : never;
358
+ /** Every flag spelling reachable in a compile-time command tree (`Record<spelling, CommandShape>`), recursively. */
359
+ type TreeSpellings<Tree> = 0 extends 1 & Tree ? string : string extends keyof Tree ? string : Tree extends object ? { [K in keyof Tree]: ShapeSpellings<Tree[K]>; }[keyof Tree] : never;
360
+ type DefinitionSpellings<D> = CommandDefinitionData<D> extends {
361
+ readonly _shape?: infer S;
362
+ } ? ShapeSpellings<S> : never;
363
+ /** Flag spellings contributed by a tuple of command definitions. */
364
+ type DefinitionTreeSpellings<Ds extends readonly unknown[]> = DefinitionSpellings<Ds[number]>;
365
+ /**
366
+ * Extension-collision brand over a built command shape. Shared by `.add()`
367
+ * (via {@link ValidateDefinitionFlags}) and inline `.command()`, whose recipe
368
+ * builder exposes a shape instead of a definition tuple.
369
+ */
370
+ type ShapeFlagCollisionBrand<S, Ext extends string> = CollisionBrand<ShapeSpellings<S>, Ext, "FIX_ALIAS_COLLISION", "Flag spelling ", " collides with a registered Extension flag">;
371
+ type DefinitionFlagCollisionBrand<D, Ext extends string> = CommandDefinitionData<D> extends {
372
+ readonly _shape?: infer S;
373
+ } ? ShapeFlagCollisionBrand<S, Ext> : {};
374
+ /**
375
+ * Validate an added definition tree's flag spellings against already-registered
376
+ * Extension flags. Recursive Extension flags inject into every node at prepare
377
+ * time, so a colliding local flag would be silently retyped for its action.
378
+ */
379
+ type ValidateDefinitionFlags<Ds extends readonly unknown[], Ext extends string> = { [I in keyof Ds]: Ds[I] & DefinitionFlagCollisionBrand<Ds[I], Ext>; };
380
+ /** Union of every statically known flag spelling contributed by a tuple of Extensions. */
381
+ type ExtensionsSpellings<Es extends readonly unknown[]> = Es extends readonly [infer H, ...infer T extends readonly unknown[]] ? ExtensionSpellings<H> | ExtensionsSpellings<T> : ExtensionSpellings<Es[number]> extends never ? never : string;
382
+ /**
383
+ * Validate Context-owned flags against accumulated existing spellings and
384
+ * against instances earlier in the same `.provide(a(), b())` call. Without
385
+ * the batch check a same-call collision silently resolves last-write-wins,
386
+ * and a required flag shadowed by a peer's alias becomes impossible to supply.
387
+ */
388
+ type ProvideChecks<Sp extends string, Cs extends readonly unknown[]> = Cs extends readonly [infer H, ...infer T extends readonly unknown[]] ? readonly [H & ContextFlagCollisionBrand<H, Sp>, ...ProvideChecks<Sp | LocalSpellingsOf<ContextOwnedFlags<H>>, T>] : Cs;
389
+ /** Whether canonical and alias spellings form a closed, fixed local namespace. */
390
+ type HasClosedFlagSpellings<F> = F extends {
391
+ name: infer N extends string;
392
+ } ? false extends IsClosedName<N> | ("short" extends keyof F ? F extends {
393
+ short: infer S extends string;
394
+ } ? IsClosedName<S> : false : true) | ("aliases" extends keyof F ? F extends {
395
+ aliases: infer A extends readonly string[];
396
+ } ? false extends IsStaticTuple<A> | IsClosedName<A[number]> ? false : true : false : true) ? false : true : false;
397
+ type LocalFlagBrand<F> = UnionToIntersection<F extends unknown ? LocalFlagBranchBrand<F> : never>;
398
+ type LocalFlagBranchBrand<F> = LocalValueBrand<F> & OwnAliasesBrand<F> & ShortLengthBrand<F> & ReservedSpellingBrand<F> & EmptySpellingBrand<F> & NoPrefixBrand<SpellingMembers<F>> & ([DefName<F> & ExtractAllAliases<F>] extends [never] ? {} : {
399
+ readonly FIX_ALIAS_COLLISION: "Flag repeats one of its own spellings";
400
+ });
401
+ /** Validate provable local fields and destination relations without inventing names for open inputs. */
402
+ type ValidateLocalFlagDefs<Defs extends readonly NamedFlagDef[], Existing extends string> = Defs & UnionToIntersection<LocalFlagTupleChecks<Defs, Existing>>;
403
+ type LocalFlagTupleChecks<Defs extends readonly NamedFlagDef[], Existing extends string, Errors = {}> = Defs extends readonly [infer Head extends NamedFlagDef, ...infer Tail extends readonly NamedFlagDef[]] ? LocalFlagTupleChecks<Tail, Existing | DefName<Head> | ExtractAllAliases<Head>, Errors & LocalFlagBrand<Head> & ExistingFlagCollisionBrand<Head, Existing>> : Defs extends readonly [] ? Errors : Errors & LocalFlagBrand<Defs[number]>;
404
+ /** An open collection is not an empty or guaranteed-present flag record. */
405
+ type KnownNamedFlag<D> = D extends NamedFlagDef ? HasClosedNames<readonly [D]> extends true ? D : never : never;
406
+ type AttachedFlags<Defs extends readonly NamedFlagDef[]> = HasClosedNames<Defs> extends true ? NamedFlagsRecord<Defs> : IsStaticTuple<Defs> extends true ? FlagsDef & NamedFlagsRecord<readonly KnownNamedFlag<Defs[number]>[]> : FlagsDef;
407
+ type AttachedSpellings<Defs extends readonly NamedFlagDef[]> = IsStaticTuple<Defs> extends true ? false extends { [I in keyof Defs]: HasClosedFlagSpellings<Defs[I]>; }[number] ? string : SpellingsOf<NamedFlagsRecord<Defs>> : string;
408
+ type LocalFlagNameBrand<N extends string> = EmptyFlagSpellingBrand<N> & ReservedSpellingBrand<{
409
+ name: N;
410
+ }> & NoPrefixBrand<N>;
411
+ /** Broad structural builder holders must not default their spelling state to empty. */
412
+ type LocalSpellingsOf<F extends FlagsDef> = string extends keyof F ? string : true extends { [K in keyof F]: HasClosedFlagSpellings<F[K] & {
413
+ name: K;
414
+ }> extends false ? true : false; }[keyof F] ? string : SpellingsOf<F>;
415
+ //#endregion
416
+ //#region src/command/snapshot.d.ts
417
+ /**
418
+ * Serializable projection of a positional argument definition.
419
+ *
420
+ * Carries everything help/man/tooling surfaces need; `parse` functions and
421
+ * schemas never cross the boundary.
422
+ *
423
+ * Fields with `undefined` values are dropped entirely (see `freezeCompact`),
424
+ * so absent means "not declared".
425
+ *
426
+ * @example
427
+ * For `{ name: "port", type: "number", default: 3000 }`:
428
+ * ```ts
429
+ * { name: "port", type: "number", default: 3000 }
430
+ * // `required`/`variadic` keys absent — not declared on the def
431
+ * ```
432
+ */
433
+ interface ArgSnapshot {
434
+ /** Argument name as defined, e.g. `"file"`. */
435
+ readonly name: string;
436
+ /** Value type (`"string"`, `"number"`, …); absent for schema-backed args. */
437
+ readonly type?: ValueType;
438
+ /** Human-readable description for help text. */
439
+ readonly description?: string;
440
+ /** `true` when parsing fails if the argument is missing. */
441
+ readonly required?: boolean;
442
+ /** `true` when the argument collects all remaining positionals into an array. */
443
+ readonly variadic?: boolean;
444
+ /** Static enum of accepted values, e.g. `["json", "text"]`. */
445
+ readonly choices?: readonly string[];
446
+ /** Declared default value; `URL` defaults are serialized to their `href` string. */
447
+ readonly default?: unknown;
448
+ }
449
+ /**
450
+ * Serializable projection of a flag definition. The flag's canonical name is
451
+ * the key it sits under in {@link CommandSnapshot.flags}, not a field here.
452
+ *
453
+ * @example
454
+ * For `{ verbose: { type: "boolean", short: "v", default: false } }`:
455
+ * ```ts
456
+ * snapshot.flags.verbose
457
+ * // => { type: "boolean", short: "v", default: false, negatable: true }
458
+ * ```
459
+ */
460
+ interface FlagSnapshot {
461
+ /** Value type, e.g. `"boolean"`, `"string"`, `"number"`. */
462
+ readonly type: ValueType;
463
+ /** Human-readable description for help text. */
464
+ readonly description?: string;
465
+ /** Single-character short alias without the dash, e.g. `"v"` for `-v`. */
466
+ readonly short?: string;
467
+ /** Additional aliases without dashes; one-character aliases accept one or two dashes. */
468
+ readonly aliases?: readonly string[];
469
+ /** `true` when parsing fails if the flag is not provided. */
470
+ readonly required?: boolean;
471
+ /** `true` when the flag can repeat and collects values into an array. */
472
+ readonly multiple?: boolean;
473
+ /** `true` when the flag accepts generated `--no-<name>` spellings. */
474
+ readonly negatable: boolean;
475
+ /** `true` when a boolean flag opted out of the `--no-<name>` spelling. */
476
+ readonly noNegate?: boolean;
477
+ /** Static enum of accepted values, e.g. `["debug", "info", "error"]`. */
478
+ readonly choices?: readonly string[];
479
+ /** Declared default value; `URL` defaults are serialized to their `href` string. */
480
+ readonly default?: unknown;
481
+ }
482
+ /**
483
+ * A readonly, serializable description of a command, exposed across public
484
+ * API boundaries (Command Action context, Extension hooks, and
485
+ * `COMMAND_NOT_FOUND` error details) instead of internal command nodes.
486
+ *
487
+ * `flags` contains the effective (Context-owned + local merged) flags — the same
488
+ * set the parser accepts for the command.
489
+ *
490
+ * @example
491
+ * ```ts
492
+ * defineCommand("add", (cmd) =>
493
+ * cmd
494
+ * .args({ name: "name", type: "string", required: true })
495
+ * .flags({ name: "force", type: "boolean", short: "f" })
496
+ * .action(() => {}),
497
+ * );
498
+ * // snapshots to:
499
+ * // {
500
+ * // meta: { name: "add" },
501
+ * // hasAction: true,
502
+ * // args: [{ name: "name", type: "string", required: true }],
503
+ * // flags: { force: { type: "boolean", short: "f", negatable: true } },
504
+ * // subCommands: {},
505
+ * // }
506
+ * ```
507
+ */
508
+ interface CommandSnapshot {
509
+ /** Command metadata, including routing and presentation options. */
510
+ readonly meta: Readonly<CommandMeta>;
511
+ /** Whether the command defines a Command Action */
512
+ readonly hasAction: boolean;
513
+ /** Positional argument snapshots in declaration order. */
514
+ readonly args: readonly ArgSnapshot[];
515
+ /** Effective flags keyed by canonical flag name. */
516
+ readonly flags: Readonly<Record<string, FlagSnapshot>>;
517
+ /** Direct subcommand snapshots keyed by canonical name (includes hidden ones). */
518
+ readonly subCommands: Readonly<Record<string, CommandSnapshot>>;
519
+ }
520
+ //#endregion
521
+ //#region src/command/crust.d.ts
522
+ /**
523
+ * The runtime context object passed to the Command Action defined with
524
+ * `.action()`.
525
+ *
526
+ * Generic parameters:
527
+ * - `A` — positional argument definitions tuple
528
+ * - `F` — the effective (Context-owned + local merged) flag definitions
529
+ */
530
+ interface CrustCommandContext<A extends ArgsDef = ArgsDef, F extends FlagsDef = FlagsDef, Ctx extends ContextMap = {}> extends InvocationIO {
531
+ /** Resolved positional arguments, keyed by arg name */
532
+ args: InferArgs<A>;
533
+ /** Resolved flags, keyed by flag name */
534
+ flags: InferFlags<F>;
535
+ /** Lazy Context values available on this command path. */
536
+ ctx: ContextBag<Ctx>;
537
+ /** Raw arguments that appeared after the `--` separator */
538
+ rawArgs: string[];
539
+ /** Readonly, serializable snapshot of the resolved command */
540
+ command: CommandSnapshot;
541
+ /** Readonly snapshot of the application root, including Extension contributions */
542
+ rootCommand: CommandSnapshot;
543
+ }
544
+ declare const commandProviders: unique symbol;
545
+ /** Compile-time description of one command's programmatic input and action result. */
546
+ interface CommandShape<A extends ArgsDef = ArgsDef, F extends FlagsDef = FlagsDef, Children extends object = {}, Result = unknown, Providers extends Record<string, ContextValue> = Record<string, ContextValue>> {
547
+ readonly [commandProviders]?: Providers;
548
+ readonly args: A;
549
+ readonly flags: F;
550
+ readonly children: Children;
551
+ readonly result: Result;
552
+ }
553
+ /** Captured invocation after lifecycle cleanup. */
554
+ type RunOutcome<Result> = {
555
+ readonly stdout: string;
556
+ readonly stderr: string;
557
+ } & ({
558
+ readonly status: "completed";
559
+ readonly result: Result;
560
+ } | {
561
+ readonly status: "finished";
562
+ readonly by: ExtensionId;
563
+ } | {
564
+ readonly status: "failed";
565
+ readonly error: unknown;
566
+ });
567
+ /** Compile-time command tree accumulated by `.add()`. */
568
+ type CommandTree = Record<string, CommandShape>;
569
+ /** Every valid path through a command tree, including the root path (`[]`). */
570
+ type CommandPath<Tree extends object, Depth extends readonly unknown[] = readonly []> = Depth["length"] extends 15 ? readonly string[] : string extends keyof Tree ? readonly string[] : readonly [] | { [K in keyof Tree & string]: Tree[K] extends CommandShape ? readonly [K, ...CommandPath<Tree[K]["children"], readonly [...Depth, unknown]>] : never; }[keyof Tree & string];
571
+ type KnownCommandPath<Path extends readonly string[], Tree> = string extends keyof Tree ? Path : IsStaticTuple<Path> extends true ? string extends Path[number] ? never : Path : never;
572
+ /** Resolve the command shape at a typed path. */
573
+ type CommandShapeAt<Shape extends CommandShape, Path extends readonly string[]> = Path extends readonly [infer Head, ...infer Tail extends readonly string[]] ? Head extends keyof Shape["children"] ? Shape["children"][Head] extends (infer Child extends CommandShape) ? CommandShapeAt<Child, Tail> : never : string extends Head ? CommandShape : never : Path extends readonly [] ? Shape : CommandShape;
574
+ type RunSection<Name extends string, Values> = keyof Values extends never ? { [K in Name]?: never; } : {} extends Values ? { [K in Name]?: Values; } : { [K in Name]: Values; };
575
+ /** Structured values bound directly against the selected command's definitions; no argv is produced. */
576
+ type RunInput<Shape extends CommandShape> = RunSection<"args", ArgsDef extends Shape["args"] ? NonNullable<RunInputPayload["args"]> : InputArgs<Shape["args"]>> & RunSection<"flags", FlagsDef extends Shape["flags"] ? NonNullable<RunInputPayload["flags"]> : InputFlags<Shape["flags"]>> & {
577
+ readonly raw?: readonly string[];
578
+ };
579
+ type CompatibleRunValue<Expected, Actual> = Actual extends Expected ? Actual extends object ? Expected extends unknown ? Actual extends Expected ? Actual & { [K in Exclude<keyof Actual, keyof Expected>]: never; } & { [K in keyof Actual & keyof Expected]: CompatibleRunValue<Expected[K], Actual[K]>; } : never : never : Actual : JsonValue extends Expected ? Actual extends JsonCompatible<Actual> ? Actual : never : Expected extends unknown ? CompatibleRunBranch<Expected, Actual> : never;
580
+ type CompatibleRunBranch<Expected, Actual> = Actual extends Expected ? Actual : Expected extends readonly (infer Item)[] ? JsonValue extends Item ? Actual extends (Expected extends readonly [unknown, ...unknown[]] ? readonly [unknown, ...unknown[]] : readonly unknown[]) ? Actual extends JsonCompatible<Actual> ? Actual : never : never : never : Actual extends object ? string extends keyof Expected ? { [K in keyof Actual]: CompatibleRunValue<Exclude<Expected[K & keyof Expected], undefined>, Actual[K]>; } : { [K in keyof Expected]: K extends keyof Actual ? CompatibleRunValue<Exclude<Expected[K], undefined>, Actual[K]> : Expected[K]; } & { [K in Exclude<keyof Actual, keyof Expected>]: never; } : never;
581
+ type CompatibleRunInput<Shape extends CommandShape, Input> = CompatibleRunValue<RunInput<Shape>, Input>;
582
+ type RunInputArguments<Shape extends CommandShape> = {} extends RunInput<Shape> ? readonly [input?: RunInput<Shape>] : readonly [input: RunInput<Shape>];
583
+ type RunArguments<Shape extends CommandShape> = readonly [...RunInputArguments<Shape>, io?: Partial<InvocationIO>];
584
+ /**
585
+ * Typed invoker bound to one command in an app, returned by {@link Crust.at}.
586
+ *
587
+ * `run` accepts the same structured input and IO as `Crust.run` with the path
588
+ * already applied, so a handle can be re-exported as a plain typed function.
589
+ */
590
+ interface CommandHandle<Shape extends CommandShape> {
591
+ /** The typed path this handle was created with (`[]` selects the root). */
592
+ readonly path: readonly string[];
593
+ run(...args: RunArguments<Shape>): Promise<RunOutcome<Shape["result"]>>;
594
+ run<const Input>(input: Input, ...validation: [Input] extends [CompatibleRunInput<Shape, Input>] ? readonly [io?: Partial<InvocationIO>] : readonly [invalidInput: never]): Promise<RunOutcome<Shape["result"]>>;
595
+ }
596
+ /** Static configuration for a reusable command definition. */
597
+ interface CommandConfig extends Omit<CommandMeta, "name" | "sections" | "version"> {
598
+ /** Plain-text sections rendered after built-in command documentation. */
599
+ readonly sections?: readonly RuntimeCommandSectionInput[];
600
+ }
601
+ /** Static metadata accepted by the root command constructor. */
602
+ type RootCommandMeta = Pick<CommandMeta, "description" | "version" | "usage"> & {
603
+ /** Plain-text sections rendered after built-in command documentation. */
604
+ readonly sections?: readonly RuntimeCommandSectionInput[];
605
+ };
606
+ type AnyCommandDefinitionBuilder = Crust<any, any, any, any, any, any, any, any, any, any, any, "recipe">;
607
+ type CommandRecipe<Builder extends AnyCommandDefinitionBuilder = AnyCommandDefinitionBuilder> = (command: CommandDefinitionBuilder<{}, [], {}, never, never>) => Builder;
608
+ declare const commandDefinitionInternal: unique symbol;
609
+ interface CommandDefinitionInternal {
610
+ readonly name: string;
611
+ readonly recipe: (command: AnyCommandDefinitionBuilder) => AnyCommandDefinitionBuilder;
612
+ readonly meta: Omit<CommandMeta, "name">;
613
+ }
614
+ type CommandInputShape<S extends CommandShape> = {
615
+ readonly args: S["args"];
616
+ readonly flags: S["flags"];
617
+ readonly providers: S[typeof commandProviders];
618
+ readonly children: { [K in keyof S["children"]]: S["children"][K] extends CommandShape ? CommandInputShape<S["children"][K]> : never; };
619
+ };
620
+ interface CommandDefinition<Name extends string = string, Aliases extends readonly string[] = readonly string[], Shape extends CommandShape = CommandShape, Deps extends ContextMap = {}> {
621
+ /** The subcommand name this definition is added under */
622
+ readonly name: Name;
623
+ /** The same definition under a different name; configured aliases travel with it. */
624
+ as<const N extends string>(name: N & CommandNameBrand<N> & ValidateCommandConfig<N, {
625
+ aliases: Aliases;
626
+ }>): CommandDefinition<N, Aliases, Shape, Deps>;
627
+ /** @internal */
628
+ readonly [commandDefinitionInternal]: CommandDefinitionInternal & {
629
+ readonly _aliases?: Aliases;
630
+ readonly _shape?: Shape;
631
+ readonly _deps?: Deps;
632
+ readonly proof?: [Shape] extends [never] ? unknown : string extends keyof Shape["flags"] | keyof Deps ? unknown : (state: [CommandInputShape<Shape>, Deps]) => void;
633
+ };
634
+ }
635
+ /** @internal */
636
+ type CommandDefinitionData<D> = D extends {
637
+ readonly [commandDefinitionInternal]: infer Data;
638
+ } ? Data : D;
639
+ type AppendedArgs<A extends ArgsDef, NewA extends ArgsDef> = readonly [...A, ...AttachedArgs<NewA>];
640
+ /** Configure-only capability of {@link Crust} passed to command recipes. */
641
+ type CommandDefinitionBuilder<Flags extends FlagsDef = {}, A extends ArgsDef = ArgsDef, Ctx extends ContextMap = {}, Sibs extends string = never, Sp extends string = LocalSpellingsOf<Flags>, Tree extends object = {}, CtxFlags extends FlagsDef = {}, Result = void, Deps extends ContextMap = {}, Providers extends Record<string, ContextValue> = {}> = Crust<Flags, A, Ctx, Sibs, Sp, Tree, CtxFlags, CollisionSpellings<never, never, {}, never, Deps, Providers>, Result, {}, string, "recipe">;
642
+ type ShapeOfBuilder<B> = [B] extends [never] ? CommandShape<[], {}, {}, never, {}> : B extends {
643
+ readonly _recipeTypes: {
644
+ shape: infer S extends CommandShape;
645
+ };
646
+ } ? S : never;
647
+ type DepsOfBuilder<B> = UnionToIntersection<B extends {
648
+ readonly _recipeTypes: {
649
+ deps: infer Deps extends ContextMap;
650
+ };
651
+ } ? Deps : {}> extends (infer Merged extends ContextMap) ? Merged : {};
652
+ type DefinitionShapeForSpelling<D, Spelling extends string> = D extends unknown ? CommandDefinitionData<D> extends {
653
+ readonly _shape?: infer Shape extends CommandShape;
654
+ } ? Spelling extends CommandDefinitionSpellings<D> ? Shape : never : never : never;
655
+ type ShapeWithInheritedFlags<S, CF extends FlagsDef> = keyof CF extends never ? S : S extends CommandShape<infer SA, infer SF, infer SC, infer SR, infer P> ? CommandShape<SA, MergeFlags<CF, SF>, { [K in keyof SC]: ShapeWithInheritedFlags<SC[K], CF>; }, SR, P> : never;
656
+ type DefinitionsTree<Ds extends readonly CommandDefinition<any, any, any, any>[], CtxFlags extends FlagsDef = {}> = string extends AttachedCommandSpellings<Ds> ? Record<string, CommandShape> & KnownDefinitionTree<Ds, CtxFlags> : { [K in CommandDefinitionSpellings<Ds[number]>]: ShapeWithInheritedFlags<DefinitionShapeForSpelling<Ds[number], K>, CtxFlags>; };
657
+ type KnownDefinitionTree<Ds extends readonly unknown[], CF extends FlagsDef> = IsUnion<Ds> extends true ? {} : Ds extends readonly [infer H, ...infer T] ? (IsUnion<H> extends true ? {} : { [K in CommandDefinitionSpellings<H>]: ShapeWithInheritedFlags<DefinitionShapeForSpelling<H, K>, CF>; }) & KnownDefinitionTree<T, CF> : {};
658
+ type ExtensionCheckAt<Checks, I> = I extends keyof Checks ? Checks[I] : never;
659
+ type ExtensionCommands<Es extends readonly AnyExtension[]> = Es extends readonly [infer H, ...infer T extends readonly AnyExtension[]] ? readonly [...ExtensionCommandDefs<H>, ...ExtensionCommands<T>] : ExtensionCommandDefs<Es[number]>[number] extends never ? readonly [] : readonly CommandDefinition<any, any, any, any>[];
660
+ type ExtensionProviders<E> = [E] extends [never] ? [] : DefiningOf<E> extends {
661
+ provides?: infer P extends readonly AnyContextInstance[];
662
+ } ? P : [];
663
+ type ExtensionOwnDefs<E> = [E] extends [never] ? [] : DefiningOf<E> extends {
664
+ _flagDefs?: infer F extends readonly NamedFlagDef[];
665
+ } ? F : [];
666
+ type ExtensionFlags<Es extends readonly AnyExtension[]> = Es extends readonly [infer H, ...infer T extends readonly AnyExtension[]] ? AttachedFlags<ExtensionOwnDefs<H>> & ContextsOwnedFlags<ExtensionProviders<H>> & ExtensionFlags<T> : ExtensionOwnDefs<Es[number]>[number] extends never ? keyof ContextsOwnedFlags<ExtensionProviders<Es[number]>> extends never ? {} : FlagsDef : FlagsDef;
667
+ type RecursiveFlagsOf<E> = ExtensionOwnDefs<E>[number] extends never ? {} : true extends { [K in keyof ExtensionOwnDefs<E>]: ExtensionOwnDefs<E>[K] extends (infer D extends NamedFlagDef) ? D extends {
668
+ readonly recursive: false;
669
+ } ? false : IsClosedName<D["name"]> extends false ? true : IsUnion<D["name"]> extends true ? true : D extends {
670
+ recursive: infer R;
671
+ } ? boolean extends R ? true : false : false : false; }[number] ? FlagsDef : IsStaticTuple<ExtensionOwnDefs<E>> extends true ? { [D in ExtensionOwnDefs<E>[number] as D extends {
672
+ readonly recursive: infer R;
673
+ } ? [R] extends [false] ? never : D["name"] : D["name"]]: Omit<D, "name">; } : FlagsDef;
674
+ type RecursiveExtensionFlags<Es extends readonly AnyExtension[]> = Es extends readonly [infer H, ...infer T extends readonly AnyExtension[]] ? RecursiveFlagsOf<H> & ContextsOwnedFlags<ExtensionProviders<H>> & RecursiveExtensionFlags<T> : ExtensionFlags<Es>;
675
+ type TreeWithInheritedFlags<Tree, F extends FlagsDef> = { [K in keyof Tree]: ShapeWithInheritedFlags<Tree[K], F>; };
676
+ type ReplacementTree<Tree, D extends CommandDefinition<any, any, any, any>, CF extends FlagsDef> = CommandDefinitionData<D> extends {
677
+ readonly _aliases?: infer Aliases extends readonly string[];
678
+ } ? IsClosedName<Aliases[number]> extends false ? Record<string, CommandShape> & { [K in D["name"]]: ShapeWithInheritedFlags<DefinitionShapeForSpelling<D, K>, CF>; } : Omit<Tree, CommandDefinitionSpellings<D>> & { [K in CommandDefinitionSpellings<D>]: K extends D["name"] ? ShapeWithInheritedFlags<DefinitionShapeForSpelling<D, K>, CF> : K extends keyof Tree ? CommandShape : ShapeWithInheritedFlags<DefinitionShapeForSpelling<D, K>, CF>; } : Record<string, CommandShape>;
679
+ type ReplacedTree<Tree, Commands extends readonly unknown[], CF extends FlagsDef> = Commands extends readonly [infer H extends CommandDefinition<any, any, any, any>, ...infer T extends readonly unknown[]] ? ReplacedTree<IsClosedName<H["name"]> extends false ? Record<string, CommandShape> : true extends IsUnion<H> | IsUnion<H["name"]> ? Record<string, CommandShape> : ReplacementTree<Tree, H, CF>, T, CF> : number extends Commands["length"] ? Record<string, CommandShape> : Tree;
680
+ type ReplacedExtensionTree<Tree, Es extends readonly AnyExtension[], CF extends FlagsDef> = Es extends readonly [infer H extends AnyExtension, ...infer T extends readonly AnyExtension[]] ? ReplacedExtensionTree<ReplacedTree<Tree, ExtensionCommandDefs<H>, CF>, T, CF> : ExtensionCommandDefs<Es[number]>[number] extends never ? Tree : Record<string, CommandShape>;
681
+ type ExtendedTree<Tree, Es extends readonly AnyExtension[], RecursiveFlags extends FlagsDef, InheritedFlags extends FlagsDef> = keyof RecursiveFlags extends never ? ReplacedExtensionTree<Tree, Es, InheritedFlags> : TreeWithInheritedFlags<ReplacedExtensionTree<Tree, Es, InheritedFlags>, RecursiveFlags>;
682
+ /**
683
+ * Define a reusable, inert command under a required name.
684
+ *
685
+ * The recipe runs once per `.add()`, receiving a fresh builder.
686
+ *
687
+ * Static metadata belongs in `config`. Use `.as(name)`
688
+ * to add one definition under a different name; configured aliases travel with it.
689
+ */
690
+ declare function defineCommand<const Name extends string, Builder extends AnyCommandDefinitionBuilder>(name: Name & CommandNameBrand<Name>, recipe: CommandRecipe<Builder>): CommandDefinition<Name, readonly [], ShapeOfBuilder<Builder>, DepsOfBuilder<Builder>>;
691
+ declare function defineCommand<const Name extends string, const C extends CommandConfig, Builder extends AnyCommandDefinitionBuilder>(name: Name & CommandNameBrand<Name>, config: C & LocalCommandConfigBrand<Name, C>, recipe: CommandRecipe<Builder>): CommandDefinition<Name, AliasesOf<C>, ShapeOfBuilder<Builder>, DepsOfBuilder<Builder>>;
692
+ /**
693
+ * Chainable builder for defining CLI commands with full type inference.
694
+ *
695
+ * Generic parameters:
696
+ * - `Flags` — flags defined locally or installed by provided Contexts
697
+ * - `A` — positional argument definitions
698
+ * - `Ctx` — provided Context values
699
+ * - `Sibs` — sibling command names and aliases already registered
700
+ * - `Sp` — accumulated flag spellings used for collision checks
701
+ * - `Tree` — command shapes accumulated by `.add()` for typed `run()`
702
+ * - `CtxFlags` — Context-owned flags accumulated by `.provide()` and recursive
703
+ * Extension flags accumulated by `.extend()`, inherited by the shapes of
704
+ * definitions added afterwards
705
+ * - `Result` — awaited return type of this command's action
706
+ * - `Meta` — authored root metadata available to Extension requirements
707
+ * - `Caps` — root application or configure-only recipe capabilities
708
+ *
709
+ * @example
710
+ * ```ts
711
+ * const app = new Crust("my-cli")
712
+ * .flags({ name: "verbose", type: "boolean", short: "v" })
713
+ * .args({ name: "file", type: "string", required: true })
714
+ * .action(({ args, flags }) => {
715
+ * console.log(args.file, flags.verbose);
716
+ * });
717
+ * ```
718
+ */
719
+ type CollisionSpellings<Extensions extends string = never, Tree extends string = never, Demands extends ContextMap = {}, Pending extends string = never, RecipeDeps extends ContextMap = {}, Providers extends Record<string, ContextValue> = {}, ActionDeps extends ContextMap = {}> = {
720
+ readonly actionDeps: ActionDeps;
721
+ readonly pending: Pending;
722
+ readonly demands: Demands;
723
+ readonly extension: Extensions;
724
+ readonly tree: Tree;
725
+ readonly recipeDeps: RecipeDeps;
726
+ readonly providers: Providers;
727
+ };
728
+ type AnyCollisionSpellings = {
729
+ readonly actionDeps?: ContextMap;
730
+ readonly pending: string;
731
+ readonly demands: ContextMap;
732
+ readonly extension: string;
733
+ readonly tree: string;
734
+ readonly recipeDeps?: ContextMap;
735
+ readonly providers?: Record<string, ContextValue>;
736
+ };
737
+ type RecipeDepsOf<S extends AnyCollisionSpellings> = S extends {
738
+ readonly recipeDeps: infer Deps extends ContextMap;
739
+ } ? Deps : {};
740
+ type ProvidersOf<S extends AnyCollisionSpellings> = S extends {
741
+ readonly providers: infer Providers extends Record<string, ContextValue>;
742
+ } ? Providers : {};
743
+ /** Obligations of this node's stored action, never inherited by descendants. */
744
+ type ActionDepsOf<S extends AnyCollisionSpellings> = S extends {
745
+ readonly actionDeps: infer Deps extends ContextMap;
746
+ } ? Deps : {};
747
+ type AfterFlags<Flags extends FlagsDef, A extends ArgsDef, Ctx extends ContextMap, Sibs extends string, Sp extends string, Tree extends object, CtxFlags extends FlagsDef, CollisionSp extends AnyCollisionSpellings, Result, Defs extends readonly NamedFlagDef[], Meta extends RootCommandMeta | undefined, Caps extends "app" | "recipe"> = Crust<MergeFlags<Flags, AttachedFlags<Defs>>, A, Ctx, Sibs, Sp | AttachedSpellings<Defs>, Tree, CtxFlags, CollisionSp, Result, Meta, string, Caps>;
748
+ type AfterArgs<Flags extends FlagsDef, A extends ArgsDef, Ctx extends ContextMap, Sibs extends string, Sp extends string, Tree extends object, CtxFlags extends FlagsDef, CollisionSp extends AnyCollisionSpellings, Result, NewA extends ArgsDef, Meta extends RootCommandMeta | undefined, Caps extends "app" | "recipe"> = Crust<Flags, AppendedArgs<A, NewA>, Ctx, Sibs, Sp, Tree, CtxFlags, CollisionSp, Result, Meta, string, Caps>;
749
+ type AfterUse<Flags extends FlagsDef, A extends ArgsDef, Ctx extends ContextMap, Sibs extends string, Sp extends string, Tree extends object, CtxFlags extends FlagsDef, CollisionSp extends AnyCollisionSpellings, Result, Fs extends readonly AnyContextFactory[], Meta extends RootCommandMeta | undefined> = Crust<Flags, A, MergeContext<Ctx, ContextDependencies<Fs>>, Sibs, Sp, Tree, CtxFlags, CollisionSpellings<CollisionSp["extension"], CollisionSp["tree"], CollisionSp["demands"], CollisionSp["pending"], MergeContext<RecipeDepsOf<CollisionSp>, ContextDependencies<Fs>>, ProvidersOf<CollisionSp>, ActionDepsOf<CollisionSp>>, Result, Meta, string, "recipe">;
750
+ type AfterProvide<Flags extends FlagsDef, A extends ArgsDef, Ctx extends ContextMap, Sibs extends string, Sp extends string, Tree extends object, CtxFlags extends FlagsDef, CollisionSp extends AnyCollisionSpellings, Result, Cs extends readonly AnyContextInstance[], Meta extends RootCommandMeta | undefined, Caps extends "app" | "recipe"> = Crust<MergeFlags<Flags, ContextsOwnedFlags<Cs>>, A, MergeProviders<Ctx, ContextsOutput<Cs>>, Sibs, Sp | LocalSpellingsOf<ContextsOwnedFlags<Cs>>, Tree, MergeFlags<CtxFlags, ContextsOwnedFlags<Cs>>, CollisionSpellings<CollisionSp["extension"], CollisionSp["tree"], CollisionSp["demands"], CollisionSp["pending"], RecipeDepsOf<CollisionSp>, MergeProviders<ProvidersOf<CollisionSp>, ContextsOutput<Cs>>, ActionDepsOf<CollisionSp>>, Result, Meta, string, Caps>;
751
+ type AfterAction<Flags extends FlagsDef, A extends ArgsDef, Ctx extends ContextMap, Sibs extends string, Sp extends string, Tree extends object, CtxFlags extends FlagsDef, CollisionSp extends AnyCollisionSpellings, R, Meta extends RootCommandMeta | undefined, Caps extends "app" | "recipe"> = Crust<Flags, A, Ctx, Sibs, Sp, Tree, CtxFlags, Omit<CollisionSp, "actionDeps"> & {
752
+ readonly actionDeps: Ctx;
753
+ }, Awaited<R>, Meta, string, Caps>;
754
+ type AfterExtend<Flags extends FlagsDef, A extends ArgsDef, Ctx extends ContextMap, Sibs extends string, Sp extends string, Tree extends object, CtxFlags extends FlagsDef, CollisionSp extends AnyCollisionSpellings, Result, Es extends readonly AnyExtension[], Meta extends RootCommandMeta | undefined, Caps extends "app" | "recipe"> = Crust<MergeFlags<Flags, ExtensionFlags<Es>>, A, MergeProviders<Ctx, ExtensionsProvidesOutput<Es>>, Sibs | ExtensionsCommandSpellings<Es>, Sp | ExtensionsSpellings<Es>, ExtendedTree<Tree, Es, RecursiveExtensionFlags<Es>, CtxFlags>, MergeFlags<CtxFlags, RecursiveExtensionFlags<Es>>, CollisionSpellings<CollisionSp["extension"] | ExtensionsSpellings<Es>, CollisionSp["tree"] | DefinitionTreeSpellings<ExtensionCommands<Es>>, CollisionSp["demands"] & ExtensionDemandValues<Es>, CollisionSp["pending"] | DefinitionTreeSpellings<ExtensionCommands<Es>>, RecipeDepsOf<CollisionSp>, MergeProviders<ProvidersOf<CollisionSp>, ExtensionsProvidesOutput<Es>>, ActionDepsOf<CollisionSp>>, Result, Meta, string, Caps>;
755
+ type AfterAdd<Flags extends FlagsDef, A extends ArgsDef, Ctx extends ContextMap, Sibs extends string, Sp extends string, Tree extends object, CtxFlags extends FlagsDef, CollisionSp extends AnyCollisionSpellings, Result, Ds extends readonly CommandDefinition<any, any, any, any>[], Meta extends RootCommandMeta | undefined, Caps extends "app" | "recipe"> = Crust<Flags, A, Ctx, Sibs | AttachedCommandSpellings<Ds>, Sp, Tree & DefinitionsTree<Ds, CtxFlags>, CtxFlags, CollisionSpellings<CollisionSp["extension"], CollisionSp["tree"] | DefinitionTreeSpellings<Ds>, CollisionSp["demands"], CollisionSp["pending"], RecipeDepsOf<CollisionSp>, ProvidersOf<CollisionSp>, ActionDepsOf<CollisionSp>>, Result, Meta, string, Caps>;
756
+ type ExtensionDemandValues<Es extends readonly AnyExtension[]> = UnionToIntersection<DefiningOf<Es[number]> extends {
757
+ readonly _hookDeps?: infer H extends ContextMap;
758
+ } ? H : Record<string, ContextValue>> extends (infer D extends ContextMap) ? D : {};
759
+ type DescendantShapeValuesBrand<S, Deps> = S extends CommandShape ? DeclaredDependencyValuesBrand<Deps, NonNullable<S[typeof commandProviders]>> & DescendantValuesBrand<S["children"], Deps> : {};
760
+ type DescendantValuesBrand<Tree, Deps> = keyof Deps extends never ? {} : UnionToIntersection<Tree extends unknown ? keyof Tree extends never ? {} : { [K in keyof Tree]: DescendantShapeValuesBrand<Tree[K], Deps>; }[keyof Tree] : never>;
761
+ type DefinitionDescendantValuesBrand<Ds extends readonly CommandDefinition<any, any, any, any>[], Deps> = DescendantValuesBrand<DefinitionsTree<Ds>, Deps>;
762
+ type ValidateInlineCommandDeps<Ctx extends ContextMap, B> = MissingDeclaredDependencyBrand<{
763
+ readonly _deps?: DepsOfBuilder<B>;
764
+ }, keyof Ctx & string> & DeclaredDependencyValuesBrand<DepsOfBuilder<B>, Ctx>;
765
+ /** Completed applications expose inspection and invocation, not authoring after erasure. */
766
+ type AnyCrust = Pick<Crust<FlagsDef, ArgsDef, Record<string, ContextValue>, string, string, CommandTree, FlagsDef, AnyCollisionSpellings, unknown, RootCommandMeta>, "_types" | "run" | "execute" | "snapshot">;
767
+ type DefinedRootMetaKeys<Meta extends RootCommandMeta | undefined> = { [K in RootMetaKey]: [Meta] extends [Required<Pick<RootCommandMeta, K>>] ? K : never; }[RootMetaKey];
768
+ declare class Crust<Flags extends FlagsDef = {}, A extends ArgsDef = [], Ctx extends ContextMap = {}, Sibs extends string = never, Sp extends string = LocalSpellingsOf<Flags>, Tree extends object = {}, CtxFlags extends FlagsDef = {}, CollisionSp extends AnyCollisionSpellings = CollisionSpellings, Result = void, const out Meta extends RootCommandMeta | undefined = {}, const Name extends string = string, Caps extends "app" | "recipe" = "app"> {
769
+ private readonly _contextProof;
770
+ /** @internal — recipe state, without structural inference through builder methods. */
771
+ readonly _recipeTypes: {
772
+ readonly shape: CommandShape<A, Flags, Tree, Result, ProvidersOf<CollisionSp>>;
773
+ readonly deps: RecipeDepsOf<CollisionSp>;
774
+ readonly proof?: (state: [CommandInputShape<CommandShape<A, Flags, Tree, Result, ProvidersOf<CollisionSp>>>, RecipeDepsOf<CollisionSp>]) => void;
775
+ };
776
+ /** Supported type-level seam exposing the application's inferred command types. */
777
+ readonly _types: {
778
+ flags: Flags;
779
+ args: A;
780
+ ctx: Ctx;
781
+ tree: Tree;
782
+ shape: CommandShape<A, Flags, Tree, Result>;
783
+ readonly rootMeta: Meta;
784
+ readonly caps: Caps;
785
+ };
786
+ /** @internal */
787
+ _node: CommandNode;
788
+ /** @internal — Recipe-builder lineage anchor, unique per materialization and preserved by clones */
789
+ _ancestorOwnedFlags: FlagsDef;
790
+ /**
791
+ * Create a new root command builder.
792
+ *
793
+ * @param name - The command name.
794
+ * @param metadata - Optional root description, version, usage, and documentation sections.
795
+ */
796
+ constructor(nameInput: (Name & CommandNameBrand<Name>) & ({} extends Meta ? {} : {
797
+ readonly FIX_ROOT_META: "This root requires metadata";
798
+ }));
799
+ constructor(nameInput: Name & CommandNameBrand<Name>, meta: Meta & (undefined | (RootCommandMeta & LocalSectionsBrand<NoInfer<NonNullable<Meta>>> & { [K in Exclude<keyof Meta, RootMetaKey>]: never; })));
800
+ /** @internal — Clone this builder with a new node, preserving generics. */
801
+ _clone<Out = this>(nodeOverrides: Partial<CommandNode>): Out;
802
+ /**
803
+ * Define local flags for this command from named flag definitions
804
+ * (created with `defineFlag(name, def)` or written inline as
805
+ * `{ name: "dry-run", type: "boolean" }`).
806
+ *
807
+ * Repeated `.flags()` calls accumulate local flags. Returns a new builder
808
+ * with the combined local flag types. The original builder is not mutated.
809
+ *
810
+ * @param defs - Named flag definitions
811
+ * @returns A new `Crust` instance with the given flags
812
+ */
813
+ flags<const Defs extends readonly NamedFlagDef[], _Union extends this = never>(...defs: ValidateLocalFlagDefs<Defs, Sp>): AfterFlags<Flags, A, Ctx, Sibs, Sp, Tree, CtxFlags, CollisionSp, Result, Defs, Meta, Caps>;
814
+ /**
815
+ * Define positional arguments for this command; argument order is the
816
+ * order they are passed (created with `defineArg(name, def)` or written
817
+ * inline).
818
+ *
819
+ * Repeated `.args()` calls append in call order. Returns a new builder with
820
+ * the combined args types. The original builder is not mutated.
821
+ *
822
+ * @param defs - Positional argument definitions, in positional order
823
+ * @returns A new `Crust` instance with the combined args
824
+ */
825
+ args<const NewA extends ArgsDef, _Union extends this = never>(...defs: NewA & AppendArgsChecks<A, NewA>): AfterArgs<Flags, A, Ctx, Sibs, Sp, Tree, CtxFlags, CollisionSp, Result, NewA, Meta, Caps>;
826
+ /**
827
+ * Declare Contexts this command consumes without supplying their values.
828
+ * Factory references are retained while setup stays lazy.
829
+ */
830
+ use<const Fs extends readonly [AnyContextFactory, ...AnyContextFactory[]] = never>(this: {
831
+ readonly _types: {
832
+ readonly caps: "recipe";
833
+ };
834
+ }, ...factories: Fs & DeclaredDependencyValuesBrand<ContextDependencies<Fs>, ProvidersOf<CollisionSp>>): AfterUse<Flags, A, Ctx, Sibs, Sp, Tree, CtxFlags, CollisionSp, Result, Fs, Meta>;
835
+ /**
836
+ * Attach Contexts — named command dependencies — to this command.
837
+ *
838
+ * Contexts are inherited by descendant commands and constructed lazily when
839
+ * their `ctx` property is accessed. Dependency order within one call does not
840
+ * affect construction. Disposable values are released in
841
+ * reverse construction order after post-run hooks. TypeScript rejects known Context-owned flag collisions, including pending
842
+ * Extension commands. Consuming operations throw `DEFINITION` for actual collisions.
843
+ *
844
+ */
845
+ provide<const Cs extends readonly AnyContextInstance[] = never>(...instances: KnownContextInstances<Cs> & ProvideChecks<Sp | CollisionSp["pending"], Cs> & ValidateContextNames<Caps extends "recipe" ? ProvidersOf<CollisionSp> : Ctx, Cs> & ValidateContextDeps<Ctx, Cs> & DeclaredDependencyValuesBrand<CollisionSp["demands"] & RecipeDepsOf<CollisionSp> & ActionDepsOf<CollisionSp>, ContextsOutput<NoInfer<Cs>>>): AfterProvide<Flags, A, Ctx, Sibs, Sp, Tree, CtxFlags, CollisionSp, Result, Cs, Meta, Caps>;
846
+ /**
847
+ * Define the Command Action — the function that implements this
848
+ * command's behavior after its inputs are ready.
849
+ *
850
+ * The action receives a {@link CrustCommandContext} with `args` typed from
851
+ * `.args()` and `flags` typed from the accumulated `Flags`.
852
+ *
853
+ * Calling `.action()` again replaces the command behavior and its Context obligations
854
+ * on the new builder. Later local providers must satisfy the bound Context value types;
855
+ * descendants may shadow independently. The original builder is not mutated.
856
+ *
857
+ * @param action - The Command Action function
858
+ * @returns A new `Crust` instance with the action registered
859
+ */
860
+ action<R>(action: (ctx: NoInfer<CrustCommandContext<A, Flags, Ctx>>) => R): AfterAction<Flags, A, Ctx, Sibs, Sp, Tree, CtxFlags, CollisionSp, R, Meta, Caps>;
861
+ /**
862
+ * Register one or more CLI Extensions on the application root.
863
+ *
864
+ * Extensions are application-wide: they own the flags and commands they
865
+ * contribute. Repeated calls accumulate Extensions in registration order,
866
+ * except that registering an `ExtensionId` again keeps only the last
867
+ * registration — its contributions and providers replace the earlier ones
868
+ * and its hooks run once, at the later position. ID deduplication is
869
+ * runtime-only, so removed paths can remain statically visible and reject
870
+ * with `COMMAND_NOT_FOUND`. Canonical replacements use the new
871
+ * shape; open replacements and ambiguous aliases have unknown results.
872
+ * Required root metadata keys are checked against the constructor's inferred
873
+ * metadata by TypeScript, not at runtime.
874
+ * Recipe builders cannot call this root-only method.
875
+ */
876
+ extend<const Es extends readonly Extension<any, any, any, any, DefinedRootMetaKeys<Meta>>[], _Union extends this = never>(this: {
877
+ readonly _types: {
878
+ readonly caps: "app";
879
+ };
880
+ }, ...extensions: Es & { [I in keyof Es]: (ExtensionCommandDefs<Es[I]> extends ValidateDefinitionFlags<ExtensionCommandDefs<Es[I]>, LocalSpellingsOf<CtxFlags>> ? {} : {
881
+ readonly FIX_ALIAS_COLLISION: "Extension command flags collide with inherited Context flags";
882
+ }) & ValidateDeclaredDeps<MergeProviders<Ctx, ExtensionsProvidesOutput<Es>>, Es>[I] & DeclaredDependencyValuesBrand<CollisionSp["demands"], MergeProviders<Ctx, ExtensionsProvidesOutput<Es>>> & DescendantValuesBrand<Tree, ExtensionDemandValues<Es>> & DefinitionDescendantValuesBrand<ExtensionCommands<Es>, CollisionSp["demands"] & ExtensionDemandValues<Es>> & ExtensionCheckAt<ValidateExtensionFlags<Es, Sp | CollisionSp["tree"] | DefinitionTreeSpellings<ExtensionCommands<Es>>>, I> & ExtensionCheckAt<ValidateExtensionCommands<Es, Sibs>, I> & ExtensionCheckAt<ValidateExtensionProvides<Es, Ctx>, I>; }): AfterExtend<Flags, A, Ctx, Sibs, Sp, Tree, CtxFlags, CollisionSp, Result, Es, Meta, Caps>;
883
+ /**
884
+ * Materialize and register inert reusable command definitions, each
885
+ * under its own carried name (use `.as(name)` to rename).
886
+ *
887
+ */
888
+ add<const Ds extends readonly CommandDefinition<any, any, any, any>[] = never>(...definitions: Ds & ValidateCommandDefinitions<Ds, Sibs> & ValidateDeclaredDeps<Ctx, Ds> & DefinitionDescendantValuesBrand<Ds, CollisionSp["demands"]> & ValidateDefinitionFlags<Ds, CollisionSp["extension"] | LocalSpellingsOf<CtxFlags>>): AfterAdd<Flags, A, Ctx, Sibs, Sp, Tree, CtxFlags, CollisionSp, Result, Ds, Meta, Caps>;
889
+ /**
890
+ * Define an app-local leaf subcommand inline (root-only sugar for
891
+ * `.add(defineCommand(name, recipe))`).
892
+ *
893
+ * The recipe builder is seeded with the Contexts and Context-owned flags
894
+ * accumulated on this builder so far — the call site. Contexts provided
895
+ * after `.command()` are not visible to it, matching the positional runtime
896
+ * semantics of `.provide()`. Extract to `defineCommand` when a command needs
897
+ * its own file, reuse, or a package. Recipe builders cannot call this
898
+ * root-only method.
899
+ */
900
+ command<const N extends string, B extends AnyCommandDefinitionBuilder>(this: {
901
+ readonly _types: {
902
+ readonly caps: "app";
903
+ };
904
+ }, name: N & CommandNameBrand<N> & CommandCollisionBrand<N, Sibs>, recipe: ((command: CommandDefinitionBuilder<{}, [], Ctx, never, LocalSpellingsOf<CtxFlags>, {}, CtxFlags>) => B & ShapeFlagCollisionBrand<ShapeOfBuilder<B>, CollisionSp["extension"]> & ValidateInlineCommandDeps<Ctx, NoInfer<B>>) & NoInfer<DescendantValuesBrand<{
905
+ child: ShapeOfBuilder<B>;
906
+ }, CollisionSp["demands"]>>): AfterAdd<Flags, A, Ctx, Sibs, Sp, Tree, CtxFlags, CollisionSp, Result, readonly [CommandDefinition<N, readonly [], ShapeOfBuilder<B>, DepsOfBuilder<B>>], Meta, Caps>;
907
+ private _addDefinitions;
908
+ /**
909
+ * Prepare a frozen Command Snapshot for tooling such as man-page, skill,
910
+ * and build generators.
911
+ *
912
+ * Materializes Extension contributions and command definitions without
913
+ * calling Command Actions.
914
+ */
915
+ snapshot(this: {
916
+ readonly _types: {
917
+ readonly caps: "app";
918
+ };
919
+ }): Promise<CommandSnapshot>;
920
+ /**
921
+ * Programmatically invoke a typed command, quietly capturing its output.
922
+ * Returns completed, finished, or failed after cleanup without presenting errors.
923
+ * Use {@link execute} as the streaming terminal adapter.
924
+ *
925
+ * @param path - Typed path to the command to invoke (`[]` selects the root)
926
+ * @param input - Structured argument, flag, and raw values
927
+ * @param io - Optional `stdout(text)` / `stderr(text)` callbacks, also
928
+ * exposed to Command Actions and Extensions
929
+ */
930
+ run<const Path extends CommandPath<Tree>>(this: {
931
+ readonly _types: {
932
+ readonly caps: "app";
933
+ };
934
+ }, path: Path & KnownCommandPath<Path, Tree>, ...args: RunArguments<CommandShapeAt<CommandShape<A, Flags, Tree, Result>, Path>>): Promise<RunOutcome<CommandShapeAt<CommandShape<A, Flags, Tree, Result>, Path>["result"]>>;
935
+ run<const Path extends CommandPath<Tree>, const Input>(this: {
936
+ readonly _types: {
937
+ readonly caps: "app";
938
+ };
939
+ }, path: Path & KnownCommandPath<Path, Tree>, input: Input, ...validation: [Input] extends [CompatibleRunInput<CommandShapeAt<CommandShape<A, Flags, Tree, Result>, NoInfer<Path>>, Input>] ? readonly [io?: Partial<InvocationIO>] : readonly [invalidInput: never]): Promise<RunOutcome<CommandShapeAt<CommandShape<A, Flags, Tree, Result>, Path>["result"]>>;
940
+ /**
941
+ * Bind a typed command path into a reusable {@link CommandHandle}.
942
+ *
943
+ * Validates the path eagerly against the prepared command tree, so an
944
+ * unknown path throws `COMMAND_NOT_FOUND` here rather than on the first
945
+ * `handle.run()`. The handle is bound to this builder's tree; commands added
946
+ * afterwards belong to the new builder returned by `.add()`.
947
+ *
948
+ * @param path - Typed path to the command to bind (`[]` selects the root)
949
+ * @throws {CrustError} COMMAND_NOT_FOUND when the path does not name a command
950
+ */
951
+ at<const Path extends CommandPath<Tree>>(this: {
952
+ readonly _types: {
953
+ readonly caps: "app";
954
+ };
955
+ }, path: Path & KnownCommandPath<Path, Tree>): CommandHandle<CommandShapeAt<CommandShape<A, Flags, Tree, Result>, Path>>;
956
+ /**
957
+ * Parse `process.argv`, resolve subcommands, run Extension hooks, and
958
+ * execute the matched Command Action.
959
+ *
960
+ * This is the terminal CLI boundary — call it on the root builder. It
961
+ * renders a failure once (through Extension `onError` hooks, ending in
962
+ * Core's default renderer), sets `process.exitCode` (`1`, or
963
+ * `130` for an `AbortError` cancellation), and resolves to the exit code.
964
+ *
965
+ * @param options - Optional overrides (e.g. custom `argv` and captured
966
+ * `io` for in-process testing of exit codes and
967
+ * rendered failures)
968
+ * @returns The terminal exit code (`0`, `1`, or `130` for cancellation)
969
+ */
970
+ execute(this: {
971
+ readonly _types: {
972
+ readonly caps: "app";
973
+ };
974
+ }, options?: {
975
+ argv?: string[];
976
+ io?: Partial<InvocationIO>;
977
+ }): Promise<number>;
978
+ }
979
+ //#endregion
980
+ //#region src/errors.d.ts
981
+ /** A value thrown by user code crossing a Core error boundary. */
982
+ type CaughtError = unknown;
983
+ /** Details for a subcommand token that could not be resolved. */
984
+ interface CommandNotFoundErrorDetails {
985
+ /** Unrecognized subcommand token. */
986
+ input: string;
987
+ /** Canonical names of visible available child commands. */
988
+ available: string[];
989
+ /** Canonical path to the command whose child could not be resolved. */
990
+ commandPath: string[];
991
+ /** Readonly, serializable snapshot of the parent command. */
992
+ parentCommand: CommandSnapshot;
993
+ }
994
+ /** Aggregated Standard Schema and required-value validation failures. */
995
+ interface ValidationErrorDetails {
996
+ /** Issues normalized under `args.<name>` or `flags.<name>`. */
997
+ issues: readonly {
998
+ readonly message: string;
999
+ readonly path: string;
1000
+ }[];
1001
+ }
1002
+ /** Details for argv syntax or built-in value parsing failures. */
1003
+ interface ParseErrorDetails {
1004
+ readonly flag?: string;
1005
+ readonly argument?: string;
1006
+ /** Retained for compatibility; Core no longer populates this field. */
1007
+ readonly value?: string;
1008
+ readonly reason?: string;
1009
+ }
1010
+ /** Details for runtime recipe, Extension, Context, and documentation failures. */
1011
+ interface DefinitionErrorDetails {
1012
+ readonly subject?: "command" | "context" | "extension" | "flag" | "argument";
1013
+ readonly name?: string;
1014
+ readonly reason?: string;
1015
+ }
1016
+ interface CrustErrorDetailsMap {
1017
+ DEFINITION: DefinitionErrorDetails | undefined;
1018
+ VALIDATION: ValidationErrorDetails | undefined;
1019
+ PARSE: ParseErrorDetails | undefined;
1020
+ COMMAND_NOT_FOUND: CommandNotFoundErrorDetails;
1021
+ }
1022
+ /**
1023
+ * All possible error codes emitted by Crust.
1024
+ *
1025
+ * - `DEFINITION` — Runtime recipe, Extension, Context, or documentation definition failure
1026
+ * - `VALIDATION` — Missing required arguments or flags
1027
+ * - `PARSE` — Argv parsing failures (unknown flags, type coercion)
1028
+ * - `COMMAND_NOT_FOUND` — Unrecognised subcommand at the current level
1029
+ *
1030
+ * @example
1031
+ * ```ts
1032
+ * const outcome = await app.run(path, input);
1033
+ * if (outcome.status === "failed") {
1034
+ * const err = outcome.error;
1035
+ * if (err instanceof CrustError) {
1036
+ * switch (err.code) {
1037
+ * case "VALIDATION":
1038
+ * console.error(err.message);
1039
+ * showHelp(cmd);
1040
+ * break;
1041
+ * case "PARSE":
1042
+ * console.error(err.message);
1043
+ * break;
1044
+ * }
1045
+ * }
1046
+ * }
1047
+ * ```
1048
+ */
1049
+ type CrustErrorCode = keyof CrustErrorDetailsMap;
1050
+ type CrustErrorDetails<C extends CrustErrorCode> = CrustErrorDetailsMap[C];
1051
+ interface CrustErrorJson<C extends CrustErrorCode> {
1052
+ code: C;
1053
+ message: string;
1054
+ details: CrustErrorDetails<C>;
1055
+ }
1056
+ /**
1057
+ * A typed error for runtime recipe, Extension, Context, documentation, argv, and validation failures.
1058
+ *
1059
+ * Every `CrustError` carries a {@link CrustErrorCode} that identifies the specific
1060
+ * failure, enabling programmatic error handling without fragile message parsing.
1061
+ *
1062
+ * @example
1063
+ * ```ts
1064
+ * import { CrustError } from "@crustjs/core";
1065
+ *
1066
+ * const outcome = await app.run(["deploy"], { args: { target: "prod" } });
1067
+ * if (outcome.status === "failed") {
1068
+ * const err = outcome.error;
1069
+ * if (err instanceof CrustError) {
1070
+ * console.error(`[${err.code}] ${err.message}`);
1071
+ * }
1072
+ * }
1073
+ * ```
1074
+ */
1075
+ declare class CrustError<C extends CrustErrorCode = CrustErrorCode> extends Error {
1076
+ /** Machine-readable error code for programmatic handling */
1077
+ readonly code: C;
1078
+ /** Structured payload for programmatic handling */
1079
+ readonly details: CrustErrorDetails<C>;
1080
+ /** Optional wrapped original error/value */
1081
+ override cause?: unknown;
1082
+ constructor(code: C, message: string, ...details: undefined extends CrustErrorDetails<C> ? [] | [CrustErrorDetails<C>] : [CrustErrorDetails<C>]);
1083
+ is<T extends CrustErrorCode>(code: T): this is CrustError<T>;
1084
+ withCause(cause: unknown): this;
1085
+ toJSON(): CrustErrorJson<C>;
1086
+ }
1087
+ //#endregion
1088
+ //#region src/api/extension.d.ts
1089
+ declare const finishedBrand: unique symbol;
1090
+ /** Opaque token returned by {@link ExtensionContext.finish} to end an invocation successfully. */
1091
+ interface Finished {
1092
+ readonly [finishedBrand]: true;
1093
+ }
1094
+ type InvocationOutcome = {
1095
+ readonly status: "completed";
1096
+ } | {
1097
+ readonly status: "finished";
1098
+ readonly by: ExtensionId;
1099
+ } | {
1100
+ readonly status: "failed";
1101
+ readonly error: unknown;
1102
+ readonly by?: ExtensionId;
1103
+ };
1104
+ /** Authored root metadata fields an Extension may require. */
1105
+ type RootMetaKey = keyof RootCommandMeta;
1106
+ type RootCommandSnapshot<K extends RootMetaKey> = CommandSnapshot & {
1107
+ readonly meta: Readonly<Required<Pick<CommandMeta, K>>>;
1108
+ };
1109
+ /** One file a build hook produces; `path` is POSIX-relative to the build output directory. */
1110
+ interface BuildFile {
1111
+ readonly path: string;
1112
+ readonly content: string | Uint8Array;
1113
+ }
1114
+ /** Files returned by a build hook; build tooling writes them into the build output directory. */
1115
+ type BuildArtifacts = readonly BuildFile[];
1116
+ /** Files written for each Extension build hook, in hook execution order. */
1117
+ interface BuildReport {
1118
+ readonly extensions: readonly {
1119
+ readonly id: ExtensionId;
1120
+ readonly files: readonly string[];
1121
+ }[];
1122
+ }
1123
+ /**
1124
+ * Build-time context passed to an Extension's artifact generator. It deliberately
1125
+ * carries no output directory: build tooling owns that tree, so every shipped file
1126
+ * is a returned {@link BuildFile} and the {@link BuildReport} is exact.
1127
+ */
1128
+ interface ExtensionBuildContext<MetaKeys extends RootMetaKey = never> {
1129
+ /**
1130
+ * Frozen snapshot prepared before this hook starts. It does not include this hook's own
1131
+ * outputs; later-registered hooks receive refreshed snapshots.
1132
+ */
1133
+ readonly snapshot: RootCommandSnapshot<MetaKeys>;
1134
+ }
1135
+ /**
1136
+ * Readonly invocation view passed to Extension hooks.
1137
+ *
1138
+ * Commands cross this boundary as readonly, serializable
1139
+ * {@link CommandSnapshot}s — never as internal command nodes.
1140
+ *
1141
+ * Examples below assume the `tool deploy api --trace -- --dry-run` invocation.
1142
+ */
1143
+ interface ExtensionContext<Defs extends readonly NamedExtensionFlagDef[] = [], Deps extends ContextMap = {}, MetaKeys extends RootMetaKey = never> extends Readonly<InvocationIO> {
1144
+ /**
1145
+ * Complete argv passed to the application, including routed command names.
1146
+ * For typed `run()` this is the command path only; structured values are never rendered as argv.
1147
+ *
1148
+ * @example `["deploy", "api", "--trace", "--", "--dry-run"]`
1149
+ */
1150
+ readonly argv: readonly string[];
1151
+ /**
1152
+ * Snapshot of the application root, including Extension-contributed flags/commands.
1153
+ *
1154
+ * @example
1155
+ * ```ts
1156
+ * ctx.rootCommand.meta.name; // "tool"
1157
+ * Object.keys(ctx.rootCommand.subCommands); // ["deploy"]
1158
+ * ```
1159
+ */
1160
+ readonly rootCommand: RootCommandSnapshot<MetaKeys>;
1161
+ /**
1162
+ * Snapshot of the resolved command (the root when routing failed).
1163
+ *
1164
+ * @example
1165
+ * ```ts
1166
+ * ctx.command.meta.name; // "deploy"
1167
+ * ctx.command.args; // [{ name: "target", type: "string", required: true }]
1168
+ * ```
1169
+ */
1170
+ readonly command: CommandSnapshot;
1171
+ /**
1172
+ * Canonical names from the application root through the resolved command.
1173
+ *
1174
+ * @example `["tool", "deploy"]`
1175
+ */
1176
+ readonly commandPath: readonly string[];
1177
+ /**
1178
+ * Bound positional values for the resolved command, before validation: parsed from
1179
+ * argv tokens for `execute()`, taken as-is from the structured input for typed `run()`
1180
+ * (URL/JSON values keep their identity).
1181
+ *
1182
+ * @example `{ target: "api" }`
1183
+ */
1184
+ readonly args: Readonly<Record<string, ParsedArgValue>>;
1185
+ /**
1186
+ * Bound own flags plus unknown flags from the resolved command, before validation;
1187
+ * parsed from argv tokens for `execute()`, taken as-is from the structured input for typed `run()`.
1188
+ *
1189
+ * @example `{ trace: true }`
1190
+ */
1191
+ readonly flags: Readonly<InferExtensionFlags<Defs> & Record<string, ParsedFlagValue>>;
1192
+ /**
1193
+ * Positional values that appeared after the `--` separator, or the `raw` array passed to typed `run()`.
1194
+ *
1195
+ * @example `["--dry-run"]`
1196
+ */
1197
+ readonly rawArgs: readonly string[];
1198
+ /** Declared Contexts, constructed lazily on first property access. */
1199
+ readonly ctx: ContextBag<Deps>;
1200
+ /**
1201
+ * End the invocation successfully before validation, Context construction, and the action.
1202
+ *
1203
+ * @example
1204
+ * ```ts
1205
+ * preRun(ctx) {
1206
+ * if (ctx.flags.help === true) return ctx.finish();
1207
+ * }
1208
+ * ```
1209
+ */
1210
+ readonly finish: () => Finished;
1211
+ }
1212
+ interface ExtensionHooks<Defs extends readonly NamedExtensionFlagDef[] = [], Deps extends ContextMap = {}, MetaKeys extends RootMetaKey = never> {
1213
+ /**
1214
+ * Runs after routing and input binding (argv parsing for `execute()`, structured
1215
+ * binding for typed `run()`), before validation, in `.extend()` order.
1216
+ * Return `ctx.finish()` to end the invocation successfully; later pre-run hooks,
1217
+ * validation, schemas, Contexts, and the Command Action do not run.
1218
+ */
1219
+ readonly preRun?: (ctx: ExtensionContext<Defs, Deps, MetaKeys>) => Awaitable<void | Finished>;
1220
+ /**
1221
+ * Runs after the invocation settles, in reverse `.extend()` order. This is the
1222
+ * `finally` slot for cleanup and post-run side effects.
1223
+ */
1224
+ readonly postRun?: (ctx: ExtensionContext<Defs, Deps, MetaKeys>, outcome: InvocationOutcome) => Awaitable<void>;
1225
+ /**
1226
+ * Renders a failure in `execute()` only. Return true when rendered to stop the
1227
+ * chain; falsy values delegate to the next Extension and then Core's renderer.
1228
+ * A hook that throws ends the chain: remaining hooks are skipped and Core's
1229
+ * default renderer reports the original failure.
1230
+ *
1231
+ * Receives the base context: routing or syntax-parse failures render with a
1232
+ * fallback context whose `flags` are empty, so owned-flag inference would lie here.
1233
+ */
1234
+ readonly onError?: (error: CaughtError, ctx: ExtensionContext<[], Deps, MetaKeys>) => Awaitable<boolean | void>;
1235
+ }
1236
+ /**
1237
+ * A flag owned by an Extension. `recursive` (default `true`) contributes the
1238
+ * flag to every command in the application; set `false` for a root-only flag.
1239
+ */
1240
+ type ExtensionFlagDef = FlagDef & {
1241
+ readonly recursive?: boolean;
1242
+ };
1243
+ /** A named flag definition accepted by {@link defineExtension}. */
1244
+ type NamedExtensionFlagDef = NamedFlagDef & {
1245
+ readonly recursive?: boolean;
1246
+ };
1247
+ type SchemaToken<F> = F extends {
1248
+ type: "boolean";
1249
+ } ? boolean : string;
1250
+ type InferPreSchemaExtensionFlag<F extends ExtensionFlagDef> = F extends {
1251
+ schema: unknown;
1252
+ } ? (F extends {
1253
+ multiple: true;
1254
+ } ? never : SchemaToken<F>) | ("multiple" extends keyof F ? true extends F["multiple"] ? SchemaToken<F>[] : never : never) | undefined : F extends {
1255
+ required: true;
1256
+ } ? F extends {
1257
+ default: unknown;
1258
+ } ? InferFlags<{
1259
+ value: F;
1260
+ }>["value"] : InferFlags<{
1261
+ value: F;
1262
+ }>["value"] | undefined : InferFlags<{
1263
+ value: F;
1264
+ }>["value"];
1265
+ type InferExtensionFlag<F> = F extends ExtensionFlagDef ? InferPreSchemaExtensionFlag<F> | ("recursive" extends keyof F ? (false extends F["recursive"] ? undefined : never) : never) : never;
1266
+ /** Infer pre-validation hook values; uncertain collections claim no typed ownership. */
1267
+ type InferExtensionFlags<Defs extends readonly NamedExtensionFlagDef[]> = IsStaticTuple<Defs> extends true ? HasClosedNames<Defs> extends true ? { [K in keyof NamedFlagsRecord<Defs>]: InferExtensionFlag<NamedFlagsRecord<Defs>[K]>; } : Record<string, ParsedFlagValue> : Record<string, ParsedFlagValue>;
1268
+ /** A documentation section an Extension contributes to one command path. */
1269
+ type ExtensionSectionContribution = RuntimeCommandSectionInput & {
1270
+ readonly command: readonly string[];
1271
+ };
1272
+ type CommandDefinitionsDependencies<Commands extends readonly CommandDefinition<any, any, any, any>[]> = Commands extends readonly [infer H extends CommandDefinition<any, any, any, any>, ...infer T extends readonly CommandDefinition<any, any, any, any>[]] ? ([H] extends [never] ? {} : DeclaredDepsOf<H>) & CommandDefinitionsDependencies<T> : Commands extends readonly [] ? {} : Record<string, ContextValue>;
1273
+ interface ExtensionConfig<Defs extends readonly NamedExtensionFlagDef[] = readonly NamedExtensionFlagDef[], Uses extends readonly AnyContextFactory[] = readonly AnyContextFactory[], Provides extends readonly AnyContextInstance[] = readonly AnyContextInstance[], Commands extends readonly CommandDefinition<any, any, any, any>[] = readonly CommandDefinition<any, any, any, any>[], MetaKeys extends RootMetaKey = never> {
1274
+ readonly flags?: Defs;
1275
+ readonly commands?: Commands;
1276
+ readonly uses?: Uses;
1277
+ readonly provides?: Provides;
1278
+ readonly sections?: (snapshot: RootCommandSnapshot<MetaKeys>) => readonly ExtensionSectionContribution[];
1279
+ readonly build?: (ctx: ExtensionBuildContext<MetaKeys>) => Awaitable<BuildArtifacts>;
1280
+ readonly hooks?: ExtensionHooks<Defs, ContextDependencies<Uses>, MetaKeys>;
1281
+ }
1282
+ type ValidateExtensionConfig<Defs extends readonly NamedExtensionFlagDef[], Provides extends readonly AnyContextInstance[], Commands extends readonly CommandDefinition<any, any, any, any>[], Uses extends readonly AnyContextFactory[]> = {
1283
+ readonly uses?: Uses;
1284
+ readonly commands?: ValidateCommandDefinitions<Commands>;
1285
+ readonly flags?: ValidateLocalFlagDefs<Defs, ProvidedContextSpellings<Provides>>;
1286
+ readonly provides?: KnownContextInstances<Provides> & ProvideChecks<never, Provides>;
1287
+ };
1288
+ declare const extensionHookProof: unique symbol;
1289
+ interface Extension<Deps extends ContextMap = ContextMap, Provides extends readonly AnyContextInstance[] = readonly AnyContextInstance[], FlagDefs extends readonly NamedExtensionFlagDef[] = readonly NamedExtensionFlagDef[], Commands extends readonly CommandDefinition<any, any, any, any>[] = readonly CommandDefinition<any, any, any, any>[], out MetaKeys extends RootMetaKey = never, HookDeps extends ContextMap = Deps> extends Defining<Extension<Deps, Provides, FlagDefs, Commands, MetaKeys, HookDeps>> {
1290
+ /** @internal Hook demands are distinct from command/provider attachment dependencies. */
1291
+ readonly _hookDeps?: HookDeps;
1292
+ readonly [extensionHookProof]?: (deps: HookDeps) => void;
1293
+ readonly id: ExtensionId;
1294
+ readonly flags?: Readonly<Record<string, ExtensionFlagDef>>;
1295
+ /** @internal — phantom carrying declared flag literals for extend-time collision checks */
1296
+ readonly _flagDefs?: FlagDefs;
1297
+ readonly commands?: Commands;
1298
+ readonly uses: readonly AnyContextFactory[];
1299
+ readonly provides?: Provides;
1300
+ readonly sections?: (snapshot: RootCommandSnapshot<MetaKeys>) => readonly ExtensionSectionContribution[];
1301
+ readonly build?: (ctx: ExtensionBuildContext<MetaKeys>) => Awaitable<BuildArtifacts>;
1302
+ readonly hooks?: ExtensionHooks<any, Deps, MetaKeys>;
1303
+ readonly _deps?: Deps;
1304
+ }
1305
+ /** @internal Broad Extension constraint; contravariance requires the full metadata key set. */
1306
+ type AnyExtension = Extension<any, any, any, any, RootMetaKey>;
1307
+ type ExtensionProvidesOutput<E> = DefiningOf<E> extends Extension<any, infer Provides, any, any, RootMetaKey> ? ContextsOutput<Provides> : {};
1308
+ type ExtensionsProvidesOutput<Es extends readonly AnyExtension[]> = Es extends readonly [infer H, ...infer T extends readonly AnyExtension[]] ? MergeProviders<ExtensionProvidesOutput<H>, ExtensionsProvidesOutput<T>> : Es extends readonly [] ? {} : Es[number] extends Extension<any, infer P, any, any, RootMetaKey> ? P[number] extends never ? {} : Record<string, ContextValue> : {};
1309
+ /**
1310
+ * A callable Extension constructor whose identity is also a section consumer.
1311
+ * Contribution parameters default to closed sets. Use `ContextMap`,
1312
+ * `readonly AnyContextInstance[]`, `readonly NamedExtensionFlagDef[]`, or
1313
+ * `readonly CommandDefinition<any, any, any, any>[]` to keep a namespace open.
1314
+ */
1315
+ type ExtensionFactory<Args extends readonly unknown[] = [], Deps extends ContextMap = {}, Provides extends readonly AnyContextInstance[] = [], Defs extends readonly NamedExtensionFlagDef[] = [], Commands extends readonly CommandDefinition<any, any, any, any>[] = [], MetaKeys extends RootMetaKey = never, HookDeps extends ContextMap = Deps> = ((...args: Args) => Extension<Deps, Provides, Defs, Commands, MetaKeys, HookDeps>) & {
1316
+ readonly id: ExtensionId;
1317
+ };
1318
+ /** Curried Extension definer: explicit metadata keys leave all other types inferred. */
1319
+ interface DefineExtensionWith<MetaKeys extends RootMetaKey> {
1320
+ <Args extends readonly unknown[], const Defs extends readonly NamedExtensionFlagDef[] = [], const Uses extends readonly AnyContextFactory[] = [], const Provides extends readonly AnyContextInstance[] = [], const Commands extends readonly CommandDefinition<any, any, any, any>[] = []>(id: ExtensionId, factory: (...args: Args) => ExtensionConfig<Defs, Uses, Provides, Commands, MetaKeys> & ValidateExtensionConfig<Defs, Provides, Commands, Uses>): ExtensionFactory<Args, ContextDependencies<Uses> & ContextsDependencies<Provides> & CommandDefinitionsDependencies<Commands>, Provides, Defs, Commands, MetaKeys, ContextDependencies<Uses>>;
1321
+ <const Defs extends readonly NamedExtensionFlagDef[] = [], const Uses extends readonly AnyContextFactory[] = [], const Provides extends readonly AnyContextInstance[] = [], const Commands extends readonly CommandDefinition<any, any, any, any>[] = []>(id: ExtensionId, config?: ExtensionConfig<Defs, Uses, Provides, Commands, MetaKeys> & ValidateExtensionConfig<Defs, Provides, Commands, Uses>): Extension<ContextDependencies<Uses> & ContextsDependencies<Provides> & CommandDefinitionsDependencies<Commands>, Provides, Defs, Commands, MetaKeys, ContextDependencies<Uses>>;
1322
+ }
1323
+ /**
1324
+ * Define an Extension, or a factory that builds one from config on each call.
1325
+ *
1326
+ * Extensions apply to the whole application and own the flags and commands
1327
+ * they contribute. Factories expose the same identity for section audiences.
1328
+ * `defineExtension<"version">()(id, configOrFactory)` declares required root
1329
+ * metadata keys without preventing inference of flags, Contexts, or commands.
1330
+ */
1331
+ declare function defineExtension<MetaKeys extends RootMetaKey = never>(): DefineExtensionWith<MetaKeys>;
1332
+ declare function defineExtension<Args extends readonly unknown[], const Defs extends readonly NamedExtensionFlagDef[] = [], const Uses extends readonly AnyContextFactory[] = [], const Provides extends readonly AnyContextInstance[] = [], const Commands extends readonly CommandDefinition<any, any, any, any>[] = []>(id: ExtensionId, factory: (...args: Args) => ExtensionConfig<Defs, Uses, Provides, Commands> & ValidateExtensionConfig<Defs, Provides, Commands, Uses>): ExtensionFactory<Args, ContextDependencies<Uses> & ContextsDependencies<Provides> & CommandDefinitionsDependencies<Commands>, Provides, Defs, Commands, never, ContextDependencies<Uses>>;
1333
+ declare function defineExtension<const Defs extends readonly NamedExtensionFlagDef[] = [], const Uses extends readonly AnyContextFactory[] = [], const Provides extends readonly AnyContextInstance[] = [], const Commands extends readonly CommandDefinition<any, any, any, any>[] = []>(id: ExtensionId, config?: ExtensionConfig<Defs, Uses, Provides, Commands> & ValidateExtensionConfig<Defs, Provides, Commands, Uses>): Extension<ContextDependencies<Uses> & ContextsDependencies<Provides> & CommandDefinitionsDependencies<Commands>, Provides, Defs, Commands, never, ContextDependencies<Uses>>;
1334
+ //#endregion
1335
+ //#region src/parsing/spellings.d.ts
1336
+ interface FlagSpelling {
1337
+ canonicalName: string;
1338
+ def: FlagDef;
1339
+ kind: "canonical" | "short" | "alias";
1340
+ negatable: boolean;
1341
+ }
1342
+ //#endregion
1343
+ //#region src/command/node.d.ts
1344
+ /** Runtime-erased Command Action; typed builders and run() own the specific result contract. */
1345
+ type CommandAction = (ctx: CrustCommandContext) => unknown;
1346
+ interface CommandContext {
1347
+ instance: AnyContextInstance;
1348
+ extensionId?: ExtensionId;
1349
+ }
1350
+ /**
1351
+ * Internal representation of a single node in the command tree.
1352
+ *
1353
+ * Built by the `Crust` builder class; not part of the public API.
1354
+ * Each node carries its own local flags, the pre-computed effective
1355
+ * (Context-owned + local merged) flags, positional args, subcommands,
1356
+ * extensions, and the Command Action.
1357
+ */
1358
+ interface CommandNode {
1359
+ /** Command metadata (name, description, usage) */
1360
+ meta: CommandMeta;
1361
+ /** Flags defined directly on this command via `.flags()` */
1362
+ localFlags: FlagsDef;
1363
+ /** Accumulated flags owned by Contexts provided on this command path */
1364
+ ownedFlags: FlagsDef;
1365
+ /** Context-owned and local flags merged for parsing */
1366
+ effectiveFlags: FlagsDef;
1367
+ /** Cached canonical/short/alias table for the effective flags. */
1368
+ flagSpellings: Map<string, FlagSpelling>;
1369
+ /** Positional argument definitions */
1370
+ args: ArgsDef;
1371
+ /** Named subcommands keyed by name */
1372
+ subCommands: Record<string, CommandNode>;
1373
+ /** Contexts available to this command in provide order (construction order is pull-driven). */
1374
+ contexts: CommandContext[];
1375
+ /** Declared command demands; validated when recipes are materialized. */
1376
+ demands: readonly AnyContextFactory[];
1377
+ /** Extensions registered via `.extend()` (root builder only) */
1378
+ extensions: Extension[];
1379
+ /** The Command Action */
1380
+ run?: CommandAction;
1381
+ }
1382
+ //#endregion
1383
+ //#region src/parsing/parser.d.ts
1384
+ type RunInputValue = URL | JsonValue | readonly RunInputValue[];
1385
+ interface RunInputPayload {
1386
+ readonly args?: Readonly<Record<string, RunInputValue | undefined>>;
1387
+ readonly flags?: Readonly<Record<string, RunInputValue | undefined>>;
1388
+ readonly raw?: readonly string[];
1389
+ }
1390
+ //#endregion
1391
+ //#region src/types.d.ts
1392
+ /** Injectable output callbacks threaded through one invocation. */
1393
+ interface InvocationIO {
1394
+ /** Write a line of standard output (injectable text callback) */
1395
+ stdout: (text: string) => void;
1396
+ /** Write a line of diagnostic output (injectable text callback) */
1397
+ stderr: (text: string) => void;
1398
+ }
1399
+ /**
1400
+ * Supported type literals for args and flags.
1401
+ *
1402
+ * Extends `BaseValueType` (`"string" | "number" | "boolean"`) with three
1403
+ * formatted built-ins:
1404
+ *
1405
+ * - `"url"` — the raw value is parsed via `new URL()` into a {@link URL}
1406
+ * - `"path"` — the raw value is expanded (`~`) and resolved against
1407
+ * `process.cwd()` into an absolute `string`
1408
+ * - `"json"` — the raw value is parsed via `JSON.parse()` into `unknown`
1409
+ */
1410
+ type ValueType = BaseValueType | "url" | "path" | "json";
1411
+ /** Resolve a {@link ValueType} literal to its runtime TypeScript type. */
1412
+ type Resolve<T extends ValueType> = {
1413
+ string: string;
1414
+ number: number;
1415
+ boolean: boolean;
1416
+ url: URL;
1417
+ path: string;
1418
+ json: unknown;
1419
+ }[T];
1420
+ /**
1421
+ * Resolve the inferred runtime type for a flag/arg definition.
1422
+ *
1423
+ * When the def declares a `parse` escape hatch (only allowed on `"string"`
1424
+ * variants), the inferred type is `ReturnType<typeof parse>`. Optional parsers
1425
+ * also retain the unparsed output branch. String defs
1426
+ * with a literal `choices` tuple narrow to the union of those literals.
1427
+ * Otherwise it delegates to {@link Resolve} on the declared `type`.
1428
+ */
1429
+ type ResolveBaseType<F> = "parse" extends keyof F ? F["parse"] extends (infer Parse) ? Parse extends ((raw: string) => infer R) ? R : ResolveUnparsedType<F> : never : ResolveUnparsedType<F>;
1430
+ type ResolveUnparsedType<F> = F extends {
1431
+ type: "string";
1432
+ choices: readonly (infer C extends string)[];
1433
+ } ? C : F extends {
1434
+ type: infer T extends ValueType;
1435
+ } ? Resolve<T> : never;
1436
+ /** Shared fields present on every positional argument definition */
1437
+ interface ArgDefBase {
1438
+ /** The argument name (used as the key in the parsed result and in help text) */
1439
+ name: string;
1440
+ /** Human-readable description for help text */
1441
+ description?: string;
1442
+ /**
1443
+ * When `true`, the parser throws if the argument is not provided.
1444
+ *
1445
+ * For variadic args without a default, the validated output is a nonempty tuple.
1446
+ */
1447
+ required?: true;
1448
+ /** Not supported with core value options — see {@link SchemaArgDef} */
1449
+ schema?: never;
1450
+ /**
1451
+ * When `true`, collects all remaining positional values into an array.
1452
+ *
1453
+ * The validated output is always an array, never `undefined`.
1454
+ * Required core variadics without defaults infer `[T, ...T[]]` after
1455
+ * required validation; other core variadics infer `T[]`.
1456
+ */
1457
+ variadic?: true;
1458
+ }
1459
+ /** A positional argument whose value is a string */
1460
+ interface StringArgDef<ParseOutput = unknown> extends ArgDefBase {
1461
+ type: "string";
1462
+ /** Default string value when the argument is not provided */
1463
+ default?: string;
1464
+ /**
1465
+ * Static enum of valid values for this argument.
1466
+ *
1467
+ * Checked for argv and structured invocation input before `parse` runs.
1468
+ * Typed input also proves membership statically. Passing a value outside
1469
+ * `choices` throws `CrustError("PARSE", …)` before any `parse` transform
1470
+ * is applied. Also consumed by shell-completion extensions
1471
+ * (e.g. `@crustjs/extensions`) to emit value candidates.
1472
+ *
1473
+ * Only available on string-typed args; not supported on number/boolean.
1474
+ *
1475
+ * @example
1476
+ * { name: "target", type: "string", choices: ["browser", "bun", "node"] }
1477
+ */
1478
+ choices?: readonly string[];
1479
+ /**
1480
+ * Custom synchronous parser for the raw argv string. Runs after `choices`
1481
+ * validation and per element for variadic args. Its return type becomes the
1482
+ * argument's inferred runtime type; declared defaults are parsed too.
1483
+ *
1484
+ * @example
1485
+ * { name: "port", type: "string", parse: (s) => Number(s) }
1486
+ */
1487
+ parse?: (raw: string) => ParseOutput;
1488
+ }
1489
+ /** A positional argument whose value is a number */
1490
+ interface NumberArgDef extends ArgDefBase {
1491
+ type: "number";
1492
+ choices?: never;
1493
+ /** Default number value when the argument is not provided */
1494
+ default?: number;
1495
+ /** Not supported on number args — use `type: "string"` with `parse`. */
1496
+ parse?: never;
1497
+ }
1498
+ /** A positional argument whose value is a boolean */
1499
+ interface BooleanArgDef extends ArgDefBase {
1500
+ type: "boolean";
1501
+ choices?: never;
1502
+ /** Default boolean value when the argument is not provided */
1503
+ default?: boolean;
1504
+ /** Not supported on boolean args — use `type: "string"` with `parse`. */
1505
+ parse?: never;
1506
+ }
1507
+ /** A positional argument whose value is a {@link URL} */
1508
+ interface UrlArgDef extends ArgDefBase {
1509
+ type: "url";
1510
+ choices?: never;
1511
+ /** Default URL value when the argument is not provided */
1512
+ default?: URL;
1513
+ /** Not supported on url args — use `type: "string"` with `parse`. */
1514
+ parse?: never;
1515
+ }
1516
+ /** A positional argument whose value is an absolute filesystem path */
1517
+ interface PathArgDef extends ArgDefBase {
1518
+ type: "path";
1519
+ choices?: never;
1520
+ /** Default path string when the argument is not provided */
1521
+ default?: string;
1522
+ /** Not supported on path args — use `type: "string"` with `parse`. */
1523
+ parse?: never;
1524
+ }
1525
+ /** A positional argument whose value is JSON parsed to `unknown` */
1526
+ interface JsonArgDef extends ArgDefBase {
1527
+ type: "json";
1528
+ choices?: never;
1529
+ /** Default parsed JSON value when the argument is not provided */
1530
+ default?: unknown;
1531
+ /** Not supported on json args — use `type: "string"` with `parse`. */
1532
+ parse?: never;
1533
+ }
1534
+ /**
1535
+ * A positional argument validated by a Standard Schema (exclusive mode).
1536
+ *
1537
+ * The schema receives the raw string token (`string | undefined` when the
1538
+ * argument is absent; `string[]` for variadic args) and exclusively owns
1539
+ * coercion, defaults, requiredness, choices, and validation. Its inferred
1540
+ * output type reaches the Command Action. Core value options (`type`,
1541
+ * `default`, `required`, `choices`, `parse`) cannot be mixed in.
1542
+ */
1543
+ interface SchemaArgDef {
1544
+ /** The argument name (used as the key in the parsed result and in help text) */
1545
+ name: string;
1546
+ /** Human-readable description for help text */
1547
+ description?: string;
1548
+ /** When `true`, collects all remaining raw tokens into a `string[]` for the schema */
1549
+ variadic?: true;
1550
+ /** Standard Schema that owns coercion, defaults, requiredness, and validation */
1551
+ schema: StandardSchema;
1552
+ type?: never;
1553
+ required?: never;
1554
+ default?: never;
1555
+ choices?: never;
1556
+ parse?: never;
1557
+ }
1558
+ /**
1559
+ * Defines a single positional argument for a CLI command.
1560
+ *
1561
+ * Discriminated by `type` for type-safe `default` values. Boolean toggle
1562
+ * fields (`required`, `variadic`) only accept `true`.
1563
+ *
1564
+ * @example
1565
+ * ```ts
1566
+ * const args = [
1567
+ * { name: "port", type: "number", description: "Port number", default: 3000 },
1568
+ * { name: "name", type: "string", required: true },
1569
+ * { name: "files", type: "string", variadic: true },
1570
+ * ] as const satisfies ArgsDef;
1571
+ * ```
1572
+ */
1573
+ type ArgDef = StringArgDef | NumberArgDef | BooleanArgDef | UrlArgDef | PathArgDef | JsonArgDef | SchemaArgDef;
1574
+ /** Ordered tuple of positional argument definitions */
1575
+ type ArgsDef = readonly ArgDef[];
1576
+ /** Shared fields present on every flag definition */
1577
+ interface FlagDefBase {
1578
+ /** Human-readable description for help text */
1579
+ description?: string;
1580
+ /** Single-character short alias (e.g. `"v"` → `-v`) */
1581
+ short?: string;
1582
+ /** Additional aliases (e.g. `["out"]` → `--out`); one-character aliases also accept one dash. */
1583
+ aliases?: readonly string[];
1584
+ /** When `true`, the parser throws if the flag is not provided */
1585
+ required?: true;
1586
+ /** Not supported with core value options — see {@link SchemaStringFlagDef} */
1587
+ schema?: never;
1588
+ }
1589
+ /** Base for single-value flags — `multiple` must be omitted */
1590
+ interface SingleFlagBase extends FlagDefBase {
1591
+ /** Must be omitted for single-value flags — set to `true` for multi-value */
1592
+ multiple?: never;
1593
+ }
1594
+ /** Base for multi-value flags — `multiple` is required as `true` */
1595
+ interface MultiFlagBase extends FlagDefBase {
1596
+ /** Collect repeated values into an array */
1597
+ multiple: true;
1598
+ }
1599
+ type StringFlagFields<Default, ParseOutput> = {
1600
+ /** Default string value, or string array for a multi-value flag. */
1601
+ default?: Default;
1602
+ /**
1603
+ * Static enum of valid values for this flag.
1604
+ *
1605
+ * Checked for argv and structured invocation input before `parse` runs.
1606
+ * Typed input also proves membership statically. Passing a value outside
1607
+ * `choices` throws `CrustError("PARSE", …)` before any `parse` transform
1608
+ * is applied. Also consumed by shell-completion extensions.
1609
+ */
1610
+ choices?: readonly string[];
1611
+ /**
1612
+ * Custom synchronous parser for the raw argv string. For multi-value
1613
+ * flags it runs once per occurrence. The return type becomes the flag's
1614
+ * inferred runtime value type.
1615
+ */
1616
+ parse?: (raw: string) => ParseOutput;
1617
+ noNegate?: never;
1618
+ };
1619
+ type TypedFlagFields<T extends Exclude<ValueType, "string">, Default> = {
1620
+ /** Default value, or value array for a multi-value flag. */
1621
+ default?: Default;
1622
+ choices?: never;
1623
+ /** Only boolean flags support generated-negation opt-out. */
1624
+ noNegate?: T extends "boolean" ? true : never;
1625
+ /** Use `type: "string"` with `parse` for custom parsing. */
1626
+ parse?: never;
1627
+ };
1628
+ type CoreFlagFields<T extends ValueType, Default, ParseOutput> = T extends "string" ? StringFlagFields<Default, ParseOutput> : T extends Exclude<ValueType, "string"> ? TypedFlagFields<T, Default> : never;
1629
+ /** A single-value core flag for the declared value type. */
1630
+ type TypedFlagDef<T extends ValueType, ParseOutput = unknown> = SingleFlagBase & {
1631
+ type: T;
1632
+ } & CoreFlagFields<T, Resolve<T>, ParseOutput>;
1633
+ /** A repeatable core flag for the declared value type. */
1634
+ type TypedMultiFlagDef<T extends ValueType, ParseOutput = unknown> = MultiFlagBase & {
1635
+ type: T;
1636
+ } & CoreFlagFields<T, readonly Resolve<T>[], ParseOutput>;
1637
+ /** Shared fields for schema-backed flags (exclusive mode) */
1638
+ interface SchemaFlagBase extends Omit<FlagDefBase, "schema" | "required"> {
1639
+ /** Standard Schema that owns coercion, defaults, requiredness, and validation */
1640
+ schema: StandardSchema;
1641
+ required?: never;
1642
+ default?: never;
1643
+ choices?: never;
1644
+ parse?: never;
1645
+ }
1646
+ /**
1647
+ * A schema-backed flag that consumes a value token (`--flag value`).
1648
+ * The schema receives the raw string (`string | undefined`, or
1649
+ * `string[] | undefined` with `multiple: true`) and exclusively owns coercion,
1650
+ * defaults, requiredness, and validation. `type` declares token consumption only.
1651
+ */
1652
+ interface SchemaStringFlagDef extends SchemaFlagBase {
1653
+ type: "string";
1654
+ /** When `true`, the schema receives `string[]` when present, or `undefined` when omitted. */
1655
+ multiple?: true;
1656
+ noNegate?: never;
1657
+ }
1658
+ /**
1659
+ * A schema-backed toggle flag (no value token). The schema receives the raw
1660
+ * `boolean | undefined` (or `boolean[] | undefined` with `multiple: true`).
1661
+ */
1662
+ interface SchemaBooleanFlagDef extends SchemaFlagBase {
1663
+ type: "boolean";
1664
+ /** When `true`, the schema receives `boolean[]` when present, or `undefined` when omitted. */
1665
+ multiple?: true;
1666
+ /** When `true`, reject `--no-{name}` (and negated aliases) at parse time and hide the generated help label */
1667
+ noNegate?: true;
1668
+ }
1669
+ /**
1670
+ * Defines a single named flag for a CLI command.
1671
+ *
1672
+ * Discriminated by `type` and `multiple` for type-safe `default` values.
1673
+ * Boolean toggle fields (`required`, `multiple`) only accept `true`.
1674
+ *
1675
+ * @example
1676
+ * ```ts
1677
+ * const flags = {
1678
+ * verbose: { type: "boolean", description: "Enable verbose logging", short: "v" },
1679
+ * port: { type: "number", description: "Port number", default: 3000 },
1680
+ * files: { type: "string", multiple: true, default: ["index.ts"] },
1681
+ * } satisfies FlagsDef;
1682
+ * ```
1683
+ */
1684
+ type FlagDef = { [T in ValueType]: TypedFlagDef<T> | TypedMultiFlagDef<T>; }[ValueType] | SchemaStringFlagDef | SchemaBooleanFlagDef;
1685
+ /** Record mapping flag names to their definitions */
1686
+ type FlagsDef = Record<string, FlagDef>;
1687
+ /**
1688
+ * A flag definition that carries its own name — the authoring shape
1689
+ * produced by `defineFlag(name, def)` or written inline as an object
1690
+ * literal (`{ name: "dry-run", type: "boolean" }`) and attached with the
1691
+ * variadic `.flags(...defs)`.
1692
+ */
1693
+ type NamedFlagDef = FlagDef & {
1694
+ readonly name: string;
1695
+ };
1696
+ /**
1697
+ * Derive the internal `FlagsDef` record from a tuple of named flag
1698
+ * definitions: each definition's `name` literal becomes a key, its value
1699
+ * the definition without `name`.
1700
+ *
1701
+ * The `extends infer R extends FlagsDef` step defers evaluation so the
1702
+ * result satisfies `FlagsDef` in generic positions.
1703
+ */
1704
+ type FlagWithoutName<D> = D extends unknown ? Omit<D, "name"> : never;
1705
+ type NamedFlagsRecord<Defs extends readonly NamedFlagDef[]> = { [K in Defs[number]["name"]]: FlagWithoutName<Extract<Defs[number], {
1706
+ name: K;
1707
+ }>>; } extends (infer R extends FlagsDef) ? R : never;
1708
+ /**
1709
+ * Merges two flag sets as a flat intersection.
1710
+ *
1711
+ * Statically known shared keys are branded at compile time (`DuplicateNameBrand`,
1712
+ * `ExistingFlagCollisionBrand`, `ProvideChecks`). A plain intersection stays
1713
+ * flat in the checker — chained `.flags()`/`.provide()` calls cost constant
1714
+ * instantiation depth, where per-call merge layers (mapped type or
1715
+ * `Simplify<Omit & …>`) nested and hit TS2589 at ~47 / ~31 chained calls.
1716
+ */
1717
+ type MergeFlags<Base extends FlagsDef, Override extends FlagsDef> = Base & Override;
1718
+ /**
1719
+ * Infer the resolved type for a single ArgDef:
1720
+ *
1721
+ * - **variadic** → `[primitive, ...primitive[]]` when required without a default,
1722
+ * otherwise `primitive[]` (always an array, never `undefined`)
1723
+ * - **required** or **has default** → `primitive` (non-optional)
1724
+ * - otherwise → `primitive | undefined`
1725
+ *
1726
+ * Required core variadics without defaults resolve to nonempty tuples.
1727
+ * Schema-backed and default-backed arguments retain their own output contracts.
1728
+ */
1729
+ type InferArgValue<A extends ArgDef> = A extends {
1730
+ schema: infer S extends StandardSchema;
1731
+ } ? InferOutput<S> : A extends {
1732
+ variadic: true;
1733
+ } ? A extends {
1734
+ required: true;
1735
+ default?: never;
1736
+ } ? [ResolveBaseType<A>, ...ResolveBaseType<A>[]] : ResolveBaseType<A>[] : ("variadic" extends keyof A ? true extends A["variadic"] ? ResolveBaseType<A>[] : never : never) | (A extends {
1737
+ required: true;
1738
+ } ? ResolveBaseType<A> : A extends {
1739
+ default: infer Default;
1740
+ } ? undefined extends Default ? ResolveBaseType<A> | undefined : ResolveBaseType<A> : ResolveBaseType<A> | undefined);
1741
+ type DuplicateArgNames<A extends readonly ArgDef[], Seen extends string = never, Duplicates extends string = never> = A extends readonly [infer Head extends ArgDef, ...infer Tail extends readonly ArgDef[]] ? DuplicateArgNames<Tail, Seen | Head["name"], Duplicates | (Head["name"] & Seen)> : Duplicates;
1742
+ type InferDuplicateArgs<A extends readonly ArgDef[]> = A extends readonly [infer Head extends ArgDef, ...infer Tail extends readonly ArgDef[]] ? { [K in Head["name"]]: InferArgValue<Head>; } & InferDuplicateArgs<Tail> : {};
1743
+ /**
1744
+ * Convert a literal ArgsDef tuple into resolved values keyed by argument name.
1745
+ *
1746
+ * Tuples with rest elements (`number extends A["length"]`) opt out to `{}`;
1747
+ * the builder only produces fixed tuples. Unions of tuples distribute through
1748
+ * `InferArgs`'s naked conditional, so each member is inferred separately.
1749
+ */
1750
+ type InferArgsTuple<A extends readonly ArgDef[]> = number extends A["length"] ? {} : [DuplicateArgNames<A>] extends [never] ? { [D in A[number] as D["name"]]: InferArgValue<D>; } : InferDuplicateArgs<A>;
1751
+ /**
1752
+ * Maps an ArgsDef tuple to resolved arg types keyed by each arg's `name`.
1753
+ *
1754
+ * @example
1755
+ * ```ts
1756
+ * type Result = InferArgs<readonly [
1757
+ * { name: "port"; type: "number"; default: 3000 },
1758
+ * { name: "name"; type: "string"; required: true },
1759
+ * { name: "files"; type: "string"; variadic: true },
1760
+ * ]>;
1761
+ * // Result = { port: number; name: string; files: string[] }
1762
+ * ```
1763
+ */
1764
+ type InferArgs<A> = A extends ArgsDef ? Simplify<InferArgsTuple<A>> : Record<string, never>;
1765
+ /**
1766
+ * Infer the resolved type for a single FlagDef:
1767
+ *
1768
+ * - **multiple** → wraps the resolved type in an array
1769
+ * - **required** or **has default** → `primitive` (non-optional)
1770
+ * - otherwise → `primitive | undefined`
1771
+ */
1772
+ type InferFlagValue<F extends FlagDef> = F extends {
1773
+ schema: infer S extends StandardSchema;
1774
+ } ? InferOutput<S> : F extends {
1775
+ multiple: true;
1776
+ } ? F extends {
1777
+ required: true;
1778
+ } ? ResolveBaseType<F>[] : F extends {
1779
+ default: readonly unknown[];
1780
+ } ? ResolveBaseType<F>[] : ResolveBaseType<F>[] | undefined : F extends {
1781
+ required: true;
1782
+ } ? ResolveBaseType<F> : F extends {
1783
+ default: infer Default;
1784
+ } ? undefined extends Default ? ResolveBaseType<F> | undefined : ResolveBaseType<F> : ResolveBaseType<F> | undefined;
1785
+ /**
1786
+ * Maps a full FlagsDef record to resolved flag types.
1787
+ *
1788
+ * @example
1789
+ * ```ts
1790
+ * type Result = InferFlags<{
1791
+ * verbose: { type: "boolean" };
1792
+ * port: { type: "number", default: 3000 };
1793
+ * }>;
1794
+ * // Result = { verbose: boolean | undefined; port: number }
1795
+ * ```
1796
+ */
1797
+ type InferFlags<F> = F extends FlagsDef ? { [K in keyof F]: InferFlagValue<F[K]>; } : Record<string, never>;
1798
+ type InputBaseValue<D> = true extends IsUnion<D> | IsUnion<D[keyof D & "type"]> ? never : D extends {
1799
+ type: "boolean";
1800
+ } ? "noNegate" extends keyof D ? true extends D["noNegate"] ? true : boolean : boolean : D extends {
1801
+ schema: StandardSchema;
1802
+ } ? D extends {
1803
+ type: "boolean";
1804
+ } ? boolean : string : D extends {
1805
+ type: "json";
1806
+ } ? JsonValue : "choices" extends keyof D ? Exclude<D["choices"], undefined> extends (infer Choices extends readonly string[]) ? [Choices] extends [never] ? D extends {
1807
+ type: infer T extends ValueType;
1808
+ } ? Resolve<T> : never : IsStaticTuple<Choices> extends true ? IsClosedName<Choices[number]> extends true ? Choices[number] : never : never : never : D extends {
1809
+ parse: (raw: string) => infer _ParseOutput;
1810
+ } ? string : D extends {
1811
+ type: infer T extends ValueType;
1812
+ } ? Resolve<T> : never;
1813
+ type InputArgValue<D extends ArgDef, Value = InputBaseValue<D>> = [Value] extends [never] ? never : D extends {
1814
+ variadic: true;
1815
+ } ? RequiredArgNames<[D]> extends never ? Value[] : [Value, ...Value[]] : "variadic" extends keyof D ? true extends D["variadic"] ? never : Value : Value;
1816
+ type InputFlagValue<D, Value = InputBaseValue<D>> = [Value] extends [never] ? never : D extends {
1817
+ multiple: true;
1818
+ } ? Value[] : "multiple" extends keyof D ? true extends D["multiple"] ? never : Value : Value;
1819
+ type RequiredArgNames<A extends ArgsDef> = A[number] extends (infer D) ? D extends {
1820
+ name: infer N extends string;
1821
+ } ? "required" extends keyof D ? true extends D["required"] ? D extends {
1822
+ default: infer Default;
1823
+ } ? undefined extends Default ? N : never : N : never : never : never : never;
1824
+ type InputArgsPrefixes<Remaining extends ArgsDef, Supplied = {}, Prefixes = never> = Remaining extends readonly [infer Head extends ArgDef, ...infer Tail extends ArgsDef] ? InputArgsPrefixes<Tail, Supplied & { [K in Head["name"]]: InputArgValue<Head>; }, Prefixes | (RequiredArgNames<Remaining> extends never ? Simplify<Supplied & { [D in Remaining[number] as D["name"]]?: never; }> : never)> : Prefixes | Simplify<Supplied>;
1825
+ /** Supplied positional values form a prefix; defaults do not fill input gaps. */
1826
+ type InputArgs<A extends ArgsDef> = number extends A["length"] ? never : IsUnion<A> extends true ? never : IsClosedName<A[number]["name"]> extends true ? InputArgsPrefixes<A> : never;
1827
+ type RequiredFlagName<D, K> = D extends unknown ? "required" extends keyof D ? true extends D["required"] ? D extends {
1828
+ default: infer Default;
1829
+ } ? undefined extends Default ? K : never : K : never : never : never;
1830
+ type RequiredFlagNames<F extends FlagsDef> = { [K in keyof F]-?: RequiredFlagName<F[K], K>; }[keyof F];
1831
+ /** Flag values accepted by typed programmatic invocation before parsing/validation. */
1832
+ type KnownFlags<F extends FlagsDef> = { [K in keyof F as string extends K ? never : K]: F[K]; };
1833
+ type InputFlags<F extends FlagsDef> = IsUnion<F> extends true ? never : Simplify<{ [K in RequiredFlagNames<KnownFlags<F>>]-?: InputFlagValue<KnownFlags<F>[K]>; } & { [K in Exclude<keyof KnownFlags<F>, RequiredFlagNames<KnownFlags<F>>>]?: InputFlagValue<KnownFlags<F>[K]>; }> & (string extends keyof F ? NonNullable<RunInputPayload["flags"]> : {});
1834
+ type SectionConsumer = ExtensionId | {
1835
+ readonly id: ExtensionId;
1836
+ };
1837
+ type Audience<C> = {
1838
+ readonly only: C;
1839
+ readonly except?: never;
1840
+ } | {
1841
+ readonly except: C;
1842
+ readonly only?: never;
1843
+ } | {
1844
+ readonly only?: never;
1845
+ readonly except?: never;
1846
+ };
1847
+ type SectionAudience = Audience<readonly [SectionConsumer, ...SectionConsumer[]]>;
1848
+ type SectionContent = {
1849
+ readonly title: string;
1850
+ readonly body: string;
1851
+ };
1852
+ /** A plain-text documentation section accepted from command and Extension authors. */
1853
+ type CommandSectionInput = SectionContent & SectionAudience;
1854
+ /** Typed dynamic audiences may be empty until their consuming operation checks them. */
1855
+ type RuntimeCommandSectionInput = SectionContent & Audience<readonly SectionConsumer[]>;
1856
+ /** A validated documentation section rendered after built-in command documentation. */
1857
+ type CommandSection = SectionContent & Audience<readonly [ExtensionId, ...ExtensionId[]]>;
1858
+ /** Metadata describing a CLI command */
1859
+ interface CommandMeta {
1860
+ /** The command name (used in help text and routing) */
1861
+ name: string;
1862
+ /** Human-readable description for help text */
1863
+ description?: string;
1864
+ /** Application version exposed to Extensions and tooling on the root command. */
1865
+ version?: string;
1866
+ /** Custom usage string (overrides auto-generated usage) */
1867
+ usage?: string;
1868
+ /** Plain-text sections rendered after built-in command documentation. */
1869
+ sections?: readonly CommandSection[];
1870
+ /**
1871
+ * Alternative names that resolve to the same command.
1872
+ *
1873
+ * Each entry is a sibling-level alternative for `name`. For example,
1874
+ * `defineCommand("issue", { aliases: ["issues", "i"] }, recipe)` makes
1875
+ * `cli issue`, `cli issues`, and `cli i` all route to the same command node.
1876
+ *
1877
+ * **Conflict policy.** Alias strings must not collide with this command's
1878
+ * own canonical `name`, with any sibling's `name`, or with any sibling's
1879
+ * own alias. TypeScript reports statically known collisions. Each alias
1880
+ * must also be a non-empty string with no
1881
+ * whitespace and must not start with `-`.
1882
+ *
1883
+ * **Display contract.** Help output renders the canonical name with
1884
+ * aliases inline as `name (a, b, c)`. The canonical `name` is what
1885
+ * appears in `commandPath`, error messages, and suggestions from
1886
+ * `didYouMean` — it does not depend on which alias the user typed.
1887
+ *
1888
+ * @example
1889
+ * defineCommand("issue", { aliases: ["issues", "i"] }, recipe)
1890
+ */
1891
+ aliases?: readonly string[];
1892
+ /**
1893
+ * When `true`, omit this command from every tooling surface that
1894
+ * enumerates the command tree for users:
1895
+ *
1896
+ * - `help` rendered output (subcommand list + USAGE token)
1897
+ * - `@crustjs/man` generated man pages (`SUBCOMMANDS` section)
1898
+ * - `completion` candidate lists (recursively — hidden
1899
+ * subcommands and their descendants never appear in generated
1900
+ * bash/zsh/fish scripts)
1901
+ * - `didYouMean` typo suggestions and "Available commands"
1902
+ * list (so internal names never surface in error UX)
1903
+ * - `skill` manifests
1904
+ *
1905
+ * The command is **only hidden from listings**: routing in
1906
+ * `@crustjs/core` does not consult `meta.hidden`, so it stays fully
1907
+ * invocable by direct name (or alias). The intended use case is
1908
+ * internal/runtime commands like a `__complete` shell-completion
1909
+ * entrypoint. Marking a user-facing command `hidden` is supported but
1910
+ * unusual.
1911
+ *
1912
+ * **Scope: commands only.** There is no analogous `hidden` field on
1913
+ * `FlagDef` or `ArgDef`; flags and positional arguments always surface
1914
+ * in help, completion, and man output. If you need a flag that does
1915
+ * not advertise itself, the workaround is to register it as an Extension
1916
+ * flags entry without a description (omit `description`),
1917
+ * which suppresses its description body but still lists the spelling
1918
+ * — there is intentionally no full hide mechanism at the flag layer.
1919
+ *
1920
+ * Tooling contract: any renderer or generator that walks
1921
+ * `subCommands` to produce a user-facing listing should skip nodes
1922
+ * where `meta.hidden === true`.
1923
+ *
1924
+ * @example
1925
+ * meta: { name: "__complete", hidden: true, description: "Internal" }
1926
+ */
1927
+ hidden?: boolean;
1928
+ }
1929
+ /** Raw token shapes a Standard Schema receives before it runs. */
1930
+ type RawSchemaFlagInput = string | boolean | readonly (string | boolean)[] | undefined;
1931
+ /** One flag value after syntax parsing and before required/schema validation. */
1932
+ type RawFlagValue<D extends FlagDef> = D extends {
1933
+ schema: StandardSchema;
1934
+ } ? RawSchemaFlagInput : InferFlagValue<D> | undefined;
1935
+ /** Positional counterpart of {@link RawFlagValue}. */
1936
+ type RawArgValue<D extends ArgDef> = D extends {
1937
+ schema: StandardSchema;
1938
+ } ? D extends {
1939
+ variadic: true;
1940
+ } ? string[] : string | undefined : D extends {
1941
+ variadic: true;
1942
+ } ? ResolveBaseType<D>[] | undefined : InferArgValue<D> | undefined;
1943
+ /** Runtime-erased syntax-parsed flag value. */
1944
+ type ParsedFlagValue = RawFlagValue<FlagDef>;
1945
+ /** Runtime-erased syntax-parsed positional value. */
1946
+ type ParsedArgValue = RawArgValue<ArgDef>;
1947
+ type RawParsedFlags<F extends FlagsDef> = { [K in keyof F]: RawFlagValue<F[K]>; };
1948
+ type RawParsedArgs<A extends ArgsDef> = number extends A["length"] ? Record<string, ParsedArgValue> : { [D in A[number] as D["name"]]: RawArgValue<D>; };
1949
+ /** A declared default on any argument or flag definition. */
1950
+ type DeclaredDefault = (ArgDef | FlagDef)["default"];
1951
+ /** Syntax-parsed input, before required and Standard Schema validation. */
1952
+ interface ParseResult<A extends ArgsDef = ArgsDef, F extends FlagsDef = FlagsDef> {
1953
+ args: RawParsedArgs<A>;
1954
+ flags: RawParsedFlags<F>;
1955
+ /** Positionals before `--` that were not consumed by a declared argument. */
1956
+ excessArgs: string[];
1957
+ /** Arguments after the `--` separator. */
1958
+ rawArgs: string[];
1959
+ }
1960
+ /** Fully validated input returned by the schema boundary. */
1961
+ interface ValidatedInput<A extends ArgsDef = ArgsDef, F extends FlagsDef = FlagsDef> {
1962
+ args: InferArgs<A>;
1963
+ flags: InferFlags<F>;
1964
+ }
1965
+ //#endregion
1966
+ //#region src/api/context.d.ts
1967
+ /** Upper bound for phantom name-to-value context maps. */
1968
+ type ContextMap = object;
1969
+ declare const defining: unique symbol;
1970
+ declare const contextProof: unique symbol;
1971
+ /** @internal Immutable defining data retained through public structural copies. */
1972
+ interface Defining<T> {
1973
+ readonly [defining]: T;
1974
+ }
1975
+ /** @internal */
1976
+ type DefiningOf<T> = T extends Defining<unknown> ? T[typeof defining] : T;
1977
+ /**
1978
+ * Adapter hook: the Context sources a bag was built from, exposed as a
1979
+ * non-enumerable symbol property. Reading it never starts construction.
1980
+ */
1981
+ declare const contextSources: unique symbol;
1982
+ /** Lazy, invocation-scoped Context values. Reading a property starts construction. */
1983
+ type ContextBag<Deps extends ContextMap = {}> = { readonly [K in keyof Deps]: Promise<Deps[K]>; } & {
1984
+ readonly [contextSources]?: readonly (AnyContextFactory | AnyContextInstance)[];
1985
+ };
1986
+ interface ContextConfig {
1987
+ readonly flags?: readonly NamedFlagDef[];
1988
+ readonly uses?: readonly AnyContextFactory[];
1989
+ }
1990
+ type ValidateContextConfig<R extends ContextConfig> = {
1991
+ readonly flags?: R["flags"] extends readonly NamedFlagDef[] ? ValidateLocalFlagDefs<R["flags"], never> : "flags" extends keyof R ? {} : never;
1992
+ readonly uses?: R["uses"] extends readonly AnyContextFactory[] ? R["uses"] : "uses" extends keyof R ? {} : never;
1993
+ };
1994
+ interface ContextSetupInput<OF extends FlagsDef = FlagsDef> extends InvocationIO {
1995
+ readonly flags: InferFlags<OF>;
1996
+ readonly ctx: ContextBag<ContextMap>;
1997
+ readonly defer: (cleanup: () => void | PromiseLike<void>) => void;
1998
+ }
1999
+ interface ContextInstance<Name extends string = string, Value = unknown, OF extends FlagsDef = FlagsDef, Deps extends ContextMap = Record<string, ContextValue>> extends Defining<ContextInstance<Name, Value, OF, Deps>> {
2000
+ readonly [contextProof]?: string extends keyof OF | keyof Deps ? unknown : (state: [OF, Deps]) => void;
2001
+ readonly name: Name;
2002
+ readonly ownedFlags: FlagsDef;
2003
+ /** @internal — declared direct dependency factories */
2004
+ readonly uses: readonly AnyContextFactory[];
2005
+ /** @internal defining factory, for adapters that identify Contexts by factory */
2006
+ readonly factory: AnyContextFactory;
2007
+ setup(input: ContextSetupInput<OF>): Awaitable<Value>;
2008
+ readonly _ownedFlags?: OF;
2009
+ /** @internal — phantom carrying the transitive dependency closure */
2010
+ readonly _deps?: Deps;
2011
+ }
2012
+ /** @internal Existential registry constraint; never evidence for trusted attachment. */
2013
+ type AnyContextInstance = ContextInstance<string, unknown, any, any>;
2014
+ /** Whatever a Context setup produces, erased at the runtime registry. */
2015
+ type ContextValue = Awaited<ReturnType<AnyContextInstance["setup"]>>;
2016
+ interface ContextSetup<Options, OF extends FlagsDef = {}, Deps extends ContextMap = {}> extends InvocationIO {
2017
+ readonly options: Options;
2018
+ readonly flags: InferFlags<OF>;
2019
+ readonly ctx: ContextBag<Deps>;
2020
+ /**
2021
+ * Registers cleanup on the invocation's disposal stack: callbacks run after
2022
+ * post-run hooks in reverse registration order. Throws once setup has settled.
2023
+ */
2024
+ readonly defer: (cleanup: () => void | PromiseLike<void>) => void;
2025
+ }
2026
+ interface ContextFactory<Name extends string, Options, Value, OF extends FlagsDef = {}, Deps extends ContextMap = {}> extends Defining<ContextFactory<Name, Options, Value, OF, Deps>> {
2027
+ (options: Options): ContextInstance<Name, Value, OF, Deps>;
2028
+ readonly contextName: Name;
2029
+ /** @internal — declared direct dependency factories */
2030
+ readonly uses: readonly AnyContextFactory[];
2031
+ of(value: Value): ContextInstance<Name, Value, OF, {}>;
2032
+ readonly _deps?: Deps;
2033
+ }
2034
+ type AnyContextFactory = ContextFactory<string, any, any, any, any>;
2035
+ type NamedOutput<Name extends string, Value> = IsClosedName<Name> extends false ? Record<string, Awaited<Value>> : IsUnion<Name> extends true ? Record<string, Awaited<Value>> : { [K in Name]: Awaited<Value>; };
2036
+ type ContextOutput<C> = C extends AnyContextInstance ? DefiningOf<C> extends ContextInstance<infer Name, infer Value, any, any> ? NamedOutput<Name, Value> : never : never;
2037
+ type ContextsOutput<Cs extends readonly AnyContextInstance[]> = IsStaticTuple<Cs> extends true ? Cs extends readonly [infer H, ...infer T extends readonly AnyContextInstance[]] ? MergeProviders<ContextOutput<H>, ContextsOutput<T>> : {} : Cs[number] extends never ? {} : Record<string, ContextOutput<Cs[number]> extends (infer O) ? O extends unknown ? O[keyof O] : never : never>;
2038
+ type ContextsOwnedFlags<Cs extends readonly AnyContextInstance[]> = IsStaticTuple<Cs> extends true ? Cs extends readonly [infer H, ...infer T extends readonly AnyContextInstance[]] ? MergeFlags<ContextOwnedFlags<H>, ContextsOwnedFlags<T>> : {} : keyof UnionToIntersection<ContextOwnedFlags<Cs[number]>> extends never ? {} : FlagsDef;
2039
+ type FactoryOutput<F> = F extends AnyContextFactory ? DefiningOf<F> extends ContextFactory<infer Name, any, infer Value, any, any> ? NamedOutput<Name, Value> : never : never;
2040
+ type FactoriesOutput<Fs extends readonly AnyContextFactory[]> = Fs extends readonly [infer H, ...infer T extends readonly AnyContextFactory[]] ? FactoryOutput<H> & FactoriesOutput<T> : {};
2041
+ type FactoryDeps<F> = F extends AnyContextFactory ? DefiningOf<F> extends ContextFactory<any, any, any, any, infer Deps> ? Deps : {} : {};
2042
+ type FactoriesDeps<Fs extends readonly AnyContextFactory[]> = Fs extends readonly [infer H, ...infer T extends readonly AnyContextFactory[]] ? FactoryDeps<H> & FactoriesDeps<T> : {};
2043
+ type ContextDependencies<Uses extends readonly AnyContextFactory[]> = IsStaticTuple<Uses> extends true ? FactoriesOutput<Uses> & FactoriesDeps<Uses> : Record<string, ContextValue>;
2044
+ type ContextDepsOf<C> = C extends AnyContextInstance ? DefiningOf<C> extends {
2045
+ readonly _deps?: infer Deps extends ContextMap;
2046
+ } ? Deps : {} : {};
2047
+ type ContextsDependencies<Cs extends readonly AnyContextInstance[]> = Cs extends readonly [infer H, ...infer T extends readonly AnyContextInstance[]] ? ContextDepsOf<H> & ContextsDependencies<T> : {};
2048
+ type OwnedFlagsOf<R extends ContextConfig> = R extends {
2049
+ flags: infer F extends readonly NamedFlagDef[];
2050
+ } ? AttachedFlags<F> : "flags" extends keyof R ? FlagsDef : {};
2051
+ type UsesOf<R extends ContextConfig> = R extends {
2052
+ uses: infer Uses extends readonly AnyContextFactory[];
2053
+ } ? Uses : "uses" extends keyof R ? readonly AnyContextFactory[] : readonly [];
2054
+ /** Define a named, lazy command dependency. Declared `uses` are exposed on `ctx`. */
2055
+ declare function defineContext<Name extends string, Value, Options = void>(name: Name, setup: (input: ContextSetup<Options>) => Awaitable<Value>): ContextFactory<Name, Options, Value>;
2056
+ declare function defineContext<Name extends string, const R extends ContextConfig, Value, Options = void>(name: Name, config: R & ValidateContextConfig<R> & ContextConfig, setup: (input: ContextSetup<Options, OwnedFlagsOf<R>, ContextDependencies<UsesOf<R>>>) => Awaitable<Value>): ContextFactory<Name, Options, Value, OwnedFlagsOf<R>, ContextDependencies<UsesOf<R>>>;
2057
+ type FactoryValueOf<F extends AnyContextFactory> = F extends ContextFactory<any, any, infer Value, any, any> ? Awaited<Value> : never;
2058
+ //#endregion
2059
+ export { CrustErrorDetailsMap as $, ValueType as A, defineExtensionId as At, ExtensionFlagDef as B, NamedFlagDef as C, FlagSnapshot as Ct, SectionAudience as D, LocalValueBrand as Dt, ParsedFlagValue as E, EmptyArgNameBrand as Et, Extension as F, InvocationOutcome as G, ExtensionSectionContribution as H, ExtensionBuildContext as I, defineExtension as J, NamedExtensionFlagDef as K, ExtensionConfig as L, BuildFile as M, BuildReport as N, SectionConsumer as O, MergeContext as Ot, DefineExtensionWith as P, CrustErrorDetails as Q, ExtensionContext as R, MergeFlags as S, CommandSnapshot as St, ParsedArgValue as T, LocalFlagNameBrand as Tt, Finished as U, ExtensionHooks as V, InferExtensionFlags as W, CrustError as X, CommandNotFoundErrorDetails as Y, CrustErrorCode as Z, FlagDef as _, RunInput as _t, ContextInstance as a, CommandConfig as at, InputFlags as b, defineCommand as bt, FactoryValueOf as c, CommandHandle as ct, ArgDef as d, CommandShapeAt as dt, CrustErrorJson as et, ArgsDef as f, CommandTree as ft, DeclaredDefault as g, RunArguments as gt, CommandSectionInput as h, RootCommandMeta as ht, ContextFactory as i, AnyCrust as it, BuildArtifacts as j, ValidatedInput as k, ExtensionId as kt, contextSources as l, CommandPath as lt, CommandSection as m, CrustCommandContext as mt, ContextBag as n, ParseErrorDetails as nt, ContextMap as o, CommandDefinition as ot, CommandMeta as p, Crust as pt, RootMetaKey as q, ContextConfig as r, ValidationErrorDetails as rt, ContextSetup as s, CommandDefinitionBuilder as st, AnyContextFactory as t, DefinitionErrorDetails as tt, defineContext as u, CommandShape as ut, FlagsDef as v, RunInputArguments as vt, ParseResult as w, LocalFlagBrand as wt, InvocationIO as x, ArgSnapshot as xt, InputArgs as y, RunOutcome as yt, ExtensionFactory as z };