padrone 1.4.0 → 1.5.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 (82) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/README.md +105 -284
  3. package/dist/{args-CVDbyyzG.mjs → args-D5PNDyNu.mjs} +41 -18
  4. package/dist/args-D5PNDyNu.mjs.map +1 -0
  5. package/dist/chunk-CjcI7cDX.mjs +15 -0
  6. package/dist/codegen/index.d.mts +28 -3
  7. package/dist/codegen/index.d.mts.map +1 -1
  8. package/dist/codegen/index.mjs +169 -19
  9. package/dist/codegen/index.mjs.map +1 -1
  10. package/dist/command-utils-B1D-HqCd.mjs +1117 -0
  11. package/dist/command-utils-B1D-HqCd.mjs.map +1 -0
  12. package/dist/completion.d.mts +1 -1
  13. package/dist/completion.d.mts.map +1 -1
  14. package/dist/completion.mjs +77 -29
  15. package/dist/completion.mjs.map +1 -1
  16. package/dist/docs/index.d.mts +22 -2
  17. package/dist/docs/index.d.mts.map +1 -1
  18. package/dist/docs/index.mjs +94 -7
  19. package/dist/docs/index.mjs.map +1 -1
  20. package/dist/errors-BiVrBgi6.mjs +114 -0
  21. package/dist/errors-BiVrBgi6.mjs.map +1 -0
  22. package/dist/{formatter-ClUK5hcQ.d.mts → formatter-DtHzbP22.d.mts} +34 -5
  23. package/dist/formatter-DtHzbP22.d.mts.map +1 -0
  24. package/dist/help-bbmu9-qd.mjs +735 -0
  25. package/dist/help-bbmu9-qd.mjs.map +1 -0
  26. package/dist/index.d.mts +32 -3
  27. package/dist/index.d.mts.map +1 -1
  28. package/dist/index.mjs +493 -265
  29. package/dist/index.mjs.map +1 -1
  30. package/dist/mcp-mLWIdUIu.mjs +379 -0
  31. package/dist/mcp-mLWIdUIu.mjs.map +1 -0
  32. package/dist/serve-B0u43DK7.mjs +404 -0
  33. package/dist/serve-B0u43DK7.mjs.map +1 -0
  34. package/dist/stream-BcC146Ud.mjs +56 -0
  35. package/dist/stream-BcC146Ud.mjs.map +1 -0
  36. package/dist/test.d.mts +1 -1
  37. package/dist/test.mjs +4 -15
  38. package/dist/test.mjs.map +1 -1
  39. package/dist/{types-DjIdJN5G.d.mts → types-Ch8Mk6Qb.d.mts} +310 -62
  40. package/dist/types-Ch8Mk6Qb.d.mts.map +1 -0
  41. package/dist/{update-check-EbNDkzyV.mjs → update-check-CFX1FV3v.mjs} +2 -2
  42. package/dist/{update-check-EbNDkzyV.mjs.map → update-check-CFX1FV3v.mjs.map} +1 -1
  43. package/dist/zod.d.mts +32 -0
  44. package/dist/zod.d.mts.map +1 -0
  45. package/dist/zod.mjs +50 -0
  46. package/dist/zod.mjs.map +1 -0
  47. package/package.json +10 -2
  48. package/src/args.ts +68 -40
  49. package/src/cli/docs.ts +1 -7
  50. package/src/cli/doctor.ts +195 -10
  51. package/src/cli/index.ts +1 -1
  52. package/src/cli/init.ts +2 -3
  53. package/src/cli/link.ts +2 -2
  54. package/src/codegen/discovery.ts +80 -28
  55. package/src/codegen/index.ts +2 -1
  56. package/src/codegen/parsers/bash.ts +179 -0
  57. package/src/codegen/schema-to-code.ts +2 -1
  58. package/src/colorizer.ts +126 -13
  59. package/src/command-utils.ts +380 -30
  60. package/src/completion.ts +120 -47
  61. package/src/create.ts +480 -128
  62. package/src/docs/index.ts +122 -8
  63. package/src/formatter.ts +171 -125
  64. package/src/help.ts +45 -12
  65. package/src/index.ts +29 -1
  66. package/src/interactive.ts +45 -4
  67. package/src/mcp.ts +390 -0
  68. package/src/repl-loop.ts +16 -3
  69. package/src/runtime.ts +195 -2
  70. package/src/serve.ts +442 -0
  71. package/src/stream.ts +75 -0
  72. package/src/test.ts +7 -16
  73. package/src/type-utils.ts +28 -4
  74. package/src/types.ts +212 -30
  75. package/src/wrap.ts +23 -25
  76. package/src/zod.ts +50 -0
  77. package/dist/args-CVDbyyzG.mjs.map +0 -1
  78. package/dist/chunk-y_GBKt04.mjs +0 -5
  79. package/dist/formatter-ClUK5hcQ.d.mts.map +0 -1
  80. package/dist/help-CcBe91bV.mjs +0 -1254
  81. package/dist/help-CcBe91bV.mjs.map +0 -1
  82. package/dist/types-DjIdJN5G.d.mts.map +0 -1
@@ -1,4 +1,4 @@
1
- import { n as HelpFormat, t as HelpDetail } from "./formatter-ClUK5hcQ.mjs";
1
+ import { a as ColorConfig, n as HelpFormat, o as ColorTheme, t as HelpDetail } from "./formatter-DtHzbP22.mjs";
2
2
  import { StandardJSONSchemaV1, StandardSchemaV1 } from "@standard-schema/spec";
3
3
  import { Tool } from "ai";
4
4
 
@@ -9,12 +9,14 @@ type SingleChar = Letter | Uppercase<Letter>;
9
9
  interface PadroneFieldMeta {
10
10
  description?: string;
11
11
  /** Single-character short flags (stackable: `-abc` = `-a -b -c`). Used with single dash. */
12
- flags?: SingleChar[] | SingleChar;
12
+ flags?: readonly SingleChar[] | SingleChar;
13
13
  /** Multi-character alternative long names. Used with double dash (e.g. `--dry-run` for `--dryRun`). */
14
- alias?: string[] | string;
14
+ alias?: readonly string[] | string;
15
15
  deprecated?: boolean | string;
16
16
  hidden?: boolean;
17
- examples?: unknown[];
17
+ examples?: readonly unknown[];
18
+ /** Group name for organizing this option under a labeled section in help output. */
19
+ group?: string;
18
20
  }
19
21
  type PositionalArgs<TObj> = TObj extends Record<string, any> ? { [K in keyof TObj]: NonNullable<TObj[K]> extends Array<any> ? `...${K & string}` | (K & string) : K & string }[keyof TObj] : string;
20
22
  /**
@@ -31,23 +33,18 @@ type PositionalArgs<TObj> = TObj extends Record<string, any> ? { [K in keyof TOb
31
33
  */
32
34
  /**
33
35
  * Configuration for reading from stdin and mapping it to an argument field.
36
+ * Simply specify the field name — the read mode is inferred from the schema:
37
+ * - `string` field → reads all stdin as text
38
+ * - `string[]` field → reads stdin line-by-line
34
39
  */
35
- type StdinConfig<TObj = Record<string, any>> = (keyof TObj & string) | {
36
- /** The argument field to populate with stdin data. */field: keyof TObj & string;
37
- /**
38
- * How to consume stdin:
39
- * - `'text'` (default): read all stdin as a single string.
40
- * - `'lines'`: read stdin as an array of lines (string[]).
41
- */
42
- as?: 'text' | 'lines';
43
- };
40
+ type StdinConfig<TObj = Record<string, any>> = keyof TObj & string;
44
41
  interface PadroneArgsSchemaMeta<TObj = Record<string, any>> {
45
42
  /**
46
43
  * Array of argument names that should be treated as positional arguments.
47
44
  * Order in array determines position. Use '...name' prefix for variadic args.
48
45
  * @example ['source', '...files', 'dest'] - 'files' captures multiple values
49
46
  */
50
- positional?: PositionalArgs<TObj>[];
47
+ positional?: readonly PositionalArgs<TObj>[];
51
48
  /**
52
49
  * Per-argument metadata.
53
50
  */
@@ -72,21 +69,19 @@ interface PadroneArgsSchemaMeta<TObj = Record<string, any>> {
72
69
  * Read from stdin and inject the data into the specified argument field.
73
70
  * Only reads when stdin is piped (not a TTY) and the field wasn't already provided via CLI flags.
74
71
  *
75
- * - `string`: shorthand for `{ field: name, as: 'text' }` read all stdin as a string.
76
- * - `{ field, as }`: explicit form. `as: 'text'` reads all stdin as a string,
77
- * `as: 'lines'` reads stdin as an array of line strings.
72
+ * The read mode is inferred from the schema type of the target field:
73
+ * - `string` field reads all stdin as a single string
74
+ * - `string[]` field → reads stdin line-by-line into an array
78
75
  *
79
76
  * Precedence: CLI flags > stdin > env vars > config file > schema defaults.
80
77
  *
81
78
  * @example
82
79
  * ```ts
83
- * // Shorthand: read all stdin as text into 'data' field
80
+ * // Read all stdin as text into 'data' field
84
81
  * .arguments(z.object({ data: z.string() }), { stdin: 'data' })
85
82
  *
86
- * // Explicit: read stdin lines into 'lines' field
87
- * .arguments(z.object({ lines: z.string().array() }), {
88
- * stdin: { field: 'lines', as: 'lines' },
89
- * })
83
+ * // Read stdin lines into 'lines' field (inferred from array schema)
84
+ * .arguments(z.object({ lines: z.string().array() }), { stdin: 'lines' })
90
85
  * ```
91
86
  */
92
87
  stdin?: StdinConfig<TObj>;
@@ -106,7 +101,7 @@ interface PadroneArgsSchemaMeta<TObj = Record<string, any>> {
106
101
  * })
107
102
  * ```
108
103
  */
109
- interactive?: true | (keyof TObj & string)[];
104
+ interactive?: true | readonly (keyof TObj & string)[];
110
105
  /**
111
106
  * Optional fields offered after required interactive prompts.
112
107
  * Users are shown a multi-select to choose which of these fields to configure.
@@ -121,16 +116,70 @@ interface PadroneArgsSchemaMeta<TObj = Record<string, any>> {
121
116
  * })
122
117
  * ```
123
118
  */
124
- optionalInteractive?: true | (keyof TObj & string)[];
119
+ optionalInteractive?: true | readonly (keyof TObj & string)[];
125
120
  }
126
121
  //#endregion
127
122
  //#region src/help.d.ts
128
123
  type HelpPreferences = {
129
124
  format?: HelpFormat | 'auto';
130
125
  detail?: HelpDetail;
126
+ theme?: ColorTheme | ColorConfig; /** Show all global commands and flags in full detail */
127
+ all?: boolean;
128
+ };
129
+ //#endregion
130
+ //#region src/mcp.d.ts
131
+ type PadroneMcpPreferences = {
132
+ /** Server name. Defaults to the program name. */name?: string; /** Server version. Defaults to the program version. */
133
+ version?: string;
134
+ /**
135
+ * Transport mode.
136
+ * - `'http'` — Start a Streamable HTTP server (default). Responds with `application/json` or `text/event-stream` based on the client's `Accept` header. Use `port` and `host` to configure.
137
+ * - `'stdio'` — Communicate over stdin/stdout with newline-delimited JSON.
138
+ */
139
+ transport?: 'http' | 'stdio'; /** HTTP port. Defaults to `3000`. Only used with `transport: 'http'`. */
140
+ port?: number; /** HTTP host. Defaults to `'127.0.0.1'`. Only used with `transport: 'http'`. */
141
+ host?: string; /** Base path for the MCP endpoint. Defaults to `'/mcp'`. Only used with `transport: 'http'`. */
142
+ basePath?: string; /** CORS allowed origin. Defaults to `'*'`. Set to a specific origin or `false` to disable CORS headers. Only used with HTTP transports. */
143
+ cors?: string | false;
131
144
  };
132
145
  //#endregion
133
146
  //#region src/runtime.d.ts
147
+ /**
148
+ * A progress indicator instance (spinner, progress bar, etc).
149
+ * Created by the runtime's `progress` factory and used to show loading state during command execution.
150
+ */
151
+ type PadroneProgressIndicator = {
152
+ /** Update the displayed message. */update: (message: string) => void; /** Mark as succeeded and stop. Pass `null` to stop without rendering a final message. */
153
+ succeed: (message?: string | null, options?: {
154
+ indicator?: string;
155
+ }) => void; /** Mark as failed and stop. Pass `null` to stop without rendering a final message. */
156
+ fail: (message?: string | null, options?: {
157
+ indicator?: string;
158
+ }) => void; /** Stop without success/fail status. */
159
+ stop: () => void; /** Temporarily hide the indicator so other output can be written cleanly. */
160
+ pause: () => void; /** Redraw the indicator after a `pause()`. */
161
+ resume: () => void;
162
+ };
163
+ /** Built-in spinner presets. */
164
+ type PadroneSpinnerPreset = 'dots' | 'line' | 'arc' | 'bounce';
165
+ /**
166
+ * Spinner configuration for progress indicators.
167
+ * - A preset name (e.g., `'dots'`) to use built-in frames.
168
+ * - An object with custom `frames` and/or `interval`.
169
+ * - `false` to disable the spinner animation (static text only).
170
+ */
171
+ type PadroneSpinnerConfig = PadroneSpinnerPreset | {
172
+ frames?: string[];
173
+ interval?: number;
174
+ } | false;
175
+ /**
176
+ * Options passed to the runtime's `progress` factory.
177
+ */
178
+ type PadroneProgressOptions = {
179
+ spinner?: PadroneSpinnerConfig; /** Character/string shown before the success message. Defaults to `'✔'`. */
180
+ successIndicator?: string; /** Character/string shown before the error message. Defaults to `'✖'`. */
181
+ errorIndicator?: string;
182
+ };
134
183
  /**
135
184
  * Controls interactive prompting capability and default behavior at the runtime level.
136
185
  * - `'supported'` — capable; caller decides.
@@ -165,7 +214,8 @@ type PadroneRuntime = {
165
214
  error?: (text: string) => void; /** Return the raw CLI arguments (replaces process.argv.slice(2)). */
166
215
  argv?: () => string[]; /** Return environment variables (replaces process.env). */
167
216
  env?: () => Record<string, string | undefined>; /** Default help output format. */
168
- format?: HelpFormat | 'auto'; /** Load and parse a config file by path. Return undefined if not found or unparsable. */
217
+ format?: HelpFormat | 'auto'; /** Color theme for ANSI/console help output. A theme name or partial color config. */
218
+ theme?: ColorTheme | ColorConfig; /** Load and parse a config file by path. Return undefined if not found or unparsable. */
169
219
  loadConfigFile?: (path: string) => Record<string, unknown> | undefined; /** Find the first existing file from a list of candidate names. */
170
220
  findFile?: (names: string[]) => string | undefined;
171
221
  /**
@@ -197,6 +247,12 @@ type PadroneRuntime = {
197
247
  * When `interactive` is `true` and this is not provided, defaults to an Enquirer-based terminal prompt.
198
248
  */
199
249
  prompt?: (config: InteractivePromptConfig) => Promise<unknown>;
250
+ /**
251
+ * Create a progress indicator (spinner, progress bar, etc).
252
+ * Used by commands that set `progress` in their config, or manually via `ctx.progress()` in actions.
253
+ * When not provided, auto-progress is silently skipped and `ctx.progress()` returns a no-op indicator.
254
+ */
255
+ progress?: (message: string, options?: PadroneProgressOptions) => PadroneProgressIndicator;
200
256
  /**
201
257
  * Read a line of input from the user. Used by `repl()` for custom runtimes
202
258
  * (web UIs, chat interfaces, testing).
@@ -212,7 +268,7 @@ type PadroneRuntime = {
212
268
  * Internal resolved runtime where all fields are guaranteed to be present.
213
269
  * The `prompt`, `interactive`, and `readLine` fields remain optional since not all runtimes provide them.
214
270
  */
215
- type ResolvedPadroneRuntime = Required<Omit<PadroneRuntime, 'prompt' | 'interactive' | 'readLine' | 'stdin'>> & Pick<PadroneRuntime, 'prompt' | 'interactive' | 'readLine' | 'stdin'>;
271
+ type ResolvedPadroneRuntime = Required<Omit<PadroneRuntime, 'prompt' | 'interactive' | 'readLine' | 'stdin' | 'progress' | 'theme'>> & Pick<PadroneRuntime, 'prompt' | 'interactive' | 'readLine' | 'stdin' | 'progress' | 'theme'>;
216
272
  /**
217
273
  * Creates a persistent Node.js readline session for the REPL.
218
274
  * Enables up/down arrow history navigation and tab completion.
@@ -224,6 +280,22 @@ type ResolvedPadroneRuntime = Required<Omit<PadroneRuntime, 'prompt' | 'interact
224
280
  */
225
281
  declare const REPL_SIGINT: unique symbol;
226
282
  //#endregion
283
+ //#region src/serve.d.ts
284
+ type PadroneServePreferences = {
285
+ /** Port to listen on. Default: 3000 */port?: number; /** Host to bind to. Default: '127.0.0.1' */
286
+ host?: string; /** Base path prefix for all routes. Default: '/' */
287
+ basePath?: string; /** CORS allowed origin. Default: '*'. Set to `false` to disable CORS headers. */
288
+ cors?: string | false; /** Control built-in utility endpoints. All enabled by default. */
289
+ builtins?: {
290
+ /** GET /_health — returns 200 OK. */health?: boolean; /** GET /_help and GET /_help/:command — returns help text. */
291
+ help?: boolean; /** GET /_schema and GET /_schema/:command — returns JSON Schema. */
292
+ schema?: boolean; /** GET /_docs — Scalar OpenAPI docs viewer. */
293
+ docs?: boolean;
294
+ }; /** Hook to run before each request. Return a Response to short-circuit. */
295
+ onRequest?: (req: Request) => Response | void | Promise<Response | void>; /** Transform errors into responses. */
296
+ onError?: (error: unknown, req: Request) => Response;
297
+ };
298
+ //#endregion
227
299
  //#region src/type-utils.d.ts
228
300
  type SafeString = string & {};
229
301
  type IsUnknown<T> = unknown extends T ? true : false;
@@ -250,23 +322,39 @@ type OrAsync<TExisting extends boolean, TSchema> = TExisting extends true ? true
250
322
  * When either is `true` or a `string[]`, the command requires async execution for prompting.
251
323
  */
252
324
  type HasInteractive<TMeta> = TMeta extends {
253
- interactive: true | string[];
325
+ interactive: true | readonly string[];
254
326
  } ? true : TMeta extends {
255
- optionalInteractive: true | string[];
327
+ optionalInteractive: true | readonly string[];
256
328
  } ? true : false;
257
329
  /**
258
330
  * Combines schema-level async detection with meta-level interactive detection.
259
331
  * Returns `true` if the existing async flag is set, the schema is branded async, or the meta has interactive fields.
260
332
  */
261
333
  type OrAsyncMeta<TExisting extends boolean, TMeta> = TExisting extends true ? true : HasInteractive<TMeta> extends true ? true : false;
334
+ /**
335
+ * Unwraps a result type by resolving Promises and collecting iterables into arrays.
336
+ * - `AsyncIterable<U>` → `U[]`
337
+ * - `Iterable<U>` (excluding strings) → `U[]`
338
+ * - `Promise<U>` → `Drained<U>` (recursively unwraps)
339
+ * - `T` → `T`
340
+ */
341
+ type Drained<T> = T extends Promise<infer U> ? Drained<U> : T extends AsyncIterable<infer U> ? U[] : T extends string ? T : T extends Iterable<infer U> ? U[] : T;
342
+ /**
343
+ * A sync value augmented with Promise-like methods (.then, .catch, .finally).
344
+ * Unlike a real Promise, properties of T are accessible synchronously.
345
+ */
346
+ type Thenable<T> = T & PromiseLike<T> & {
347
+ catch: Promise<T>['catch'];
348
+ finally: Promise<T>['finally'];
349
+ };
262
350
  /**
263
351
  * Conditionally wraps a type in Promise based on the TAsync flag.
264
352
  * - `true` → `Promise<T>`
265
- * - `false` → `T & PromiseLike<T>` (thenable: supports `.then()` and `await`)
353
+ * - `false` → `T & Thenable<T>` (thenable: supports `.then()`, `.catch()`, `.finally()`, and `await`)
266
354
  * - `boolean` (union of true|false) → `Promise<T>` (safe default when async-ness is uncertain)
267
355
  * - `any` → `T` (for generic/any typed commands like AnyPadroneCommand)
268
356
  */
269
- type MaybePromise<T, TAsync> = IsAny<TAsync> extends true ? T : true extends TAsync ? Promise<T> : T & PromiseLike<T>;
357
+ type MaybePromise<T, TAsync> = IsAny<TAsync> extends true ? T : true extends TAsync ? Promise<T> : Thenable<T>;
270
358
  type SplitString<TName extends string, TSplitBy extends string = ' '> = TName extends `${infer FirstPart}${TSplitBy}${infer RestParts}` ? [FirstPart, ...SplitString<RestParts, TSplitBy>] : [TName];
271
359
  type JoinString<TParts extends string[], TJoinBy extends string = ' '> = TParts extends [infer FirstPart extends string, ...infer RestParts extends string[]] ? RestParts extends [] ? FirstPart : `${FirstPart}${TJoinBy}${JoinString<RestParts, TJoinBy>}` : TParts extends [] ? '' : TParts[number];
272
360
  type SplitLastSpace<S extends string> = SplitString<S> extends [...infer Init extends string[], infer Last extends string] ? Init extends [] ? [S, never] : [JoinString<Init>, Last] : [S, never];
@@ -424,6 +512,11 @@ type PadroneActionContext = {
424
512
  /** The resolved runtime for this command (I/O, env, config, etc.). */runtime: ResolvedPadroneRuntime; /** The command being executed. */
425
513
  command: AnyPadroneCommand; /** The root program instance. */
426
514
  program: AnyPadroneProgram;
515
+ /**
516
+ * The active auto-managed progress indicator, or a no-op if none is configured.
517
+ * Use `.update()` to change the in-progress message mid-execution.
518
+ */
519
+ progress: PadroneProgressIndicator;
427
520
  };
428
521
  /**
429
522
  * A schema that supports both validation (StandardSchemaV1) and JSON schema generation (StandardJSONSchemaV1).
@@ -478,9 +571,22 @@ type PadroneCommand<TName extends string = string, TParentName extends string =
478
571
  version?: string; /** Alternative names that can be used to invoke this command. Derived from the names passed to command(). */
479
572
  aliases?: TAliases;
480
573
  deprecated?: boolean | string;
481
- hidden?: boolean;
574
+ hidden?: boolean; /** Group name for organizing this command under a labeled section in help output. */
575
+ group?: string; /** Whether this command performs a mutation (create, update, delete). Affects HTTP method in serve (POST-only) and MCP tool annotations (destructiveHint). */
576
+ mutation?: boolean;
482
577
  needsApproval?: boolean | ((args: TArgs) => Promise<boolean> | boolean);
483
- autoOutput?: boolean;
578
+ autoOutput?: boolean; /** Usage examples shown in help output. Each entry is a command-line invocation string. */
579
+ examples?: string[];
580
+ /**
581
+ * Auto-start a progress indicator when the command's execute phase begins.
582
+ * - `true` — generic message based on command name.
583
+ * - `string` — custom message for all states.
584
+ * - `PadroneProgressConfig` — separate messages for progress, success, and error states.
585
+ *
586
+ * The indicator is automatically stopped on success (`.succeed()`) or failure (`.fail()`).
587
+ * Requires a `progress` factory on the runtime — silently skipped if not available.
588
+ */
589
+ progress?: boolean | string | PadroneProgressPrefs;
484
590
  argsSchema?: TArgs;
485
591
  configSchema?: TConfig;
486
592
  envSchema?: TEnv;
@@ -489,7 +595,7 @@ type PadroneCommand<TName extends string = string, TParentName extends string =
489
595
  configFiles?: string[]; /** Runtime flag indicating this command uses async validation. Set by `.async()` or `asyncSchema()`. */
490
596
  isAsync?: boolean; /** Runtime configuration for I/O abstraction. */
491
597
  runtime?: PadroneRuntime; /** Plugins registered on this command. Collected from the parent chain at execution time. */
492
- plugins?: PadronePlugin[]; /** Update check configuration. Only used on the root program. */
598
+ plugins?: PadronePlugin<any, any>[]; /** Update check configuration. Only used on the root program. */
493
599
  updateCheck?: UpdateCheckConfig;
494
600
  parent?: AnyPadroneCommand;
495
601
  commands?: TCommands; /** @deprecated Internal use only */
@@ -521,18 +627,50 @@ type CommandTypesBase = {
521
627
  /**
522
628
  * Configuration for a command.
523
629
  */
630
+ /**
631
+ * A progress message value: a plain string, `null` to suppress, or an object with a message and custom indicator icon.
632
+ */
633
+ type PadroneProgressMessage = string | null | {
634
+ message?: string | null;
635
+ indicator?: string;
636
+ };
637
+ /**
638
+ * Progress indicator configuration with per-state messages and optional dynamic callbacks.
639
+ *
640
+ * The `success` and `error` fields accept either a static value or a callback function:
641
+ * - `string` — static message.
642
+ * - `null` — suppress the message entirely.
643
+ * - `{ message, indicator }` — custom message with a per-call indicator icon override.
644
+ * - `(result) => PadroneProgressMessage` / `(error) => PadroneProgressMessage` — dynamic from the actual result/error.
645
+ */
646
+ type PadroneProgressPrefs<TRes = unknown> = {
647
+ /** Message shown during async validation. Defaults to `''` (spinner only). */validation?: string; /** Message shown while the command's action is running. */
648
+ progress?: string; /** Message shown when the command succeeds. `null` to suppress. Defaults to the `progress` message. */
649
+ success?: PadroneProgressMessage | ((result: TRes) => PadroneProgressMessage); /** Message shown when the command fails. `null` to suppress. Defaults to the error message. */
650
+ error?: PadroneProgressMessage | ((error: unknown) => PadroneProgressMessage); /** Spinner configuration: a preset name, custom frames/interval, or `false` to disable. */
651
+ spinner?: PadroneSpinnerConfig;
652
+ };
524
653
  type PadroneCommandConfig = {
525
654
  /** A short title for the command, displayed in help. */title?: string; /** A longer description of what the command does. */
526
655
  description?: string; /** The version of the command. */
527
656
  version?: string; /** Whether the command is deprecated, or a message explaining the deprecation. */
528
657
  deprecated?: boolean | string; /** Whether the command should be hidden from help output. */
529
- hidden?: boolean;
658
+ hidden?: boolean; /** Group name for organizing this command under a labeled section in help output. */
659
+ group?: string;
530
660
  /**
531
661
  * Automatically write this command's return value to output in CLI/eval/REPL mode.
532
662
  * Overrides the `autoOutput` setting in eval/cli preferences for this command.
533
663
  * See `PadroneEvalPreferences.autoOutput` for serialization details.
534
664
  */
535
- autoOutput?: boolean;
665
+ autoOutput?: boolean; /** Usage examples shown in help output. Each entry is a command-line invocation string. */
666
+ examples?: string[];
667
+ /**
668
+ * Whether this command performs a mutation (create, update, delete).
669
+ * - In `serve()`: mutation commands accept POST only; non-mutation commands accept GET and POST.
670
+ * - In `mcp()`: sets `annotations.destructiveHint` on the tool definition.
671
+ * - In `tool()`: defaults `needsApproval` to `true` when not explicitly set.
672
+ */
673
+ mutation?: boolean;
536
674
  };
537
675
  /**
538
676
  * Conditional type that returns either PadroneBuilder or PadroneProgram based on TReturn.
@@ -575,7 +713,7 @@ type PadroneBuilderMethods<TProgramName extends string, TName extends string, TP
575
713
  * On the program, parse/validate/execute plugins all apply.
576
714
  * On subcommands, only validate and execute plugins apply (parse is handled by the root program).
577
715
  */
578
- use: (plugin: PadronePlugin) => BuilderOrProgram<TReturn, TProgramName, TName, TParentName, TArgs, TRes, TCommands, TParentArgs, TConfig, TEnv, TAsync>;
716
+ use: (plugin: PadronePlugin<StandardSchemaV1.InferOutput<TArgs>, TRes>) => BuilderOrProgram<TReturn, TProgramName, TName, TParentName, TArgs, TRes, TCommands, TParentArgs, TConfig, TEnv, TAsync>;
579
717
  configure: (config: PadroneCommandConfig) => BuilderOrProgram<TReturn, TProgramName, TName, TParentName, TArgs, TRes, TCommands, TParentArgs, TConfig, TEnv, TAsync>;
580
718
  /**
581
719
  * Configures the runtime adapter for I/O abstraction.
@@ -657,6 +795,28 @@ type PadroneBuilderMethods<TProgramName extends string, TName extends string, TP
657
795
  * ```
658
796
  */
659
797
  env: <TNewEnv extends PadroneSchema<unknown, StandardSchemaV1.InferInput<TArgs>> = TArgs>(schema: TNewEnv | ((argsSchema: TArgs) => TNewEnv)) => BuilderOrProgram<TReturn, TProgramName, TName, TParentName, TArgs, TRes, TCommands, TParentArgs, TConfig, TNewEnv, OrAsync<TAsync, TNewEnv>>;
798
+ /**
799
+ * Configures an auto-managed progress indicator for this command.
800
+ * The indicator starts before validation and is automatically stopped on success or failure.
801
+ *
802
+ * - `true` — generic message based on command name.
803
+ * - `string` — custom message for all states.
804
+ * - `PadroneProgressConfig` — full control: per-state messages, dynamic callbacks, spinner config.
805
+ *
806
+ * Requires a `progress` factory on the runtime — silently skipped if not available.
807
+ *
808
+ * @example
809
+ * ```ts
810
+ * .progress('Deploying...')
811
+ * .progress({
812
+ * progress: 'Deploying...',
813
+ * success: (result) => `Deployed ${result.version}`,
814
+ * error: (err) => `Deploy failed: ${err.message}`,
815
+ * spinner: 'line',
816
+ * })
817
+ * ```
818
+ */
819
+ progress: (config?: boolean | string | PadroneProgressPrefs<Awaited<TRes>>) => BuilderOrProgram<TReturn, TProgramName, TName, TParentName, TArgs, TRes, TCommands, TParentArgs, TConfig, TEnv, TAsync>;
660
820
  /**
661
821
  * Defines the handler function to be executed when the command is run.
662
822
  * When overriding an existing command, the previous handler is passed as the third `base` parameter.
@@ -666,6 +826,8 @@ type PadroneBuilderMethods<TProgramName extends string, TName extends string, TP
666
826
  * Wraps an external CLI tool with optional schema transformation.
667
827
  * The config can include a schema that transforms command arguments to external CLI arguments.
668
828
  *
829
+ * @experimental This API is experimental and may change in future releases.
830
+ *
669
831
  * @example
670
832
  * ```ts
671
833
  * // No transformation - pass arguments as-is
@@ -797,13 +959,13 @@ type PadroneProgram<TProgramName extends string = '', TName extends string = str
797
959
  * if (result.argsResult?.issues) { /* handle validation errors *\/ }
798
960
  * ```
799
961
  */
800
- eval: <const TCommand extends PossibleCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>], true, true>>(input: TCommand | SafeString, prefs?: PadroneEvalPreferences) => MaybePromise<PadroneCommandResult<PickCommandByPossibleCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>], TCommand>>, PickCommandByPossibleCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>], TCommand>['~types']['async']>;
962
+ eval: <const TCommand extends PossibleCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>], true, true>>(input: TCommand | SafeString, prefs?: PadroneEvalPreferences) => MaybePromiseCommandResult<PickCommandByPossibleCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>], TCommand>, PickCommandByPossibleCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>], TCommand>['~types']['async']>;
801
963
  /**
802
964
  * Runs the program as a CLI entry point, parsing `process.argv`.
803
965
  * On validation errors, throws and prints help.
804
966
  * For programmatic invocation with a command string, use `eval()` instead.
805
967
  */
806
- cli: (prefs?: PadroneCliPreferences<PossibleCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>]>>) => MaybePromise<PadroneCommandResult<FlattenCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>]>>, TAsync>;
968
+ cli: (prefs?: PadroneCliPreferences<PossibleCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>]>>) => MaybePromiseCommandResult<FlattenCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>]>, TAsync>;
807
969
  /**
808
970
  * Parses CLI input (or the provided input string) into command and arguments without executing anything.
809
971
  */
@@ -838,7 +1000,9 @@ type PadroneProgram<TProgramName extends string = '', TName extends string = str
838
1000
  * - History persistence: save/load history across sessions (currently in-memory only)
839
1001
  * - Middleware/hooks: onBeforeCommand, onAfterCommand, error interceptors (design alongside general middleware system)
840
1002
  */
841
- repl: (options?: PadroneReplPreferences<PossibleCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>]>>) => AsyncIterable<PadroneCommandResult<FlattenCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>]>>>;
1003
+ repl: (options?: PadroneReplPreferences<PossibleCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>]>>) => AsyncIterable<PadroneCommandResult<FlattenCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>]>>> & {
1004
+ drain: () => Promise<PadroneDrainResult<PadroneCommandResult<FlattenCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>]>>[]>>;
1005
+ };
842
1006
  /**
843
1007
  * Returns a tool definition that can be passed to AI SDK.
844
1008
  */
@@ -864,6 +1028,32 @@ type PadroneProgram<TProgramName extends string = '', TName extends string = str
864
1028
  * ```
865
1029
  */
866
1030
  completion: (shell?: 'bash' | 'zsh' | 'fish' | 'powershell') => Promise<string>;
1031
+ /**
1032
+ * Starts a Model Context Protocol (MCP) server that exposes commands as tools for AI assistants.
1033
+ * Communicates over stdio using JSON-RPC with Content-Length framing.
1034
+ * Returns a Promise that resolves when the connection closes.
1035
+ *
1036
+ * @experimental This API is experimental and may change in future releases.
1037
+ *
1038
+ * @example
1039
+ * ```ts
1040
+ * await program.mcp();
1041
+ * ```
1042
+ */
1043
+ mcp: (prefs?: PadroneMcpPreferences) => Promise<void>;
1044
+ /**
1045
+ * Starts a REST HTTP server that exposes commands as endpoints.
1046
+ * Each command becomes a route: `users list` → `GET/POST /users/list`.
1047
+ * Commands with `mutation: true` only accept POST.
1048
+ *
1049
+ * @experimental This API is experimental and may change in future releases.
1050
+ *
1051
+ * @example
1052
+ * ```ts
1053
+ * await program.serve({ port: 3000 });
1054
+ * ```
1055
+ */
1056
+ serve: (prefs?: PadroneServePreferences) => Promise<void>;
867
1057
  };
868
1058
  type AnyPadroneProgram = PadroneProgram<string, string, string, any, any, [...AnyPadroneCommand[]]>;
869
1059
  /**
@@ -949,10 +1139,46 @@ type PadroneEvalPreferences = {
949
1139
  * Options that can be passed to `cli()` to control execution behavior.
950
1140
  */
951
1141
  type PadroneCliPreferences<TScope extends string = string> = PadroneEvalPreferences & {
952
- /** REPL preferences used when `--repl` flag is passed. Set to `false` to disable the `--repl` flag. */repl?: PadroneReplPreferences<TScope> | false;
1142
+ /** REPL preferences used when `--repl` flag is passed. Set to `false` to disable the `--repl` flag. */repl?: PadroneReplPreferences<TScope> | false; /** MCP server preferences used when `mcp` command is used. Set to `false` to disable. */
1143
+ mcp?: PadroneMcpPreferences | false; /** REST server preferences used when `serve` command is used. Set to `false` to disable. */
1144
+ serve?: PadroneServePreferences | false;
1145
+ };
1146
+ /**
1147
+ * Result of `drain()` — a discriminated union that never throws.
1148
+ * On success, `value` holds the fully resolved/collected result; on failure, `error` holds the error.
1149
+ */
1150
+ type PadroneDrainResult<TResult> = {
1151
+ value: Drained<TResult>;
1152
+ error?: never;
1153
+ } | {
1154
+ error: unknown;
1155
+ value?: never;
953
1156
  };
954
- type PadroneCommandResult<TCommand extends AnyPadroneCommand = AnyPadroneCommand> = PadroneParseResult<TCommand> & {
1157
+ /**
1158
+ * Result returned by `eval()`, `cli()`, and `run()`. Never thrown — errors are captured in the `error` field.
1159
+ * Discriminated union: check `error` to distinguish success from failure.
1160
+ *
1161
+ * On success: `command`, `args`, `argsResult`, `result` are populated; `error` is absent.
1162
+ * On failure: `error` is populated; `command` may be present if routing succeeded.
1163
+ */
1164
+ type PadroneCommandResult<TCommand extends AnyPadroneCommand = AnyPadroneCommand> = (PadroneParseResult<TCommand> & {
955
1165
  result: GetResults<TCommand>;
1166
+ error?: never; /** Flattens the result: awaits Promises, collects iterables, catches errors. Never throws. */
1167
+ drain: () => Promise<PadroneDrainResult<GetResults<TCommand>>>;
1168
+ }) | {
1169
+ command?: TCommand;
1170
+ args?: GetArguments<'out', TCommand>;
1171
+ argsResult?: StandardSchemaV1.Result<GetArguments<'out', TCommand>>;
1172
+ error: unknown;
1173
+ result?: never; /** Returns `{ error }` since there is no result to drain. */
1174
+ drain: () => Promise<PadroneDrainResult<GetResults<TCommand>>>;
1175
+ };
1176
+ /**
1177
+ * Like `MaybePromise<PadroneCommandResult<TCommand>, TAsync>` but ensures `drain()` is available
1178
+ * at the outer level in all cases — both sync (Thenable) and async (Promise).
1179
+ */
1180
+ type MaybePromiseCommandResult<TCommand extends AnyPadroneCommand, TAsync> = MaybePromise<PadroneCommandResult<TCommand>, TAsync> & {
1181
+ drain: () => Promise<PadroneDrainResult<GetResults<TCommand>>>;
956
1182
  };
957
1183
  type PadroneParseResult<TCommand extends AnyPadroneCommand = AnyPadroneCommand> = {
958
1184
  command: TCommand;
@@ -986,17 +1212,17 @@ type PluginValidateContext = PluginBaseContext & {
986
1212
  positionalArgs: string[];
987
1213
  };
988
1214
  /** Result returned by the validate phase's `next()`. */
989
- type PluginValidateResult = {
990
- args: unknown;
991
- argsResult: StandardSchemaV1.Result<unknown>;
1215
+ type PluginValidateResult<TArgs = unknown> = {
1216
+ args: TArgs;
1217
+ argsResult: StandardSchemaV1.Result<TArgs>;
992
1218
  };
993
1219
  /** Context for the execute phase. */
994
- type PluginExecuteContext = PluginBaseContext & {
995
- /** Validated arguments that will be passed to the action. Mutable — modify before `next()` to override. */args: unknown;
1220
+ type PluginExecuteContext<TArgs = unknown> = PluginBaseContext & {
1221
+ /** Validated arguments that will be passed to the action. Mutable — modify before `next()` to override. */args: TArgs;
996
1222
  };
997
1223
  /** Result returned by the execute phase's `next()`. */
998
- type PluginExecuteResult = {
999
- result: unknown;
1224
+ type PluginExecuteResult<TResult = unknown> = {
1225
+ result: TResult;
1000
1226
  };
1001
1227
  /** Context for the start phase. Runs before parsing, wraps the entire pipeline. */
1002
1228
  type PluginStartContext = PluginBaseContext & {
@@ -1007,19 +1233,35 @@ type PluginErrorContext = PluginBaseContext & {
1007
1233
  /** The error that was thrown. */error: unknown;
1008
1234
  };
1009
1235
  /** Result returned by the error phase's `next()`. */
1010
- type PluginErrorResult = {
1236
+ type PluginErrorResult<TResult = unknown> = {
1011
1237
  /** The error (possibly transformed). Set to `undefined` to suppress the error. */error?: unknown; /** A replacement result when suppressing the error. */
1012
- result?: unknown;
1238
+ result?: TResult;
1013
1239
  };
1014
1240
  /** Context for the shutdown phase. Always runs after the pipeline (success or failure). */
1015
- type PluginShutdownContext = PluginBaseContext & {
1241
+ type PluginShutdownContext<TResult = unknown> = PluginBaseContext & {
1016
1242
  /** The error, if the pipeline failed (after error phase processing). */error?: unknown; /** The pipeline result, if it succeeded. */
1017
- result?: unknown;
1243
+ result?: TResult;
1018
1244
  };
1019
- type PluginPhaseHandler<TCtx, TResult> = (ctx: TCtx, next: () => TResult | Promise<TResult>) => TResult | Promise<TResult>;
1245
+ /**
1246
+ * A phase handler function for the plugin middleware chain.
1247
+ *
1248
+ * - `TCtx` — the context object available to the handler.
1249
+ * - `TNextResult` — the typed result returned by `next()`, giving the handler type-safe access to downstream output.
1250
+ * - `TReturn` — the type the handler itself returns. Defaults to `TNextResult` but can be wider,
1251
+ * allowing plugins to transform or replace the result (e.g., error-recovery plugins returning a different type).
1252
+ */
1253
+ type PluginPhaseHandler<TCtx, TNextResult, TReturn = TNextResult> = (ctx: TCtx, next: () => TNextResult | Promise<TNextResult>) => TReturn | Promise<TReturn>;
1020
1254
  /**
1021
1255
  * A Padrone plugin that can intercept the parse, validate, and execute phases of command execution.
1022
- * Plugins are registered at the program level with `.use()` and apply to all commands.
1256
+ * Plugins are registered at the program or subcommand level with `.use()`.
1257
+ *
1258
+ * Type parameters:
1259
+ * - `TArgs` — the validated arguments type (output of the args schema). Provides typed `ctx.args` in the execute phase
1260
+ * and typed `args` in the validate result from `next()`.
1261
+ * - `TResult` — the command's return type. Provides typed `result` in execute/error/shutdown phases.
1262
+ *
1263
+ * When registered inline on a builder, these are inferred from the command's types automatically.
1264
+ * For reusable plugins that work with any command, use `PadronePlugin<any, any>`.
1023
1265
  *
1024
1266
  * Each phase handler receives a context and a `next()` function (onion/middleware pattern):
1025
1267
  * - Call `next()` to proceed to the next plugin or the core operation.
@@ -1028,8 +1270,14 @@ type PluginPhaseHandler<TCtx, TResult> = (ctx: TCtx, next: () => TResult | Promi
1028
1270
  * - Modify context fields before `next()` to alter inputs.
1029
1271
  * - Transform the return value of `next()` to alter outputs.
1030
1272
  */
1031
- type PadronePlugin = {
1032
- /** Unique name for this plugin. Used for identification and future disable/override support. */name: string;
1273
+ type PadronePlugin<TArgs = unknown, TResult = unknown> = {
1274
+ /** Display name for this plugin. Used for identification in logs and debugging. */name: string;
1275
+ /**
1276
+ * Optional unique identifier for deduplication. When multiple plugins share the same `id`,
1277
+ * only the last one registered is kept. Useful for allowing downstream code to override
1278
+ * a plugin without accumulating duplicates.
1279
+ */
1280
+ id?: string;
1033
1281
  /**
1034
1282
  * Ordering hint. Lower values run as outer layers (earlier before `next()`, later after).
1035
1283
  * Plugins with the same order preserve registration order. Defaults to `0`.
@@ -1041,19 +1289,19 @@ type PadronePlugin = {
1041
1289
  */
1042
1290
  start?: PluginPhaseHandler<PluginStartContext, unknown>; /** Intercepts command routing and raw argument extraction. */
1043
1291
  parse?: PluginPhaseHandler<PluginParseContext, PluginParseResult>; /** Intercepts argument preprocessing, interactive prompting, and schema validation. */
1044
- validate?: PluginPhaseHandler<PluginValidateContext, PluginValidateResult>; /** Intercepts handler execution. */
1045
- execute?: PluginPhaseHandler<PluginExecuteContext, PluginExecuteResult>;
1292
+ validate?: PluginPhaseHandler<PluginValidateContext, PluginValidateResult<TArgs>, PluginValidateResult>; /** Intercepts handler execution. */
1293
+ execute?: PluginPhaseHandler<PluginExecuteContext<TArgs>, PluginExecuteResult<TResult>, PluginExecuteResult>;
1046
1294
  /**
1047
1295
  * Called when the pipeline throws an error. `next()` passes to the next error handler
1048
1296
  * (innermost returns `{ error }` unchanged). Return `{ result }` without `error` to suppress.
1049
1297
  */
1050
- error?: PluginPhaseHandler<PluginErrorContext, PluginErrorResult>;
1298
+ error?: PluginPhaseHandler<PluginErrorContext, PluginErrorResult<TResult>, PluginErrorResult>;
1051
1299
  /**
1052
1300
  * Always runs after the pipeline completes (success or failure). `next()` calls the next shutdown handler.
1053
1301
  * Use for cleanup: closing connections, flushing logs, etc.
1054
1302
  */
1055
- shutdown?: PluginPhaseHandler<PluginShutdownContext, void>;
1303
+ shutdown?: PluginPhaseHandler<PluginShutdownContext<TResult>, void>;
1056
1304
  };
1057
1305
  //#endregion
1058
- export { PossibleCommands as _, PadroneActionContext as a, PadroneRuntime as b, PadroneCommandResult as c, PadroneProgram as d, PadroneSchema as f, PickCommandByName as g, UpdateCheckConfig as h, AsyncPadroneSchema as i, PadroneParseResult as l, WrapResult as m, AnyPadroneCommand as n, PadroneBuilder as o, WrapConfig as p, AnyPadroneProgram as r, PadroneCommand as s, AnyPadroneBuilder as t, PadronePlugin as u, InteractiveMode as v, REPL_SIGINT as x, InteractivePromptConfig as y };
1059
- //# sourceMappingURL=types-DjIdJN5G.d.mts.map
1306
+ export { Drained as A, REPL_SIGINT as B, PluginShutdownContext as C, WrapConfig as D, PluginValidateResult as E, PadroneProgressIndicator as F, PadroneProgressOptions as I, PadroneRuntime as L, PossibleCommands as M, InteractiveMode as N, WrapResult as O, InteractivePromptConfig as P, PadroneSpinnerConfig as R, PluginParseResult as S, PluginValidateContext as T, PadroneMcpPreferences as V, PluginErrorContext as _, PadroneActionContext as a, PluginExecuteResult as b, PadroneCommandResult as c, PadronePlugin as d, PadroneProgram as f, PluginBaseContext as g, PadroneSchema as h, AsyncPadroneSchema as i, PickCommandByName as j, UpdateCheckConfig as k, PadroneDrainResult as l, PadroneProgressPrefs as m, AnyPadroneCommand as n, PadroneBuilder as o, PadroneProgressMessage as p, AnyPadroneProgram as r, PadroneCommand as s, AnyPadroneBuilder as t, PadroneParseResult as u, PluginErrorResult as v, PluginStartContext as w, PluginParseContext as x, PluginExecuteContext as y, PadroneSpinnerPreset as z };
1307
+ //# sourceMappingURL=types-Ch8Mk6Qb.d.mts.map