@politty/zod 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +561 -0
- package/bin/cli.mjs +3 -0
- package/dist/arg-registry-YaWTVu_x.d.ts +1025 -0
- package/dist/augment.d.ts +15 -0
- package/dist/augment.js +1 -0
- package/dist/cli-main-Dn88vIyn.js +84 -0
- package/dist/cli-run-eibUcgys.js +7 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +16 -0
- package/dist/command-k-4yAz4J.js +42 -0
- package/dist/compile-cache-Ct41pWGL.js +100 -0
- package/dist/compile-cache.d.ts +78 -0
- package/dist/compile-cache.js +3 -0
- package/dist/completion-gtWX3mwP.js +5608 -0
- package/dist/completion.d.ts +242 -0
- package/dist/completion.js +4 -0
- package/dist/docs.d.ts +770 -0
- package/dist/docs.js +3044 -0
- package/dist/field-meta-DMy5BcRr.js +146 -0
- package/dist/index-CvhsecfS.d.ts +455 -0
- package/dist/index.d.ts +799 -0
- package/dist/index.js +17 -0
- package/dist/log-collector-CoUkLVJB.js +114 -0
- package/dist/logger-i_bb-Jhc.js +133 -0
- package/dist/prompt-CEIZ-7H1.js +171 -0
- package/dist/prompt-clack.d.ts +16 -0
- package/dist/prompt-clack.js +32 -0
- package/dist/prompt-inquirer.d.ts +16 -0
- package/dist/prompt-inquirer.js +47 -0
- package/dist/prompt.d.ts +106 -0
- package/dist/prompt.js +4 -0
- package/dist/register-Bk0K83W2.js +439 -0
- package/dist/runner-D72I7wvK.js +2956 -0
- package/dist/runner-FvUwOHyE.js +3 -0
- package/dist/schema-extractor-DMSozq40.js +250 -0
- package/dist/skill.d.ts +608 -0
- package/dist/skill.js +1832 -0
- package/dist/src-KzC0g5CS.js +191 -0
- package/dist/subcommand-router-Cskpofdk.js +134 -0
- package/package.json +103 -0
|
@@ -0,0 +1,1025 @@
|
|
|
1
|
+
//#region ../core/src/adapter/standard-schema.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Type-level subset of the Standard Schema V1 interface
|
|
4
|
+
* (https://standardschema.dev), vendored so `@politty/core` can constrain
|
|
5
|
+
* and infer user schemas without importing any schema library.
|
|
6
|
+
*
|
|
7
|
+
* Both zod v4 and valibot v1 type their schemas against the official
|
|
8
|
+
* `@standard-schema/spec` interface, so any schema from either library is
|
|
9
|
+
* structurally assignable to {@link SchemaLike}. Only the properties core
|
|
10
|
+
* needs for constraints and output inference are declared here — extra
|
|
11
|
+
* properties on the real `~standard` object don't affect assignability.
|
|
12
|
+
*
|
|
13
|
+
* This is a TYPE-ONLY neutrality layer: core never calls
|
|
14
|
+
* `~standard.validate` (rich validation goes through the registered
|
|
15
|
+
* `ValidatorAdapter` so error output keeps library-specific detail).
|
|
16
|
+
*/
|
|
17
|
+
/** The `~standard` properties politty relies on. */
|
|
18
|
+
interface StandardSchemaProps<Output = unknown> {
|
|
19
|
+
/** Version of the Standard Schema spec the library implements */
|
|
20
|
+
readonly version: 1;
|
|
21
|
+
/** Name of the implementing library (e.g. "zod", "valibot") */
|
|
22
|
+
readonly vendor: string;
|
|
23
|
+
/** Standard validation entry point (unused by politty; see module doc) */
|
|
24
|
+
readonly validate: (value: unknown) => unknown;
|
|
25
|
+
/** Type-inference carrier (never exists at runtime) */
|
|
26
|
+
readonly types?: {
|
|
27
|
+
readonly output: Output;
|
|
28
|
+
} | undefined;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* A schema from any Standard Schema implementing library, constrained by
|
|
32
|
+
* its output type.
|
|
33
|
+
*
|
|
34
|
+
* A primitive cannot satisfy this (it has no `~standard` property), which is
|
|
35
|
+
* what matters in practice: schemas are used as `WeakMap` keys by the
|
|
36
|
+
* `arg()` metadata registry. Intersecting with `object` would not add
|
|
37
|
+
* safety — TypeScript still accepts a hand-written `string & SchemaLike<…>`
|
|
38
|
+
* against an object-constrained type, and such a value throws
|
|
39
|
+
* `Invalid value used as weak map key` the moment `arg()` registers it.
|
|
40
|
+
*/
|
|
41
|
+
interface SchemaLike<Output = unknown> {
|
|
42
|
+
readonly "~standard": StandardSchemaProps<Output>;
|
|
43
|
+
}
|
|
44
|
+
/** Infer the output type of a {@link SchemaLike}. */
|
|
45
|
+
type InferSchemaOutput<S> = S extends SchemaLike ? NonNullable<S["~standard"]["types"]>["output"] : never;
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region ../core/src/adapter/field-meta.d.ts
|
|
48
|
+
/**
|
|
49
|
+
* Resolved metadata for an argument field
|
|
50
|
+
*/
|
|
51
|
+
interface ResolvedFieldMeta {
|
|
52
|
+
/** Field name (camelCase, as defined in schema) */
|
|
53
|
+
name: string;
|
|
54
|
+
/** CLI option name (kebab-case, for command line usage) */
|
|
55
|
+
cliName: string;
|
|
56
|
+
/**
|
|
57
|
+
* Aliases for this option, normalized to an array.
|
|
58
|
+
* 1-char entries are short aliases (`-v`); multi-char entries are long
|
|
59
|
+
* aliases (`--to-be`).
|
|
60
|
+
*/
|
|
61
|
+
alias?: string[] | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* Aliases that are accepted at parse time but hidden from help,
|
|
64
|
+
* generated docs, and shell completion.
|
|
65
|
+
*/
|
|
66
|
+
hiddenAlias?: string[] | undefined;
|
|
67
|
+
/** Argument description */
|
|
68
|
+
description?: string | undefined;
|
|
69
|
+
/** Whether this is a positional argument */
|
|
70
|
+
positional: boolean;
|
|
71
|
+
/** Placeholder for help display */
|
|
72
|
+
placeholder?: string | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* Environment variable name(s) to read value from.
|
|
75
|
+
* If an array, earlier entries take priority.
|
|
76
|
+
*/
|
|
77
|
+
env?: string | string[] | undefined;
|
|
78
|
+
/** Whether this argument is required */
|
|
79
|
+
required: boolean;
|
|
80
|
+
/** Default value if any */
|
|
81
|
+
defaultValue?: unknown;
|
|
82
|
+
/** Detected type from schema */
|
|
83
|
+
type: "string" | "number" | "boolean" | "array" | "unknown";
|
|
84
|
+
/**
|
|
85
|
+
* Original field schema, carried through opaquely for downstream
|
|
86
|
+
* consumers. Its concrete type belongs to the adapter's schema library
|
|
87
|
+
* (zod, valibot, or an internal descriptor); core never calls into it.
|
|
88
|
+
*/
|
|
89
|
+
schema: unknown;
|
|
90
|
+
/** True if this overrides built-in aliases (-h, -H) */
|
|
91
|
+
overrideBuiltinAlias?: true;
|
|
92
|
+
/** Enum values if detected from schema (z.enum) */
|
|
93
|
+
enumValues?: string[] | undefined;
|
|
94
|
+
/** Completion metadata from arg() */
|
|
95
|
+
completion?: CompletionMeta | undefined;
|
|
96
|
+
/** Prompt metadata from arg() for interactive input */
|
|
97
|
+
prompt?: PromptMeta | undefined;
|
|
98
|
+
/**
|
|
99
|
+
* Negation configuration for this boolean field.
|
|
100
|
+
*
|
|
101
|
+
* - String (e.g. `"disable-cache"`): the default `--no-<cliName>` form is
|
|
102
|
+
* suppressed and only `--<negation>` (plus its camelCase variant) is
|
|
103
|
+
* accepted as the negation flag.
|
|
104
|
+
* - `true`: the default `--no-<cliName>` form is accepted **and** shown in
|
|
105
|
+
* help, generated docs, and shell completions.
|
|
106
|
+
* - `false`: neither the default `--no-<cliName>` nor any custom name is
|
|
107
|
+
* accepted; the field only responds to the positive flag.
|
|
108
|
+
* - `undefined`: no negation form is accepted or shown.
|
|
109
|
+
*
|
|
110
|
+
* Only applies to boolean fields; populated as `undefined` otherwise.
|
|
111
|
+
*/
|
|
112
|
+
negation?: string | boolean | undefined;
|
|
113
|
+
/**
|
|
114
|
+
* Derived display name (no `--` prefix) for the negation flag in help,
|
|
115
|
+
* generated docs, and shell completions. `undefined` means the negation
|
|
116
|
+
* is hidden from those surfaces. Computed from `negation` + `cliName`.
|
|
117
|
+
*/
|
|
118
|
+
negationDisplay?: string | undefined;
|
|
119
|
+
/** Description shown for the negation option in help/docs. */
|
|
120
|
+
negationDescription?: string | undefined;
|
|
121
|
+
/** Side-effect callback from arg() metadata */
|
|
122
|
+
effect?: ((value: unknown, context: EffectContext) => void | PromiseLike<void>) | undefined;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Extracted fields from a schema
|
|
126
|
+
*/
|
|
127
|
+
interface ExtractedFields {
|
|
128
|
+
/** All field definitions */
|
|
129
|
+
fields: ResolvedFieldMeta[];
|
|
130
|
+
/** Original schema for validation */
|
|
131
|
+
schema: ArgsSchema;
|
|
132
|
+
/** Schema type */
|
|
133
|
+
schemaType: "object" | "discriminatedUnion" | "union" | "xor" | "intersection";
|
|
134
|
+
/** Discriminator key (for discriminatedUnion) */
|
|
135
|
+
discriminator?: string;
|
|
136
|
+
/** Variants (for discriminatedUnion) */
|
|
137
|
+
variants?: Array<{
|
|
138
|
+
discriminatorValue: string;
|
|
139
|
+
fields: ResolvedFieldMeta[];
|
|
140
|
+
description?: string;
|
|
141
|
+
}>;
|
|
142
|
+
/** Options (for union) */
|
|
143
|
+
unionOptions?: ExtractedFields[];
|
|
144
|
+
/** Schema description */
|
|
145
|
+
description?: string;
|
|
146
|
+
/**
|
|
147
|
+
* Unknown keys handling mode
|
|
148
|
+
* - "strict": Unknown keys cause validation errors (z.strictObject or z.object().strict())
|
|
149
|
+
* - "strip": Unknown keys trigger warnings (default, z.object())
|
|
150
|
+
* - "passthrough": Unknown keys are silently ignored (z.looseObject or z.object().passthrough())
|
|
151
|
+
*/
|
|
152
|
+
unknownKeysMode: UnknownKeysMode;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Unknown keys handling mode for object schemas
|
|
156
|
+
* - "strict": Unknown keys cause validation errors
|
|
157
|
+
* - "strip": Unknown keys are silently ignored (default)
|
|
158
|
+
* - "passthrough": Unknown keys are passed through
|
|
159
|
+
*/
|
|
160
|
+
type UnknownKeysMode = "strict" | "strip" | "passthrough";
|
|
161
|
+
/**
|
|
162
|
+
* Convert camelCase to kebab-case
|
|
163
|
+
* @example toKebabCase("dryRun") => "dry-run"
|
|
164
|
+
* @example toKebabCase("outputDir") => "output-dir"
|
|
165
|
+
* @example toKebabCase("XMLParser") => "xml-parser"
|
|
166
|
+
*/
|
|
167
|
+
declare function toKebabCase(str: string): string;
|
|
168
|
+
/**
|
|
169
|
+
* Convert hyphen-separated sequences to camelCase.
|
|
170
|
+
*
|
|
171
|
+
* Replaces `-x` (hyphen followed by a lowercase letter) with the uppercase
|
|
172
|
+
* variant. Non-hyphenated input (e.g., already camelCase) is returned as-is.
|
|
173
|
+
*
|
|
174
|
+
* @param str - A string that may contain hyphens
|
|
175
|
+
* @example toCamelCase("dry-run") => "dryRun"
|
|
176
|
+
* @example toCamelCase("output-dir") => "outputDir"
|
|
177
|
+
* @example toCamelCase("dryRun") => "dryRun"
|
|
178
|
+
*/
|
|
179
|
+
declare function toCamelCase(str: string): string;
|
|
180
|
+
//#endregion
|
|
181
|
+
//#region ../core/src/lazy.d.ts
|
|
182
|
+
/**
|
|
183
|
+
* A lazily-loaded command that carries synchronous metadata for
|
|
184
|
+
* static analysis (completion, help) while deferring full module
|
|
185
|
+
* loading to execution time.
|
|
186
|
+
*/
|
|
187
|
+
interface LazyCommand<T extends AnyCommand = AnyCommand> {
|
|
188
|
+
readonly __politty_lazy__: true;
|
|
189
|
+
readonly meta: T;
|
|
190
|
+
readonly load: () => Promise<AnyCommand>;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Type guard: check if a value is a LazyCommand
|
|
194
|
+
*/
|
|
195
|
+
declare function isLazyCommand(value: unknown): value is LazyCommand;
|
|
196
|
+
/**
|
|
197
|
+
* Create a lazily-loaded subcommand with synchronous metadata.
|
|
198
|
+
*
|
|
199
|
+
* The `meta` command provides names, descriptions, and args schema
|
|
200
|
+
* for static analysis (completion scripts, help text) without loading
|
|
201
|
+
* the full command module.
|
|
202
|
+
*
|
|
203
|
+
* The `load` function is called only at execution time.
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* ```ts
|
|
207
|
+
* import { lazy, defineCommand } from "politty";
|
|
208
|
+
*
|
|
209
|
+
* const cli = defineCommand({
|
|
210
|
+
* name: "mycli",
|
|
211
|
+
* subCommands: {
|
|
212
|
+
* deploy: lazy(
|
|
213
|
+
* defineCommand({
|
|
214
|
+
* name: "deploy",
|
|
215
|
+
* description: "Deploy the application",
|
|
216
|
+
* args: z.object({ env: arg(z.string()) }),
|
|
217
|
+
* }),
|
|
218
|
+
* () => import("./deploy.js").then((m) => m.deployCommand),
|
|
219
|
+
* ),
|
|
220
|
+
* },
|
|
221
|
+
* });
|
|
222
|
+
* ```
|
|
223
|
+
*/
|
|
224
|
+
declare function lazy<T extends AnyCommand>(meta: T, load: () => Promise<AnyCommand>): LazyCommand<T>;
|
|
225
|
+
//#endregion
|
|
226
|
+
//#region ../core/src/types.d.ts
|
|
227
|
+
/**
|
|
228
|
+
* Global args interface for declaration merging (Pattern 3).
|
|
229
|
+
* Users can extend this interface to add global options to all commands:
|
|
230
|
+
*
|
|
231
|
+
* ```ts
|
|
232
|
+
* declare module "politty" {
|
|
233
|
+
* interface GlobalArgs { verbose: boolean; config?: string; }
|
|
234
|
+
* }
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
interface GlobalArgs {}
|
|
238
|
+
/**
|
|
239
|
+
* Detect empty interface (used for GlobalArgs declaration merging)
|
|
240
|
+
*/
|
|
241
|
+
type IsEmpty<T> = keyof T extends never ? true : false;
|
|
242
|
+
/**
|
|
243
|
+
* Where a resolved arg value came from:
|
|
244
|
+
* - `"cli"`: an explicit CLI token (flag or positional)
|
|
245
|
+
* - `"env"`: `field.env` fallback (no CLI token was provided)
|
|
246
|
+
* - `"default"`: neither of the above (e.g. a schema default, or a value
|
|
247
|
+
* resolved by a `prompt` handler)
|
|
248
|
+
*/
|
|
249
|
+
type ArgSource = "cli" | "env" | "default";
|
|
250
|
+
/**
|
|
251
|
+
* Example definition for a command
|
|
252
|
+
*/
|
|
253
|
+
interface Example {
|
|
254
|
+
/** Command arguments to execute (e.g., "World" or "--loud Alice") */
|
|
255
|
+
cmd: string;
|
|
256
|
+
/** Description of the example */
|
|
257
|
+
desc: string;
|
|
258
|
+
/** Expected output (optional, for documentation) */
|
|
259
|
+
output?: string;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Logger interface for CLI output
|
|
263
|
+
* Can be overridden by passing a custom logger to runMain or runCommand
|
|
264
|
+
*/
|
|
265
|
+
interface Logger {
|
|
266
|
+
/** Log informational message to stdout */
|
|
267
|
+
log(message: string): void;
|
|
268
|
+
/** Log error message to stderr */
|
|
269
|
+
error(message: string): void;
|
|
270
|
+
/** Log warning message to stderr */
|
|
271
|
+
warn?(message: string): void;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Supported schema types for args: any Standard Schema (zod, valibot, ...)
|
|
275
|
+
* whose output is an object. Adapter packages narrow this back to their
|
|
276
|
+
* library's own schema type in their public exports (e.g. `@politty/zod`
|
|
277
|
+
* exports `ArgsSchema = z.ZodType<Record<string, any>>`).
|
|
278
|
+
*/
|
|
279
|
+
type ArgsSchema = SchemaLike<Record<string, any>>;
|
|
280
|
+
/**
|
|
281
|
+
* Context provided to setup function
|
|
282
|
+
*/
|
|
283
|
+
interface SetupContext<TArgs = unknown> {
|
|
284
|
+
/** Parsed and validated arguments */
|
|
285
|
+
args: TArgs;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Context provided to cleanup function
|
|
289
|
+
*/
|
|
290
|
+
interface CleanupContext<TArgs = unknown> {
|
|
291
|
+
/** Parsed and validated arguments */
|
|
292
|
+
args: TArgs;
|
|
293
|
+
/** Error if command execution failed */
|
|
294
|
+
error?: Error | undefined;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Context provided to global setup function (runMain/runCommand level)
|
|
298
|
+
*/
|
|
299
|
+
interface GlobalSetupContext {}
|
|
300
|
+
/**
|
|
301
|
+
* Context provided to global cleanup function (runMain/runCommand level)
|
|
302
|
+
*/
|
|
303
|
+
interface GlobalCleanupContext {
|
|
304
|
+
/** Error if command execution failed */
|
|
305
|
+
error?: Error | undefined;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Base command interface (shared properties)
|
|
309
|
+
* @template TArgsSchema - The args schema type (from the CLI's schema library)
|
|
310
|
+
* @template TArgs - The inferred args type from the schema
|
|
311
|
+
*/
|
|
312
|
+
interface CommandBase<TArgsSchema extends ArgsSchema | undefined = undefined, TArgs = unknown> {
|
|
313
|
+
/** Command name (required) */
|
|
314
|
+
name: string;
|
|
315
|
+
/** Command description */
|
|
316
|
+
description?: string | undefined;
|
|
317
|
+
/** Alternative names for this command (used as subcommand aliases) */
|
|
318
|
+
aliases?: string[] | undefined;
|
|
319
|
+
/** Argument schema (preserves the original schema type) */
|
|
320
|
+
args: TArgsSchema;
|
|
321
|
+
/** Subcommands */
|
|
322
|
+
subCommands?: SubCommandsRecord | undefined;
|
|
323
|
+
/** Setup hook */
|
|
324
|
+
setup?: ((context: SetupContext<TArgs>) => void | Promise<void>) | undefined;
|
|
325
|
+
/** Cleanup hook */
|
|
326
|
+
cleanup?: ((context: CleanupContext<TArgs>) => void | Promise<void>) | undefined;
|
|
327
|
+
/** Additional notes */
|
|
328
|
+
notes?: string | undefined;
|
|
329
|
+
/** Example usages for this command */
|
|
330
|
+
examples?: Example[] | undefined;
|
|
331
|
+
/**
|
|
332
|
+
* @internal
|
|
333
|
+
* Hook invoked once at the top of `runMain`, before any parsing. Used
|
|
334
|
+
* by `withCompletionCommand` to fire its detached background-refresh
|
|
335
|
+
* spawn. Best-effort; never throws.
|
|
336
|
+
*/
|
|
337
|
+
runMainHook?: ((argv: readonly string[]) => void) | undefined;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* A command with a run function
|
|
341
|
+
* @template TArgsSchema - The args schema type (from the CLI's schema library)
|
|
342
|
+
* @template TArgs - The inferred args type from the schema
|
|
343
|
+
* @template TResult - The return type of the run function
|
|
344
|
+
*/
|
|
345
|
+
interface RunnableCommand<TArgsSchema extends ArgsSchema | undefined = undefined, TArgs = unknown, TResult = unknown> extends CommandBase<TArgsSchema, TArgs> {
|
|
346
|
+
/** Main run function */
|
|
347
|
+
run: (args: TArgs) => TResult;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* A command without a run function (e.g., subcommand-only parent)
|
|
351
|
+
* @template TArgsSchema - The args schema type (from the CLI's schema library)
|
|
352
|
+
* @template TArgs - The inferred args type from the schema
|
|
353
|
+
*/
|
|
354
|
+
interface NonRunnableCommand<TArgsSchema extends ArgsSchema | undefined = undefined, TArgs = unknown> extends CommandBase<TArgsSchema, TArgs> {
|
|
355
|
+
/** No run function */
|
|
356
|
+
run?: undefined;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* A defined command (union of runnable and non-runnable)
|
|
360
|
+
*/
|
|
361
|
+
type Command<TArgsSchema extends ArgsSchema | undefined = undefined, TArgs = unknown, TResult = unknown> = RunnableCommand<TArgsSchema, TArgs, TResult> | NonRunnableCommand<TArgsSchema, TArgs>;
|
|
362
|
+
/**
|
|
363
|
+
* Type alias for any args type.
|
|
364
|
+
* Note: `any` is required here due to TypeScript's function parameter contravariance.
|
|
365
|
+
* Using `unknown` would make it impossible to assign concrete command types to AnyCommand.
|
|
366
|
+
* @internal
|
|
367
|
+
*/
|
|
368
|
+
type AnyArgs = any;
|
|
369
|
+
/**
|
|
370
|
+
* Type alias for any result type.
|
|
371
|
+
* @internal
|
|
372
|
+
*/
|
|
373
|
+
type AnyResult = any;
|
|
374
|
+
/**
|
|
375
|
+
* Command type that accepts any args/result types
|
|
376
|
+
* Used in internal functions that don't need specific type information
|
|
377
|
+
*/
|
|
378
|
+
type AnyCommand = Command<ArgsSchema | undefined, AnyArgs, AnyResult>;
|
|
379
|
+
/**
|
|
380
|
+
* Subcommand value type (either a command or a lazy-loaded command)
|
|
381
|
+
*/
|
|
382
|
+
type SubCommandValue = AnyCommand | (() => Promise<AnyCommand>) | LazyCommand;
|
|
383
|
+
/**
|
|
384
|
+
* Record of subcommands indexed by name
|
|
385
|
+
*/
|
|
386
|
+
type SubCommandsRecord = Record<string, SubCommandValue>;
|
|
387
|
+
/**
|
|
388
|
+
* Async callback to resolve missing argument values interactively.
|
|
389
|
+
* Called after env fallback, before schema validation.
|
|
390
|
+
* Provided by adapter subpath modules (e.g. `politty/prompt/clack`).
|
|
391
|
+
*/
|
|
392
|
+
type PromptResolver = (rawArgs: Record<string, unknown>, extracted: ExtractedFields) => Promise<Record<string, unknown>>;
|
|
393
|
+
/**
|
|
394
|
+
* Options for runMain (CLI entry point)
|
|
395
|
+
*/
|
|
396
|
+
interface MainOptions {
|
|
397
|
+
/** Command version */
|
|
398
|
+
version?: string;
|
|
399
|
+
/** Enable debug mode (show stack traces on errors) */
|
|
400
|
+
debug?: boolean;
|
|
401
|
+
/** Capture console output during execution (default: false) */
|
|
402
|
+
captureLogs?: boolean;
|
|
403
|
+
/** Skip command definition validation (useful in production where tests already verified) */
|
|
404
|
+
skipValidation?: boolean;
|
|
405
|
+
/** Custom logger for output (default: console) */
|
|
406
|
+
logger?: Logger;
|
|
407
|
+
/** Global args schema (shared across all subcommands) */
|
|
408
|
+
globalArgs?: ArgsSchema;
|
|
409
|
+
/** Global setup hook (runs before command execution) */
|
|
410
|
+
setup?: ((context: GlobalSetupContext) => void | Promise<void>) | undefined;
|
|
411
|
+
/** Global cleanup hook (runs after command execution, always executes even on error) */
|
|
412
|
+
cleanup?: ((context: GlobalCleanupContext) => void | Promise<void>) | undefined;
|
|
413
|
+
/** Whether to display errors to stderr before process.exit (default: true) */
|
|
414
|
+
displayErrors?: boolean;
|
|
415
|
+
/** Prompt resolver for interactive missing-arg prompts (e.g. from `politty/prompt/clack`). */
|
|
416
|
+
prompt?: PromptResolver | undefined;
|
|
417
|
+
/**
|
|
418
|
+
* Fallback hook for CLI plugin dispatch, invoked when a positional is not a
|
|
419
|
+
* known subcommand at any level whose command exposes subcommands (e.g. exec
|
|
420
|
+
* an external `<cli>-<path...>-<name>` binary).
|
|
421
|
+
*
|
|
422
|
+
* Return a number to treat it as handled and exit with that code; return
|
|
423
|
+
* `undefined` (or omit) to fall back to the default unknown-subcommand/help
|
|
424
|
+
* behavior. Not invoked for internal `__*` subcommands.
|
|
425
|
+
*/
|
|
426
|
+
onUnknownSubcommand?: UnknownSubcommandHandler | undefined;
|
|
427
|
+
/**
|
|
428
|
+
* Node.js on-disk compile cache (V8 code cache) control. `runMain` enables
|
|
429
|
+
* it before executing the command so dynamically imported modules (e.g.
|
|
430
|
+
* `lazy()` subcommands) skip recompilation on warm starts (Node >= 22.8.0;
|
|
431
|
+
* no-op otherwise).
|
|
432
|
+
* - omitted / `true`: derive the directory from the command name
|
|
433
|
+
* (`${XDG_CACHE_HOME:-$HOME/.cache}/<sanitized name>/node-compile-cache`,
|
|
434
|
+
* shared with shell-completion workers; the name is reduced to a single
|
|
435
|
+
* safe path segment, e.g. `@scope/cli` → `scope-cli`)
|
|
436
|
+
* - `string`: use this cache directory
|
|
437
|
+
* - `false`: do not enable
|
|
438
|
+
*
|
|
439
|
+
* The `NODE_COMPILE_CACHE` environment variable always takes precedence.
|
|
440
|
+
* Note: the entry module's static import graph is compiled before `runMain`
|
|
441
|
+
* runs and cannot be cached here — see `politty/compile-cache` for the
|
|
442
|
+
* bin-shim pattern that covers it.
|
|
443
|
+
*/
|
|
444
|
+
compileCache?: boolean | string;
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Handler for an unrecognized subcommand. See {@link MainOptions.onUnknownSubcommand}.
|
|
448
|
+
*/
|
|
449
|
+
type UnknownSubcommandHandler = (context: {
|
|
450
|
+
/**
|
|
451
|
+
* Known subcommand names traversed before the unknown name (excludes the
|
|
452
|
+
* root command name). Empty at the root level.
|
|
453
|
+
*/
|
|
454
|
+
commandPath: readonly string[];
|
|
455
|
+
/** The unrecognized subcommand name (first unmatched positional). */
|
|
456
|
+
name: string;
|
|
457
|
+
/** Args following the name, forwarded verbatim to the plugin. */
|
|
458
|
+
args: readonly string[];
|
|
459
|
+
/**
|
|
460
|
+
* Option tokens the host consumed before the unknown name across every
|
|
461
|
+
* traversed level (e.g. global flags typed before the plugin command),
|
|
462
|
+
* excluding the traversed subcommand names themselves. Concatenate with
|
|
463
|
+
* `args` to reconstruct the user's full flag set when forwarding to a
|
|
464
|
+
* plugin: `[...precedingArgs, ...args]`.
|
|
465
|
+
*/
|
|
466
|
+
precedingArgs: readonly string[];
|
|
467
|
+
}) => number | undefined | Promise<number | undefined>;
|
|
468
|
+
/**
|
|
469
|
+
* Options for runCommand (programmatic/test usage)
|
|
470
|
+
*/
|
|
471
|
+
interface RunCommandOptions {
|
|
472
|
+
/** Enable debug mode (show stack traces on errors) */
|
|
473
|
+
debug?: boolean;
|
|
474
|
+
/** Capture console output during execution (default: false) */
|
|
475
|
+
captureLogs?: boolean;
|
|
476
|
+
/** Skip command definition validation (useful in production where tests already verified) */
|
|
477
|
+
skipValidation?: boolean;
|
|
478
|
+
/** Custom logger for output (default: console) */
|
|
479
|
+
logger?: Logger;
|
|
480
|
+
/** Global args schema (shared across all subcommands) */
|
|
481
|
+
globalArgs?: ArgsSchema;
|
|
482
|
+
/** Global setup hook (runs before command execution) */
|
|
483
|
+
setup?: ((context: GlobalSetupContext) => void | Promise<void>) | undefined;
|
|
484
|
+
/** Global cleanup hook (runs after command execution, always executes even on error) */
|
|
485
|
+
cleanup?: ((context: GlobalCleanupContext) => void | Promise<void>) | undefined;
|
|
486
|
+
/** Prompt resolver for interactive missing-arg prompts (e.g. from `politty/prompt/clack`). */
|
|
487
|
+
prompt?: PromptResolver | undefined;
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Log level type
|
|
491
|
+
*/
|
|
492
|
+
type LogLevel = "log" | "info" | "debug" | "warn" | "error";
|
|
493
|
+
/**
|
|
494
|
+
* Output stream type
|
|
495
|
+
*/
|
|
496
|
+
type LogStream = "stdout" | "stderr";
|
|
497
|
+
/**
|
|
498
|
+
* A single log entry collected during command execution
|
|
499
|
+
*/
|
|
500
|
+
interface LogEntry {
|
|
501
|
+
/** Log message */
|
|
502
|
+
message: string;
|
|
503
|
+
/** Timestamp when the log was recorded */
|
|
504
|
+
timestamp: Date;
|
|
505
|
+
/** Log level */
|
|
506
|
+
level: LogLevel;
|
|
507
|
+
/** Output stream (stdout or stderr) */
|
|
508
|
+
stream: LogStream;
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Collected logs during command execution
|
|
512
|
+
*/
|
|
513
|
+
interface CollectedLogs {
|
|
514
|
+
/** All log entries in order */
|
|
515
|
+
entries: LogEntry[];
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Successful command execution result
|
|
519
|
+
*/
|
|
520
|
+
interface RunResultSuccess<T = unknown> {
|
|
521
|
+
/** Indicates successful execution */
|
|
522
|
+
success: true;
|
|
523
|
+
/** Command return value */
|
|
524
|
+
result: T | undefined;
|
|
525
|
+
/** Error that occurred during execution */
|
|
526
|
+
error?: never;
|
|
527
|
+
/** Exit code (always 0 for success) */
|
|
528
|
+
exitCode: 0;
|
|
529
|
+
/** Collected logs during execution */
|
|
530
|
+
logs: CollectedLogs;
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Failed command execution result
|
|
534
|
+
*/
|
|
535
|
+
interface RunResultFailure {
|
|
536
|
+
/** Indicates failed execution */
|
|
537
|
+
success: false;
|
|
538
|
+
/** Command return value */
|
|
539
|
+
result?: never;
|
|
540
|
+
/** Error that occurred during execution */
|
|
541
|
+
error: Error;
|
|
542
|
+
/** Exit code (non-zero for failure) */
|
|
543
|
+
exitCode: number;
|
|
544
|
+
/** Collected logs during execution */
|
|
545
|
+
logs: CollectedLogs;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Result of command execution (discriminated union)
|
|
549
|
+
*/
|
|
550
|
+
type RunResult<T = unknown> = RunResultSuccess<T> | RunResultFailure;
|
|
551
|
+
//#endregion
|
|
552
|
+
//#region ../core/src/core/dynamic-completion-types.d.ts
|
|
553
|
+
/**
|
|
554
|
+
* Types for in-process dynamic value completion.
|
|
555
|
+
*
|
|
556
|
+
* A `resolve` callback registered on `arg(...)` receives parsed context
|
|
557
|
+
* (other arg values typed so far, previous values supplied to the same
|
|
558
|
+
* option, the current word being completed, target shell) and returns
|
|
559
|
+
* candidates. The callback runs inside the `__complete` command. Dispatcher
|
|
560
|
+
* shell scripts call `__complete` for every completion request; static shell
|
|
561
|
+
* scripts delegate to it for any spec that uses `resolve`.
|
|
562
|
+
*
|
|
563
|
+
* Defined under `core/` (not `completion/`) so `arg-registry.ts` can
|
|
564
|
+
* reference the resolver type without crossing the lint-enforced
|
|
565
|
+
* `completion → core` boundary.
|
|
566
|
+
*/
|
|
567
|
+
/** Bitmask combining `CompletionDirective` values. */
|
|
568
|
+
type CompletionDirectiveMask = number;
|
|
569
|
+
interface DynamicCompletionContext {
|
|
570
|
+
/** Word being completed. `--field=` inline prefix is stripped before this is set. */
|
|
571
|
+
currentWord: string;
|
|
572
|
+
/** Target shell formatting requested by the caller. */
|
|
573
|
+
shell: "bash" | "zsh" | "fish";
|
|
574
|
+
/**
|
|
575
|
+
* Best-effort parsed values of OTHER args on the same command, keyed by
|
|
576
|
+
* camelCase name. Includes positionals and other options. Zod validation
|
|
577
|
+
* is NOT applied; values are raw strings (or arrays of raw strings for
|
|
578
|
+
* array-typed options/variadic positionals).
|
|
579
|
+
*/
|
|
580
|
+
parsedArgs: Readonly<Record<string, unknown>>;
|
|
581
|
+
/**
|
|
582
|
+
* Values already supplied for the SAME option/positional being completed.
|
|
583
|
+
* Useful for de-duplicating repeated array options.
|
|
584
|
+
*/
|
|
585
|
+
previousValues: readonly string[];
|
|
586
|
+
/**
|
|
587
|
+
* Subcommand path from root (e.g. ["api"]). Reflects what the user
|
|
588
|
+
* actually typed — aliases are NOT resolved to their canonical names, so
|
|
589
|
+
* resolvers that branch on the path should accept every alias they care
|
|
590
|
+
* about.
|
|
591
|
+
*/
|
|
592
|
+
subcommandPath: readonly string[];
|
|
593
|
+
}
|
|
594
|
+
interface DynamicCompletionCandidate {
|
|
595
|
+
value: string;
|
|
596
|
+
description?: string;
|
|
597
|
+
}
|
|
598
|
+
interface DynamicCompletionResult {
|
|
599
|
+
/** Candidates to surface. Strings or `{value, description}` objects. */
|
|
600
|
+
candidates: Array<string | DynamicCompletionCandidate>;
|
|
601
|
+
/**
|
|
602
|
+
* Optional directive override. When omitted, defaults to
|
|
603
|
+
* `FilterPrefix | NoFileCompletion` (matches `choices` behaviour).
|
|
604
|
+
*/
|
|
605
|
+
directive?: CompletionDirectiveMask;
|
|
606
|
+
}
|
|
607
|
+
type DynamicCompletionResolver = (ctx: DynamicCompletionContext) => DynamicCompletionResult | Promise<DynamicCompletionResult>;
|
|
608
|
+
//#endregion
|
|
609
|
+
//#region ../core/src/core/expand-completion-types.d.ts
|
|
610
|
+
/**
|
|
611
|
+
* Types for "expand" completion — candidates that depend on sibling arg
|
|
612
|
+
* values.
|
|
613
|
+
*
|
|
614
|
+
* The user provides `dependsOn` (sibling arg names that must have static
|
|
615
|
+
* `choices` or an enum schema) and `enumerate(deps)`. Dispatcher scripts call
|
|
616
|
+
* `enumerate` inside `__complete` for the dependency values already typed on
|
|
617
|
+
* the command line. Static scripts walk the cartesian product of the
|
|
618
|
+
* dependsOn values, call `enumerate` for each combination, and emit a shell
|
|
619
|
+
* lookup table.
|
|
620
|
+
*
|
|
621
|
+
* Defined under `core/` (not `completion/`) so `arg-registry.ts` can
|
|
622
|
+
* reference these types without crossing the lint-enforced
|
|
623
|
+
* `completion → core` boundary.
|
|
624
|
+
*/
|
|
625
|
+
/** Candidate returned by an `enumerate` callback. */
|
|
626
|
+
interface ExpandCandidate {
|
|
627
|
+
value: string;
|
|
628
|
+
description?: string;
|
|
629
|
+
}
|
|
630
|
+
/** Resolved candidate stored on a {@link ValueCompletion} after enumeration. */
|
|
631
|
+
interface ResolvedExpandCandidate {
|
|
632
|
+
value: string;
|
|
633
|
+
description?: string;
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* User-facing spec attached to `completion.custom.expand`.
|
|
637
|
+
*
|
|
638
|
+
* `dependsOn` lists sibling args (camelCase names) whose values determine
|
|
639
|
+
* which candidates apply. Each named arg must have a static set of values —
|
|
640
|
+
* either an explicit `completion.custom.choices` or an enum schema. The
|
|
641
|
+
* order of `dependsOn` is the order in which `deps` keys are exposed to
|
|
642
|
+
* `enumerate`.
|
|
643
|
+
*
|
|
644
|
+
* In dispatcher mode, `enumerate` runs during `__complete` for the dependency
|
|
645
|
+
* values already typed by the user. In static mode, it runs once per
|
|
646
|
+
* cartesian-product combination at script-generation time (e.g. when the user
|
|
647
|
+
* runs `<program> completion zsh --static`). It must be a pure function of
|
|
648
|
+
* `deps`.
|
|
649
|
+
*/
|
|
650
|
+
interface ExpandCompletion {
|
|
651
|
+
dependsOn: readonly string[];
|
|
652
|
+
enumerate: (deps: Readonly<Record<string, string>>) => ReadonlyArray<string | ExpandCandidate>;
|
|
653
|
+
}
|
|
654
|
+
//#endregion
|
|
655
|
+
//#region ../core/src/core/arg-registry.d.ts
|
|
656
|
+
/**
|
|
657
|
+
* Built-in completion types
|
|
658
|
+
*/
|
|
659
|
+
type CompletionType = "file" | "directory" | "none";
|
|
660
|
+
/**
|
|
661
|
+
* Custom completion specification.
|
|
662
|
+
*
|
|
663
|
+
* `choices`, `shellCommand`, `resolve`, and `expand` are mutually exclusive —
|
|
664
|
+
* specifying more than one throws when the field metadata is resolved.
|
|
665
|
+
*/
|
|
666
|
+
interface CustomCompletion {
|
|
667
|
+
/** Static list of choices for completion */
|
|
668
|
+
choices?: string[];
|
|
669
|
+
/** Shell command to execute for dynamic completion */
|
|
670
|
+
shellCommand?: string;
|
|
671
|
+
/**
|
|
672
|
+
* In-process JS callback for dynamic completion. Receives parsed context
|
|
673
|
+
* (other arg values typed so far, previously supplied values for this same
|
|
674
|
+
* option) and returns candidates. Dispatcher scripts call
|
|
675
|
+
* `<program> __complete` for every completion request; static scripts
|
|
676
|
+
* delegate to it whenever this is set.
|
|
677
|
+
*/
|
|
678
|
+
resolve?: DynamicCompletionResolver;
|
|
679
|
+
/**
|
|
680
|
+
* Completion whose candidates depend on sibling arg values. Dispatcher
|
|
681
|
+
* scripts call `enumerate` inside `__complete` for the dependency values
|
|
682
|
+
* already typed on the command line. Static scripts pre-enumerate every
|
|
683
|
+
* combination of `dependsOn` values at script-generation time and dispatch
|
|
684
|
+
* via a shell lookup table.
|
|
685
|
+
*/
|
|
686
|
+
expand?: ExpandCompletion;
|
|
687
|
+
}
|
|
688
|
+
/**
|
|
689
|
+
* Completion metadata for an argument
|
|
690
|
+
*
|
|
691
|
+
* @example
|
|
692
|
+
* ```ts
|
|
693
|
+
* // File completion with extension filter
|
|
694
|
+
* input: arg(z.string(), {
|
|
695
|
+
* completion: { type: "file", extensions: ["json", "yaml"] }
|
|
696
|
+
* })
|
|
697
|
+
*
|
|
698
|
+
* // Directory completion
|
|
699
|
+
* outputDir: arg(z.string(), {
|
|
700
|
+
* completion: { type: "directory" }
|
|
701
|
+
* })
|
|
702
|
+
*
|
|
703
|
+
* // Custom static choices
|
|
704
|
+
* logLevel: arg(z.string(), {
|
|
705
|
+
* completion: { custom: { choices: ["debug", "info", "warn", "error"] } }
|
|
706
|
+
* })
|
|
707
|
+
*
|
|
708
|
+
* // Dynamic completion from shell command
|
|
709
|
+
* branch: arg(z.string(), {
|
|
710
|
+
* completion: { custom: { shellCommand: "git branch --format='%(refname:short)'" } }
|
|
711
|
+
* })
|
|
712
|
+
*
|
|
713
|
+
* // File completion with glob pattern matcher
|
|
714
|
+
* envFile: arg(z.string(), {
|
|
715
|
+
* completion: { type: "file", matcher: [".env.*"] }
|
|
716
|
+
* })
|
|
717
|
+
* ```
|
|
718
|
+
*/
|
|
719
|
+
type CompletionMeta = {
|
|
720
|
+
/** Built-in completion type */
|
|
721
|
+
type?: CompletionType;
|
|
722
|
+
/** Custom completion (takes precedence over type if both specified) */
|
|
723
|
+
custom?: CustomCompletion;
|
|
724
|
+
} & ({
|
|
725
|
+
/** File extension filter (only applies when type is "file") */ extensions?: string[];
|
|
726
|
+
matcher?: never;
|
|
727
|
+
} | {
|
|
728
|
+
/** Glob patterns for file matching (only applies when type is "file") */ matcher?: string[];
|
|
729
|
+
extensions?: never;
|
|
730
|
+
});
|
|
731
|
+
/**
|
|
732
|
+
* Prompt input type for interactive prompts
|
|
733
|
+
*
|
|
734
|
+
* - "text": free-form text input (default for string schemas)
|
|
735
|
+
* - "password": masked text input
|
|
736
|
+
* - "confirm": yes/no prompt (default for boolean schemas)
|
|
737
|
+
* - "select": single selection from choices (default for enum schemas)
|
|
738
|
+
* - "file": file path input (inherited from completion type)
|
|
739
|
+
* - "directory": directory path input (inherited from completion type)
|
|
740
|
+
*/
|
|
741
|
+
type PromptType = "text" | "password" | "confirm" | "select" | "file" | "directory";
|
|
742
|
+
/**
|
|
743
|
+
* Prompt metadata for interactive input when a value is missing.
|
|
744
|
+
* Used by the `politty/prompt` module to request user input for unresolved arguments.
|
|
745
|
+
*
|
|
746
|
+
* @example
|
|
747
|
+
* ```ts
|
|
748
|
+
* // Custom prompt message
|
|
749
|
+
* name: arg(z.string(), {
|
|
750
|
+
* prompt: { message: "What is your name?" }
|
|
751
|
+
* })
|
|
752
|
+
*
|
|
753
|
+
* // Password input (masked)
|
|
754
|
+
* token: arg(z.string(), {
|
|
755
|
+
* prompt: { type: "password", message: "Enter API token" }
|
|
756
|
+
* })
|
|
757
|
+
*
|
|
758
|
+
* // Select with custom choices
|
|
759
|
+
* region: arg(z.string(), {
|
|
760
|
+
* prompt: { choices: ["us-east-1", "eu-west-1", "ap-northeast-1"] }
|
|
761
|
+
* })
|
|
762
|
+
* ```
|
|
763
|
+
*/
|
|
764
|
+
interface PromptMeta {
|
|
765
|
+
/** Prompt message shown to the user. Defaults to the field's description or name. */
|
|
766
|
+
message?: string;
|
|
767
|
+
/** Explicit prompt type. Overrides auto-detection from schema/completion. */
|
|
768
|
+
type?: PromptType;
|
|
769
|
+
/** Choices for select prompt. Overrides enum values from schema. */
|
|
770
|
+
choices?: Array<string | {
|
|
771
|
+
label: string;
|
|
772
|
+
value: string;
|
|
773
|
+
}>;
|
|
774
|
+
/** Whether to enable prompting for this field (default: true when prompt is set) */
|
|
775
|
+
enabled?: boolean;
|
|
776
|
+
}
|
|
777
|
+
/**
|
|
778
|
+
* Context provided to effect callbacks.
|
|
779
|
+
* When GlobalArgs is extended via declaration merging, `globalArgs` is typed accordingly.
|
|
780
|
+
*/
|
|
781
|
+
type EffectContext = {
|
|
782
|
+
/** Field name (camelCase) */
|
|
783
|
+
name: string;
|
|
784
|
+
/** Validated args for this schema (global args for global effects, command args for command effects) */
|
|
785
|
+
args: Readonly<Record<string, unknown>>;
|
|
786
|
+
} & (IsEmpty<GlobalArgs> extends true ? {
|
|
787
|
+
globalArgs?: Readonly<Record<string, unknown>>;
|
|
788
|
+
} : {
|
|
789
|
+
globalArgs?: Readonly<GlobalArgs>;
|
|
790
|
+
});
|
|
791
|
+
/**
|
|
792
|
+
* Base metadata shared by all argument types
|
|
793
|
+
*/
|
|
794
|
+
interface BaseArgMeta<TValue = unknown> {
|
|
795
|
+
/** Argument description */
|
|
796
|
+
description?: string;
|
|
797
|
+
/** Treat as positional argument */
|
|
798
|
+
positional?: boolean;
|
|
799
|
+
/** Placeholder for help display */
|
|
800
|
+
placeholder?: string;
|
|
801
|
+
/**
|
|
802
|
+
* Environment variable name(s) to read value from.
|
|
803
|
+
* If an array is provided, earlier entries take priority.
|
|
804
|
+
* CLI arguments always take precedence over environment variables.
|
|
805
|
+
*
|
|
806
|
+
* @example
|
|
807
|
+
* ```ts
|
|
808
|
+
* // Single env var
|
|
809
|
+
* port: arg(z.coerce.number(), { env: "PORT" })
|
|
810
|
+
*
|
|
811
|
+
* // Multiple env vars (PORT takes priority over SERVER_PORT)
|
|
812
|
+
* port: arg(z.coerce.number(), { env: ["PORT", "SERVER_PORT"] })
|
|
813
|
+
* ```
|
|
814
|
+
*/
|
|
815
|
+
env?: string | string[];
|
|
816
|
+
/** Completion configuration for shell tab-completion */
|
|
817
|
+
completion?: CompletionMeta;
|
|
818
|
+
/**
|
|
819
|
+
* Interactive prompt configuration for missing values.
|
|
820
|
+
* When set, the `politty/prompt` module will prompt the user interactively
|
|
821
|
+
* if this argument is not provided via CLI args or environment variables.
|
|
822
|
+
*
|
|
823
|
+
* @example
|
|
824
|
+
* ```ts
|
|
825
|
+
* name: arg(z.string(), {
|
|
826
|
+
* description: "User name",
|
|
827
|
+
* prompt: { message: "What is your name?" },
|
|
828
|
+
* })
|
|
829
|
+
* ```
|
|
830
|
+
*/
|
|
831
|
+
prompt?: PromptMeta;
|
|
832
|
+
/**
|
|
833
|
+
* Control the boolean negation option.
|
|
834
|
+
*
|
|
835
|
+
* Boolean fields accept `--no-<cliName>` (and the camelCase `--no<Name>`
|
|
836
|
+
* form) to set the value to `false` only when `negation: true` is set.
|
|
837
|
+
* By default no negation form is accepted. This option lets you customize
|
|
838
|
+
* or expose that behavior:
|
|
839
|
+
*
|
|
840
|
+
* - `string` — replaces the auto-generated `--no-*` form with a custom
|
|
841
|
+
* name. The default `--no-*` is no longer recognized.
|
|
842
|
+
* - `true` — enables the default `--no-<cliName>` form and advertises it
|
|
843
|
+
* in help, generated docs, and shell completions.
|
|
844
|
+
* - `false` — disables negation entirely; same as the default, but explicit.
|
|
845
|
+
* Neither the default `--no-*` nor any custom name is accepted.
|
|
846
|
+
*
|
|
847
|
+
* String values follow the same naming conventions as `cliName`
|
|
848
|
+
* (kebab-case is recommended). Only valid on boolean fields; setting
|
|
849
|
+
* `negation` on a non-boolean field is a type error and raises a
|
|
850
|
+
* runtime error during command parsing.
|
|
851
|
+
*
|
|
852
|
+
* @example
|
|
853
|
+
* ```ts
|
|
854
|
+
* // Custom negation name
|
|
855
|
+
* cache: arg(z.boolean().default(true), {
|
|
856
|
+
* description: "Enable caching",
|
|
857
|
+
* negation: "disable-cache",
|
|
858
|
+
* })
|
|
859
|
+
* // Accepts: --cache (true), --disable-cache (false)
|
|
860
|
+
* // No longer accepts: --no-cache
|
|
861
|
+
*
|
|
862
|
+
* // Enable default `--no-X` in parsing/help/docs/completion
|
|
863
|
+
* verbose: arg(z.boolean().default(false), {
|
|
864
|
+
* negation: true,
|
|
865
|
+
* })
|
|
866
|
+
* // Help shows `--verbose / --no-verbose`
|
|
867
|
+
*
|
|
868
|
+
* // Disable negation entirely
|
|
869
|
+
* dryRun: arg(z.boolean().default(false), {
|
|
870
|
+
* negation: false,
|
|
871
|
+
* })
|
|
872
|
+
* // Accepts: --dry-run (true)
|
|
873
|
+
* // No longer accepts: --no-dry-run
|
|
874
|
+
* ```
|
|
875
|
+
*/
|
|
876
|
+
negation?: string | boolean;
|
|
877
|
+
/**
|
|
878
|
+
* Description shown for the negation option in help and generated docs.
|
|
879
|
+
* Only meaningful when `negation` is set to a custom name string or `true`.
|
|
880
|
+
* Disallowed when `negation` is `false`.
|
|
881
|
+
*/
|
|
882
|
+
negationDescription?: string;
|
|
883
|
+
/**
|
|
884
|
+
* Side-effect callback executed after argument parsing and validation.
|
|
885
|
+
* Runs before the command lifecycle (setup/run/cleanup).
|
|
886
|
+
* Use Zod .transform() for value transformation instead.
|
|
887
|
+
*
|
|
888
|
+
* @example
|
|
889
|
+
* ```ts
|
|
890
|
+
* verbose: arg(z.boolean().default(false), {
|
|
891
|
+
* alias: "v",
|
|
892
|
+
* effect: (value) => {
|
|
893
|
+
* if (value) logger.setLevel("debug");
|
|
894
|
+
* },
|
|
895
|
+
* })
|
|
896
|
+
* ```
|
|
897
|
+
*/
|
|
898
|
+
effect?: (value: TValue, context: EffectContext) => void | PromiseLike<void>;
|
|
899
|
+
}
|
|
900
|
+
/**
|
|
901
|
+
* Metadata for regular arguments (non-builtin aliases)
|
|
902
|
+
*
|
|
903
|
+
* `alias` accepts either a single string or an array of strings.
|
|
904
|
+
* Single-character entries become short options (e.g. `-v`); multi-character
|
|
905
|
+
* entries become additional long options (e.g. `--to-be` for `--tobe`).
|
|
906
|
+
*/
|
|
907
|
+
interface RegularArgMeta<TValue = unknown> extends BaseArgMeta<TValue> {
|
|
908
|
+
/**
|
|
909
|
+
* Alias name(s) for this option.
|
|
910
|
+
* - 1-char string → short alias (`-v`)
|
|
911
|
+
* - >1-char string → long alias (`--long-name`)
|
|
912
|
+
* - array → multiple aliases of either kind
|
|
913
|
+
*/
|
|
914
|
+
alias?: string | string[] | readonly string[];
|
|
915
|
+
/**
|
|
916
|
+
* Alias name(s) that are accepted by the parser but hidden from help,
|
|
917
|
+
* generated docs, and shell completion. Useful for legacy or deprecated
|
|
918
|
+
* names that should still work without being advertised.
|
|
919
|
+
*/
|
|
920
|
+
hiddenAlias?: string | string[] | readonly string[];
|
|
921
|
+
}
|
|
922
|
+
/**
|
|
923
|
+
* Metadata for overriding built-in aliases (-h, -H)
|
|
924
|
+
*/
|
|
925
|
+
interface BuiltinOverrideArgMeta<TValue = unknown> extends BaseArgMeta<TValue> {
|
|
926
|
+
/** Built-in alias to override ('h' or 'H'), optionally combined with extra aliases */
|
|
927
|
+
alias: "h" | "H" | Array<"h" | "H" | string> | ReadonlyArray<"h" | "H" | string>;
|
|
928
|
+
/** Hidden aliases (accepted but not surfaced in help/docs/completion) */
|
|
929
|
+
hiddenAlias?: string | string[] | readonly string[];
|
|
930
|
+
/** Must be true to override built-in aliases */
|
|
931
|
+
overrideBuiltinAlias: true;
|
|
932
|
+
}
|
|
933
|
+
/**
|
|
934
|
+
* Metadata options for argument definition
|
|
935
|
+
*/
|
|
936
|
+
type ArgMeta<TValue = unknown> = RegularArgMeta<TValue> | BuiltinOverrideArgMeta<TValue>;
|
|
937
|
+
/**
|
|
938
|
+
* Register metadata for a schema
|
|
939
|
+
*
|
|
940
|
+
* @param schema - The schema to attach metadata to
|
|
941
|
+
* @param meta - Argument metadata
|
|
942
|
+
* @returns The same schema (for chaining)
|
|
943
|
+
*
|
|
944
|
+
* @example
|
|
945
|
+
* ```ts
|
|
946
|
+
* import { z } from "zod";
|
|
947
|
+
* import { arg, defineCommand } from "politty";
|
|
948
|
+
*
|
|
949
|
+
* const cmd = defineCommand({
|
|
950
|
+
* args: z.object({
|
|
951
|
+
* name: arg(z.string(), { description: "User name", positional: true }),
|
|
952
|
+
* verbose: arg(z.boolean().default(false), { alias: "v" }),
|
|
953
|
+
* }),
|
|
954
|
+
* run: (args) => {
|
|
955
|
+
* console.log(args.name, args.verbose);
|
|
956
|
+
* },
|
|
957
|
+
* });
|
|
958
|
+
* ```
|
|
959
|
+
*/
|
|
960
|
+
/**
|
|
961
|
+
* Detect whether `A` contains a reserved alias ("h" or "H"), for either a
|
|
962
|
+
* plain string or a tuple/array of strings. Uses `[A] extends [never]` to
|
|
963
|
+
* prevent distribution returning `never` for missing fields.
|
|
964
|
+
*/
|
|
965
|
+
type ContainsReservedAlias<A> = [A] extends [never] ? false : A extends "h" | "H" ? true : A extends readonly (infer E)[] ? [Extract<E, "h" | "H">] extends [never] ? false : true : false;
|
|
966
|
+
type ReservedAliasTypeError<M> = { [K in keyof M]: M[K]; } & {
|
|
967
|
+
__typeError: "Alias 'h' or 'H' requires overrideBuiltinAlias: true";
|
|
968
|
+
};
|
|
969
|
+
type NegationTypeError<M> = { [K in keyof M]: M[K]; } & {
|
|
970
|
+
__typeError: "negation/negationDescription can only be used on boolean fields";
|
|
971
|
+
};
|
|
972
|
+
type AliasFieldOf<M> = M extends {
|
|
973
|
+
alias: infer A;
|
|
974
|
+
} ? A : never;
|
|
975
|
+
type HiddenAliasFieldOf<M> = M extends {
|
|
976
|
+
hiddenAlias: infer H;
|
|
977
|
+
} ? H : never;
|
|
978
|
+
/**
|
|
979
|
+
* Check whether a Zod output type is a (possibly optional) boolean.
|
|
980
|
+
* Strips `undefined` to allow `z.boolean().optional()`. Requires both
|
|
981
|
+
* `boolean extends NonNullable<T>` (so `z.literal(true)` is rejected — the full
|
|
982
|
+
* `boolean` domain is needed) and `NonNullable<T> extends boolean` (so unions
|
|
983
|
+
* such as `z.union([z.boolean(), z.string()])` are rejected at the type level
|
|
984
|
+
* to match the runtime check).
|
|
985
|
+
*/
|
|
986
|
+
type IsBooleanField<T> = boolean extends NonNullable<T> ? ([NonNullable<T>] extends [boolean] ? true : false) : false;
|
|
987
|
+
/**
|
|
988
|
+
* Detect whether `M` has `K` set to a non-undefined value.
|
|
989
|
+
*
|
|
990
|
+
* When `M` is inferred from a literal such as `{ negation: "off" }`,
|
|
991
|
+
* `M["negation"]` is `"off"` (without `undefined`), so this returns `true`.
|
|
992
|
+
* When `M` is the wider `ArgMeta` type, `M["negation"]` is
|
|
993
|
+
* `string | boolean | undefined`, so this returns `false` and avoids
|
|
994
|
+
* false-positive type errors on broadly-typed meta values.
|
|
995
|
+
*/
|
|
996
|
+
type HasExplicit<M, K extends string> = K extends keyof M ? undefined extends M[K] ? false : true : false;
|
|
997
|
+
/**
|
|
998
|
+
* Reject `negation` / `negationDescription` on non-boolean fields.
|
|
999
|
+
* Uses {@link HasExplicit} so the error only fires when the user explicitly
|
|
1000
|
+
* sets the field on a narrowly-inferred meta literal.
|
|
1001
|
+
*/
|
|
1002
|
+
type ValidateNegation<M, TValue> = HasExplicit<M, "negation"> extends true ? IsBooleanField<TValue> extends true ? M : NegationTypeError<M> : HasExplicit<M, "negationDescription"> extends true ? IsBooleanField<TValue> extends true ? M : NegationTypeError<M> : M;
|
|
1003
|
+
/**
|
|
1004
|
+
* Type helper to validate ArgMeta.
|
|
1005
|
+
* Forces a type error when a reserved alias ("h" / "H") is used without
|
|
1006
|
+
* `overrideBuiltinAlias: true`, whether the alias is provided as a string
|
|
1007
|
+
* or as part of an array, and whether it appears in `alias` or `hiddenAlias`.
|
|
1008
|
+
* Also rejects `negation` / `negationDescription` on non-boolean fields.
|
|
1009
|
+
*/
|
|
1010
|
+
type ValidateArgMeta<M, TValue = unknown> = M extends {
|
|
1011
|
+
overrideBuiltinAlias: true;
|
|
1012
|
+
} ? ValidateNegation<M, TValue> : ContainsReservedAlias<AliasFieldOf<M>> extends true ? ReservedAliasTypeError<M> : ContainsReservedAlias<HiddenAliasFieldOf<M>> extends true ? ReservedAliasTypeError<M> : ValidateNegation<M, TValue>;
|
|
1013
|
+
/**
|
|
1014
|
+
* The overloaded `arg()` signature, parameterized by the schema constraint.
|
|
1015
|
+
* Core's `arg` accepts any Standard Schema; adapter packages re-pin the same
|
|
1016
|
+
* runtime function to their library's schema type (e.g. `ArgFn<z.ZodType>`
|
|
1017
|
+
* in `@politty/zod`) so a schema from the wrong library is rejected at the
|
|
1018
|
+
* type level.
|
|
1019
|
+
*/
|
|
1020
|
+
interface ArgFn<TSchemaBase extends SchemaLike = SchemaLike> {
|
|
1021
|
+
<T extends TSchemaBase>(schema: T): T;
|
|
1022
|
+
<T extends TSchemaBase, M extends ArgMeta<InferSchemaOutput<T>>>(schema: T, meta: ValidateArgMeta<M, InferSchemaOutput<T>>): T;
|
|
1023
|
+
}
|
|
1024
|
+
//#endregion
|
|
1025
|
+
export { toKebabCase as $, LogEntry as A, RunResultSuccess as B, Command as C, GlobalCleanupContext as D, GlobalArgs as E, NonRunnableCommand as F, UnknownSubcommandHandler as G, SetupContext as H, PromptResolver as I, lazy as J, LazyCommand as K, RunCommandOptions as L, LogStream as M, Logger as N, GlobalSetupContext as O, MainOptions as P, toCamelCase as Q, RunResult as R, CollectedLogs as S, Example as T, SubCommandValue as U, RunnableCommand as V, SubCommandsRecord as W, ResolvedFieldMeta as X, ExtractedFields as Y, UnknownKeysMode as Z, DynamicCompletionResult as _, CustomCompletion as a, ArgsSchema as b, PromptType as c, ExpandCompletion as d, InferSchemaOutput as et, ResolvedExpandCandidate as f, DynamicCompletionResolver as g, DynamicCompletionContext as h, CompletionType as i, LogLevel as j, IsEmpty as k, ValidateArgMeta as l, DynamicCompletionCandidate as m, ArgMeta as n, EffectContext as o, CompletionDirectiveMask as p, isLazyCommand as q, CompletionMeta as r, PromptMeta as s, ArgFn as t, SchemaLike as tt, ExpandCandidate as u, AnyCommand as v, CommandBase as w, CleanupContext as x, ArgSource as y, RunResultFailure as z };
|