@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.
Files changed (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +561 -0
  3. package/bin/cli.mjs +3 -0
  4. package/dist/arg-registry-YaWTVu_x.d.ts +1025 -0
  5. package/dist/augment.d.ts +15 -0
  6. package/dist/augment.js +1 -0
  7. package/dist/cli-main-Dn88vIyn.js +84 -0
  8. package/dist/cli-run-eibUcgys.js +7 -0
  9. package/dist/cli.d.ts +1 -0
  10. package/dist/cli.js +16 -0
  11. package/dist/command-k-4yAz4J.js +42 -0
  12. package/dist/compile-cache-Ct41pWGL.js +100 -0
  13. package/dist/compile-cache.d.ts +78 -0
  14. package/dist/compile-cache.js +3 -0
  15. package/dist/completion-gtWX3mwP.js +5608 -0
  16. package/dist/completion.d.ts +242 -0
  17. package/dist/completion.js +4 -0
  18. package/dist/docs.d.ts +770 -0
  19. package/dist/docs.js +3044 -0
  20. package/dist/field-meta-DMy5BcRr.js +146 -0
  21. package/dist/index-CvhsecfS.d.ts +455 -0
  22. package/dist/index.d.ts +799 -0
  23. package/dist/index.js +17 -0
  24. package/dist/log-collector-CoUkLVJB.js +114 -0
  25. package/dist/logger-i_bb-Jhc.js +133 -0
  26. package/dist/prompt-CEIZ-7H1.js +171 -0
  27. package/dist/prompt-clack.d.ts +16 -0
  28. package/dist/prompt-clack.js +32 -0
  29. package/dist/prompt-inquirer.d.ts +16 -0
  30. package/dist/prompt-inquirer.js +47 -0
  31. package/dist/prompt.d.ts +106 -0
  32. package/dist/prompt.js +4 -0
  33. package/dist/register-Bk0K83W2.js +439 -0
  34. package/dist/runner-D72I7wvK.js +2956 -0
  35. package/dist/runner-FvUwOHyE.js +3 -0
  36. package/dist/schema-extractor-DMSozq40.js +250 -0
  37. package/dist/skill.d.ts +608 -0
  38. package/dist/skill.js +1832 -0
  39. package/dist/src-KzC0g5CS.js +191 -0
  40. package/dist/subcommand-router-Cskpofdk.js +134 -0
  41. 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 };