padrone 1.3.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 +94 -0
  2. package/README.md +105 -284
  3. package/dist/{args-DFEI7_G_.mjs → args-D5PNDyNu.mjs} +46 -21
  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-XroimS3Q.d.mts → formatter-DtHzbP22.d.mts} +35 -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 +495 -267
  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-BS7RP5Ls.d.mts → types-Ch8Mk6Qb.d.mts} +311 -63
  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 +76 -44
  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 +401 -23
  60. package/src/completion.ts +120 -47
  61. package/src/create.ts +483 -130
  62. package/src/docs/index.ts +122 -8
  63. package/src/formatter.ts +173 -125
  64. package/src/help.ts +46 -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-DFEI7_G_.mjs.map +0 -1
  78. package/dist/chunk-y_GBKt04.mjs +0 -5
  79. package/dist/formatter-XroimS3Q.d.mts.map +0 -1
  80. package/dist/help-CgGP7hQU.mjs +0 -1229
  81. package/dist/help-CgGP7hQU.mjs.map +0 -1
  82. package/dist/types-BS7RP5Ls.d.mts.map +0 -1
package/src/types.ts CHANGED
@@ -2,8 +2,11 @@ import type { StandardJSONSchemaV1, StandardSchemaV1 } from '@standard-schema/sp
2
2
  import type { Tool } from 'ai';
3
3
  import type { PadroneArgsSchemaMeta } from './args.ts';
4
4
  import type { HelpPreferences } from './help.ts';
5
- import type { PadroneRuntime, ResolvedPadroneRuntime } from './runtime.ts';
5
+ import type { PadroneMcpPreferences } from './mcp.ts';
6
+ import type { PadroneProgressIndicator, PadroneRuntime, PadroneSpinnerConfig, ResolvedPadroneRuntime } from './runtime.ts';
7
+ import type { PadroneServePreferences } from './serve.ts';
6
8
  import type {
9
+ Drained,
7
10
  FindDirectChild,
8
11
  FlattenCommands,
9
12
  FullCommandName,
@@ -36,6 +39,11 @@ export type PadroneActionContext = {
36
39
  command: AnyPadroneCommand;
37
40
  /** The root program instance. */
38
41
  program: AnyPadroneProgram;
42
+ /**
43
+ * The active auto-managed progress indicator, or a no-op if none is configured.
44
+ * Use `.update()` to change the in-progress message mid-execution.
45
+ */
46
+ progress: PadroneProgressIndicator;
39
47
  };
40
48
 
41
49
  /**
@@ -178,8 +186,24 @@ export type PadroneCommand<
178
186
  aliases?: TAliases;
179
187
  deprecated?: boolean | string;
180
188
  hidden?: boolean;
189
+ /** Group name for organizing this command under a labeled section in help output. */
190
+ group?: string;
191
+ /** Whether this command performs a mutation (create, update, delete). Affects HTTP method in serve (POST-only) and MCP tool annotations (destructiveHint). */
192
+ mutation?: boolean;
181
193
  needsApproval?: boolean | ((args: TArgs) => Promise<boolean> | boolean);
182
194
  autoOutput?: boolean;
195
+ /** Usage examples shown in help output. Each entry is a command-line invocation string. */
196
+ examples?: string[];
197
+ /**
198
+ * Auto-start a progress indicator when the command's execute phase begins.
199
+ * - `true` — generic message based on command name.
200
+ * - `string` — custom message for all states.
201
+ * - `PadroneProgressConfig` — separate messages for progress, success, and error states.
202
+ *
203
+ * The indicator is automatically stopped on success (`.succeed()`) or failure (`.fail()`).
204
+ * Requires a `progress` factory on the runtime — silently skipped if not available.
205
+ */
206
+ progress?: boolean | string | PadroneProgressPrefs;
183
207
  argsSchema?: TArgs;
184
208
  configSchema?: TConfig;
185
209
  envSchema?: TEnv;
@@ -193,7 +217,7 @@ export type PadroneCommand<
193
217
  runtime?: PadroneRuntime;
194
218
 
195
219
  /** Plugins registered on this command. Collected from the parent chain at execution time. */
196
- plugins?: PadronePlugin[];
220
+ plugins?: PadronePlugin<any, any>[];
197
221
 
198
222
  /** Update check configuration. Only used on the root program. */
199
223
  updateCheck?: UpdateCheckConfig;
@@ -233,6 +257,33 @@ type CommandTypesBase = {
233
257
  /**
234
258
  * Configuration for a command.
235
259
  */
260
+ /**
261
+ * A progress message value: a plain string, `null` to suppress, or an object with a message and custom indicator icon.
262
+ */
263
+ export type PadroneProgressMessage = string | null | { message?: string | null; indicator?: string };
264
+
265
+ /**
266
+ * Progress indicator configuration with per-state messages and optional dynamic callbacks.
267
+ *
268
+ * The `success` and `error` fields accept either a static value or a callback function:
269
+ * - `string` — static message.
270
+ * - `null` — suppress the message entirely.
271
+ * - `{ message, indicator }` — custom message with a per-call indicator icon override.
272
+ * - `(result) => PadroneProgressMessage` / `(error) => PadroneProgressMessage` — dynamic from the actual result/error.
273
+ */
274
+ export type PadroneProgressPrefs<TRes = unknown> = {
275
+ /** Message shown during async validation. Defaults to `''` (spinner only). */
276
+ validation?: string;
277
+ /** Message shown while the command's action is running. */
278
+ progress?: string;
279
+ /** Message shown when the command succeeds. `null` to suppress. Defaults to the `progress` message. */
280
+ success?: PadroneProgressMessage | ((result: TRes) => PadroneProgressMessage);
281
+ /** Message shown when the command fails. `null` to suppress. Defaults to the error message. */
282
+ error?: PadroneProgressMessage | ((error: unknown) => PadroneProgressMessage);
283
+ /** Spinner configuration: a preset name, custom frames/interval, or `false` to disable. */
284
+ spinner?: PadroneSpinnerConfig;
285
+ };
286
+
236
287
  export type PadroneCommandConfig = {
237
288
  /** A short title for the command, displayed in help. */
238
289
  title?: string;
@@ -244,12 +295,23 @@ export type PadroneCommandConfig = {
244
295
  deprecated?: boolean | string;
245
296
  /** Whether the command should be hidden from help output. */
246
297
  hidden?: boolean;
298
+ /** Group name for organizing this command under a labeled section in help output. */
299
+ group?: string;
247
300
  /**
248
301
  * Automatically write this command's return value to output in CLI/eval/REPL mode.
249
302
  * Overrides the `autoOutput` setting in eval/cli preferences for this command.
250
303
  * See `PadroneEvalPreferences.autoOutput` for serialization details.
251
304
  */
252
305
  autoOutput?: boolean;
306
+ /** Usage examples shown in help output. Each entry is a command-line invocation string. */
307
+ examples?: string[];
308
+ /**
309
+ * Whether this command performs a mutation (create, update, delete).
310
+ * - In `serve()`: mutation commands accept POST only; non-mutation commands accept GET and POST.
311
+ * - In `mcp()`: sets `annotations.destructiveHint` on the tool definition.
312
+ * - In `tool()`: defaults `needsApproval` to `true` when not explicitly set.
313
+ */
314
+ mutation?: boolean;
253
315
  };
254
316
 
255
317
  /**
@@ -325,7 +387,7 @@ export type PadroneBuilderMethods<
325
387
  * On subcommands, only validate and execute plugins apply (parse is handled by the root program).
326
388
  */
327
389
  use: (
328
- plugin: PadronePlugin,
390
+ plugin: PadronePlugin<StandardSchemaV1.InferOutput<TArgs>, TRes>,
329
391
  ) => BuilderOrProgram<TReturn, TProgramName, TName, TParentName, TArgs, TRes, TCommands, TParentArgs, TConfig, TEnv, TAsync>;
330
392
 
331
393
  configure: (
@@ -463,6 +525,31 @@ export type PadroneBuilderMethods<
463
525
  OrAsync<TAsync, TNewEnv>
464
526
  >;
465
527
 
528
+ /**
529
+ * Configures an auto-managed progress indicator for this command.
530
+ * The indicator starts before validation and is automatically stopped on success or failure.
531
+ *
532
+ * - `true` — generic message based on command name.
533
+ * - `string` — custom message for all states.
534
+ * - `PadroneProgressConfig` — full control: per-state messages, dynamic callbacks, spinner config.
535
+ *
536
+ * Requires a `progress` factory on the runtime — silently skipped if not available.
537
+ *
538
+ * @example
539
+ * ```ts
540
+ * .progress('Deploying...')
541
+ * .progress({
542
+ * progress: 'Deploying...',
543
+ * success: (result) => `Deployed ${result.version}`,
544
+ * error: (err) => `Deploy failed: ${err.message}`,
545
+ * spinner: 'line',
546
+ * })
547
+ * ```
548
+ */
549
+ progress: (
550
+ config?: boolean | string | PadroneProgressPrefs<Awaited<TRes>>,
551
+ ) => BuilderOrProgram<TReturn, TProgramName, TName, TParentName, TArgs, TRes, TCommands, TParentArgs, TConfig, TEnv, TAsync>;
552
+
466
553
  /**
467
554
  * Defines the handler function to be executed when the command is run.
468
555
  * When overriding an existing command, the previous handler is passed as the third `base` parameter.
@@ -479,6 +566,8 @@ export type PadroneBuilderMethods<
479
566
  * Wraps an external CLI tool with optional schema transformation.
480
567
  * The config can include a schema that transforms command arguments to external CLI arguments.
481
568
  *
569
+ * @experimental This API is experimental and may change in future releases.
570
+ *
482
571
  * @example
483
572
  * ```ts
484
573
  * // No transformation - pass arguments as-is
@@ -769,8 +858,8 @@ export type PadroneProgram<
769
858
  eval: <const TCommand extends PossibleCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>], true, true>>(
770
859
  input: TCommand | SafeString,
771
860
  prefs?: PadroneEvalPreferences,
772
- ) => MaybePromise<
773
- PadroneCommandResult<PickCommandByPossibleCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>], TCommand>>,
861
+ ) => MaybePromiseCommandResult<
862
+ PickCommandByPossibleCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>], TCommand>,
774
863
  PickCommandByPossibleCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>], TCommand>['~types']['async']
775
864
  >;
776
865
 
@@ -781,7 +870,7 @@ export type PadroneProgram<
781
870
  */
782
871
  cli: (
783
872
  prefs?: PadroneCliPreferences<PossibleCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>]>>,
784
- ) => MaybePromise<PadroneCommandResult<FlattenCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>]>>, TAsync>;
873
+ ) => MaybePromiseCommandResult<FlattenCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>]>, TAsync>;
785
874
 
786
875
  /**
787
876
  * Parses CLI input (or the provided input string) into command and arguments without executing anything.
@@ -831,9 +920,11 @@ export type PadroneProgram<
831
920
  * - History persistence: save/load history across sessions (currently in-memory only)
832
921
  * - Middleware/hooks: onBeforeCommand, onAfterCommand, error interceptors (design alongside general middleware system)
833
922
  */
834
- repl: (
835
- options?: PadroneReplPreferences<PossibleCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>]>>,
836
- ) => AsyncIterable<PadroneCommandResult<FlattenCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>]>>>;
923
+ repl: (options?: PadroneReplPreferences<PossibleCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>]>>) => AsyncIterable<
924
+ PadroneCommandResult<FlattenCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>]>>
925
+ > & {
926
+ drain: () => Promise<PadroneDrainResult<PadroneCommandResult<FlattenCommands<[PadroneCommand<'', '', TArgs, TRes, TCommands>]>>[]>>;
927
+ };
837
928
 
838
929
  /**
839
930
  * Returns a tool definition that can be passed to AI SDK.
@@ -863,6 +954,34 @@ export type PadroneProgram<
863
954
  * ```
864
955
  */
865
956
  completion: (shell?: 'bash' | 'zsh' | 'fish' | 'powershell') => Promise<string>;
957
+
958
+ /**
959
+ * Starts a Model Context Protocol (MCP) server that exposes commands as tools for AI assistants.
960
+ * Communicates over stdio using JSON-RPC with Content-Length framing.
961
+ * Returns a Promise that resolves when the connection closes.
962
+ *
963
+ * @experimental This API is experimental and may change in future releases.
964
+ *
965
+ * @example
966
+ * ```ts
967
+ * await program.mcp();
968
+ * ```
969
+ */
970
+ mcp: (prefs?: PadroneMcpPreferences) => Promise<void>;
971
+
972
+ /**
973
+ * Starts a REST HTTP server that exposes commands as endpoints.
974
+ * Each command becomes a route: `users list` → `GET/POST /users/list`.
975
+ * Commands with `mutation: true` only accept POST.
976
+ *
977
+ * @experimental This API is experimental and may change in future releases.
978
+ *
979
+ * @example
980
+ * ```ts
981
+ * await program.serve({ port: 3000 });
982
+ * ```
983
+ */
984
+ serve: (prefs?: PadroneServePreferences) => Promise<void>;
866
985
  };
867
986
 
868
987
  export type AnyPadroneProgram = PadroneProgram<string, string, string, any, any, [...AnyPadroneCommand[]]>;
@@ -959,10 +1078,48 @@ export type PadroneEvalPreferences = {
959
1078
  export type PadroneCliPreferences<TScope extends string = string> = PadroneEvalPreferences & {
960
1079
  /** REPL preferences used when `--repl` flag is passed. Set to `false` to disable the `--repl` flag. */
961
1080
  repl?: PadroneReplPreferences<TScope> | false;
1081
+ /** MCP server preferences used when `mcp` command is used. Set to `false` to disable. */
1082
+ mcp?: PadroneMcpPreferences | false;
1083
+ /** REST server preferences used when `serve` command is used. Set to `false` to disable. */
1084
+ serve?: PadroneServePreferences | false;
962
1085
  };
963
1086
 
964
- export type PadroneCommandResult<TCommand extends AnyPadroneCommand = AnyPadroneCommand> = PadroneParseResult<TCommand> & {
965
- result: GetResults<TCommand>;
1087
+ /**
1088
+ * Result of `drain()` — a discriminated union that never throws.
1089
+ * On success, `value` holds the fully resolved/collected result; on failure, `error` holds the error.
1090
+ */
1091
+ export type PadroneDrainResult<TResult> = { value: Drained<TResult>; error?: never } | { error: unknown; value?: never };
1092
+
1093
+ /**
1094
+ * Result returned by `eval()`, `cli()`, and `run()`. Never thrown — errors are captured in the `error` field.
1095
+ * Discriminated union: check `error` to distinguish success from failure.
1096
+ *
1097
+ * On success: `command`, `args`, `argsResult`, `result` are populated; `error` is absent.
1098
+ * On failure: `error` is populated; `command` may be present if routing succeeded.
1099
+ */
1100
+ export type PadroneCommandResult<TCommand extends AnyPadroneCommand = AnyPadroneCommand> =
1101
+ | (PadroneParseResult<TCommand> & {
1102
+ result: GetResults<TCommand>;
1103
+ error?: never;
1104
+ /** Flattens the result: awaits Promises, collects iterables, catches errors. Never throws. */
1105
+ drain: () => Promise<PadroneDrainResult<GetResults<TCommand>>>;
1106
+ })
1107
+ | {
1108
+ command?: TCommand;
1109
+ args?: GetArguments<'out', TCommand>;
1110
+ argsResult?: StandardSchemaV1.Result<GetArguments<'out', TCommand>>;
1111
+ error: unknown;
1112
+ result?: never;
1113
+ /** Returns `{ error }` since there is no result to drain. */
1114
+ drain: () => Promise<PadroneDrainResult<GetResults<TCommand>>>;
1115
+ };
1116
+
1117
+ /**
1118
+ * Like `MaybePromise<PadroneCommandResult<TCommand>, TAsync>` but ensures `drain()` is available
1119
+ * at the outer level in all cases — both sync (Thenable) and async (Promise).
1120
+ */
1121
+ type MaybePromiseCommandResult<TCommand extends AnyPadroneCommand, TAsync> = MaybePromise<PadroneCommandResult<TCommand>, TAsync> & {
1122
+ drain: () => Promise<PadroneDrainResult<GetResults<TCommand>>>;
966
1123
  };
967
1124
 
968
1125
  export type PadroneParseResult<TCommand extends AnyPadroneCommand = AnyPadroneCommand> = {
@@ -1020,20 +1177,20 @@ export type PluginValidateContext = PluginBaseContext & {
1020
1177
  };
1021
1178
 
1022
1179
  /** Result returned by the validate phase's `next()`. */
1023
- export type PluginValidateResult = {
1024
- args: unknown;
1025
- argsResult: StandardSchemaV1.Result<unknown>;
1180
+ export type PluginValidateResult<TArgs = unknown> = {
1181
+ args: TArgs;
1182
+ argsResult: StandardSchemaV1.Result<TArgs>;
1026
1183
  };
1027
1184
 
1028
1185
  /** Context for the execute phase. */
1029
- export type PluginExecuteContext = PluginBaseContext & {
1186
+ export type PluginExecuteContext<TArgs = unknown> = PluginBaseContext & {
1030
1187
  /** Validated arguments that will be passed to the action. Mutable — modify before `next()` to override. */
1031
- args: unknown;
1188
+ args: TArgs;
1032
1189
  };
1033
1190
 
1034
1191
  /** Result returned by the execute phase's `next()`. */
1035
- export type PluginExecuteResult = {
1036
- result: unknown;
1192
+ export type PluginExecuteResult<TResult = unknown> = {
1193
+ result: TResult;
1037
1194
  };
1038
1195
 
1039
1196
  /** Context for the start phase. Runs before parsing, wraps the entire pipeline. */
@@ -1049,26 +1206,45 @@ export type PluginErrorContext = PluginBaseContext & {
1049
1206
  };
1050
1207
 
1051
1208
  /** Result returned by the error phase's `next()`. */
1052
- export type PluginErrorResult = {
1209
+ export type PluginErrorResult<TResult = unknown> = {
1053
1210
  /** The error (possibly transformed). Set to `undefined` to suppress the error. */
1054
1211
  error?: unknown;
1055
1212
  /** A replacement result when suppressing the error. */
1056
- result?: unknown;
1213
+ result?: TResult;
1057
1214
  };
1058
1215
 
1059
1216
  /** Context for the shutdown phase. Always runs after the pipeline (success or failure). */
1060
- export type PluginShutdownContext = PluginBaseContext & {
1217
+ export type PluginShutdownContext<TResult = unknown> = PluginBaseContext & {
1061
1218
  /** The error, if the pipeline failed (after error phase processing). */
1062
1219
  error?: unknown;
1063
1220
  /** The pipeline result, if it succeeded. */
1064
- result?: unknown;
1221
+ result?: TResult;
1065
1222
  };
1066
1223
 
1067
- type PluginPhaseHandler<TCtx, TResult> = (ctx: TCtx, next: () => TResult | Promise<TResult>) => TResult | Promise<TResult>;
1224
+ /**
1225
+ * A phase handler function for the plugin middleware chain.
1226
+ *
1227
+ * - `TCtx` — the context object available to the handler.
1228
+ * - `TNextResult` — the typed result returned by `next()`, giving the handler type-safe access to downstream output.
1229
+ * - `TReturn` — the type the handler itself returns. Defaults to `TNextResult` but can be wider,
1230
+ * allowing plugins to transform or replace the result (e.g., error-recovery plugins returning a different type).
1231
+ */
1232
+ type PluginPhaseHandler<TCtx, TNextResult, TReturn = TNextResult> = (
1233
+ ctx: TCtx,
1234
+ next: () => TNextResult | Promise<TNextResult>,
1235
+ ) => TReturn | Promise<TReturn>;
1068
1236
 
1069
1237
  /**
1070
1238
  * A Padrone plugin that can intercept the parse, validate, and execute phases of command execution.
1071
- * Plugins are registered at the program level with `.use()` and apply to all commands.
1239
+ * Plugins are registered at the program or subcommand level with `.use()`.
1240
+ *
1241
+ * Type parameters:
1242
+ * - `TArgs` — the validated arguments type (output of the args schema). Provides typed `ctx.args` in the execute phase
1243
+ * and typed `args` in the validate result from `next()`.
1244
+ * - `TResult` — the command's return type. Provides typed `result` in execute/error/shutdown phases.
1245
+ *
1246
+ * When registered inline on a builder, these are inferred from the command's types automatically.
1247
+ * For reusable plugins that work with any command, use `PadronePlugin<any, any>`.
1072
1248
  *
1073
1249
  * Each phase handler receives a context and a `next()` function (onion/middleware pattern):
1074
1250
  * - Call `next()` to proceed to the next plugin or the core operation.
@@ -1077,9 +1253,15 @@ type PluginPhaseHandler<TCtx, TResult> = (ctx: TCtx, next: () => TResult | Promi
1077
1253
  * - Modify context fields before `next()` to alter inputs.
1078
1254
  * - Transform the return value of `next()` to alter outputs.
1079
1255
  */
1080
- export type PadronePlugin = {
1081
- /** Unique name for this plugin. Used for identification and future disable/override support. */
1256
+ export type PadronePlugin<TArgs = unknown, TResult = unknown> = {
1257
+ /** Display name for this plugin. Used for identification in logs and debugging. */
1082
1258
  name: string;
1259
+ /**
1260
+ * Optional unique identifier for deduplication. When multiple plugins share the same `id`,
1261
+ * only the last one registered is kept. Useful for allowing downstream code to override
1262
+ * a plugin without accumulating duplicates.
1263
+ */
1264
+ id?: string;
1083
1265
  /**
1084
1266
  * Ordering hint. Lower values run as outer layers (earlier before `next()`, later after).
1085
1267
  * Plugins with the same order preserve registration order. Defaults to `0`.
@@ -1093,17 +1275,17 @@ export type PadronePlugin = {
1093
1275
  /** Intercepts command routing and raw argument extraction. */
1094
1276
  parse?: PluginPhaseHandler<PluginParseContext, PluginParseResult>;
1095
1277
  /** Intercepts argument preprocessing, interactive prompting, and schema validation. */
1096
- validate?: PluginPhaseHandler<PluginValidateContext, PluginValidateResult>;
1278
+ validate?: PluginPhaseHandler<PluginValidateContext, PluginValidateResult<TArgs>, PluginValidateResult>;
1097
1279
  /** Intercepts handler execution. */
1098
- execute?: PluginPhaseHandler<PluginExecuteContext, PluginExecuteResult>;
1280
+ execute?: PluginPhaseHandler<PluginExecuteContext<TArgs>, PluginExecuteResult<TResult>, PluginExecuteResult>;
1099
1281
  /**
1100
1282
  * Called when the pipeline throws an error. `next()` passes to the next error handler
1101
1283
  * (innermost returns `{ error }` unchanged). Return `{ result }` without `error` to suppress.
1102
1284
  */
1103
- error?: PluginPhaseHandler<PluginErrorContext, PluginErrorResult>;
1285
+ error?: PluginPhaseHandler<PluginErrorContext, PluginErrorResult<TResult>, PluginErrorResult>;
1104
1286
  /**
1105
1287
  * Always runs after the pipeline completes (success or failure). `next()` calls the next shutdown handler.
1106
1288
  * Use for cleanup: closing connections, flushing logs, etc.
1107
1289
  */
1108
- shutdown?: PluginPhaseHandler<PluginShutdownContext, void>;
1290
+ shutdown?: PluginPhaseHandler<PluginShutdownContext<TResult>, void>;
1109
1291
  };
package/src/wrap.ts CHANGED
@@ -58,7 +58,7 @@ export type WrapResult = {
58
58
  /**
59
59
  * Converts parsed arguments to CLI arguments for an external command.
60
60
  */
61
- function argsToCliArgs(input: Record<string, unknown> | undefined, positional: string[] = []): string[] {
61
+ function argsToCliArgs(input: Record<string, unknown> | undefined, positional: readonly string[] = []): string[] {
62
62
  const args: string[] = [];
63
63
 
64
64
  // Handle undefined or null input
@@ -122,7 +122,7 @@ function argsToCliArgs(input: Record<string, unknown> | undefined, positional: s
122
122
  export function createWrapHandler<TCommandArgs extends PadroneSchema, TWrapArgs extends PadroneSchema>(
123
123
  config: WrapConfig<TCommandArgs, TWrapArgs>,
124
124
  commandArguments: TCommandArgs,
125
- commandPositional?: string[],
125
+ commandPositional?: readonly string[],
126
126
  ): (args: StandardSchemaV1.InferOutput<TCommandArgs>) => Promise<WrapResult> {
127
127
  return async (args: StandardSchemaV1.InferOutput<TCommandArgs>): Promise<WrapResult> => {
128
128
  const { command, args: fixedArgs = [], inheritStdio = true, positional = commandPositional, schema: wrapSchema } = config;
@@ -153,33 +153,31 @@ export function createWrapHandler<TCommandArgs extends PadroneSchema, TWrapArgs
153
153
  const allArgs = [...fixedArgs, ...regularArgs];
154
154
 
155
155
  // Execute the external command
156
- const proc = Bun.spawn([command, ...allArgs], {
157
- stdout: inheritStdio ? 'inherit' : 'pipe',
158
- stderr: inheritStdio ? 'inherit' : 'pipe',
159
- stdin: inheritStdio ? 'inherit' : 'ignore',
160
- });
156
+ const { spawn } = await import('node:child_process');
161
157
 
162
- const exitCode = await proc.exited;
158
+ return new Promise<WrapResult>((resolve, reject) => {
159
+ const proc = spawn(command, allArgs, {
160
+ stdio: inheritStdio ? 'inherit' : ['ignore', 'pipe', 'pipe'],
161
+ });
163
162
 
164
- let stdout: string | undefined;
165
- let stderr: string | undefined;
163
+ const stdoutChunks: Buffer[] = [];
164
+ const stderrChunks: Buffer[] = [];
166
165
 
167
- if (!inheritStdio) {
168
- if (proc.stdout) {
169
- const stdoutBuffer = await new Response(proc.stdout).arrayBuffer();
170
- stdout = new TextDecoder().decode(stdoutBuffer);
171
- }
172
- if (proc.stderr) {
173
- const stderrBuffer = await new Response(proc.stderr).arrayBuffer();
174
- stderr = new TextDecoder().decode(stderrBuffer);
166
+ if (!inheritStdio) {
167
+ proc.stdout!.on('data', (chunk: Buffer) => stdoutChunks.push(chunk));
168
+ proc.stderr!.on('data', (chunk: Buffer) => stderrChunks.push(chunk));
175
169
  }
176
- }
177
170
 
178
- return {
179
- exitCode,
180
- stdout,
181
- stderr,
182
- success: exitCode === 0,
183
- };
171
+ proc.on('error', reject);
172
+ proc.on('close', (code) => {
173
+ const exitCode = code ?? 1;
174
+ resolve({
175
+ exitCode,
176
+ stdout: inheritStdio ? undefined : Buffer.concat(stdoutChunks).toString(),
177
+ stderr: inheritStdio ? undefined : Buffer.concat(stderrChunks).toString(),
178
+ success: exitCode === 0,
179
+ });
180
+ });
181
+ });
184
182
  };
185
183
  }
package/src/zod.ts ADDED
@@ -0,0 +1,50 @@
1
+ import * as z from 'zod/v4';
2
+ import { asyncStream } from './stream.ts';
3
+ import type { PadroneSchema } from './types.ts';
4
+
5
+ /**
6
+ * Creates a Zod schema for an async stream field, ready to use in `.arguments()`.
7
+ * Wraps `z.custom<AsyncIterable<T>>()` with the `asyncStream()` metadata automatically.
8
+ *
9
+ * @param itemSchema - Optional item schema for per-item validation.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { zodAsyncStream } from 'padrone/zod';
14
+ *
15
+ * // String lines
16
+ * z.object({ lines: zodAsyncStream() })
17
+ *
18
+ * // Typed items — each line JSON.parse'd and validated
19
+ * const recordSchema = z.object({ name: z.string(), age: z.number() });
20
+ * z.object({ records: zodAsyncStream(jsonCodec(recordSchema)) })
21
+ * ```
22
+ */
23
+ export function zodAsyncStream<T = string>(itemSchema?: PadroneSchema<unknown, T>) {
24
+ return z.custom<AsyncIterable<T>>().meta(asyncStream(itemSchema));
25
+ }
26
+
27
+ /**
28
+ * JSON codec for Zod schemas
29
+ * @see https://zod.dev/codecs?id=jsonschema
30
+ * Unlike the example in the docs, this codec also handles the case where the input is already an object
31
+ */
32
+ export const jsonCodec = <T extends z.ZodType>(schema: T) =>
33
+ z.codec(z.union([z.string(), z.unknown()]), schema, {
34
+ decode: (jsonString, ctx) => {
35
+ try {
36
+ // HACK: in some cases the object is already deserialized, we just need to validate it
37
+ if (typeof jsonString !== 'string') return jsonString as z.input<T>;
38
+ return JSON.parse(jsonString) as z.input<T>;
39
+ } catch (err: any) {
40
+ ctx.issues.push({
41
+ code: 'invalid_format',
42
+ format: 'json',
43
+ input: typeof jsonString === 'string' ? jsonString : JSON.stringify(jsonString),
44
+ message: err.message,
45
+ });
46
+ return z.NEVER;
47
+ }
48
+ },
49
+ encode: (value) => JSON.stringify(value),
50
+ });
@@ -1 +0,0 @@
1
- {"version":3,"file":"args-DFEI7_G_.mjs","names":[],"sources":["../src/args.ts"],"sourcesContent":["import type { StandardJSONSchemaV1 } from '@standard-schema/spec';\n\ntype Letter =\n | 'a'\n | 'b'\n | 'c'\n | 'd'\n | 'e'\n | 'f'\n | 'g'\n | 'h'\n | 'i'\n | 'j'\n | 'k'\n | 'l'\n | 'm'\n | 'n'\n | 'o'\n | 'p'\n | 'q'\n | 'r'\n | 's'\n | 't'\n | 'u'\n | 'v'\n | 'w'\n | 'x'\n | 'y'\n | 'z';\n\n/** A single letter character, valid as a short CLI flag (e.g. `'v'`, `'n'`, `'V'`). */\nexport type SingleChar = Letter | Uppercase<Letter>;\n\nexport interface PadroneFieldMeta {\n description?: string;\n /** Single-character short flags (stackable: `-abc` = `-a -b -c`). Used with single dash. */\n flags?: SingleChar[] | SingleChar;\n /** Multi-character alternative long names. Used with double dash (e.g. `--dry-run` for `--dryRun`). */\n alias?: string[] | string;\n deprecated?: boolean | string;\n hidden?: boolean;\n examples?: unknown[];\n}\n\ntype PositionalArgs<TObj> =\n TObj extends Record<string, any>\n ? {\n [K in keyof TObj]: TObj[K] extends Array<any> ? `...${K & string}` : K & string;\n }[keyof TObj]\n : string;\n\n/**\n * Meta configuration for arguments, including positional arguments.\n * The `positional` array defines which arguments are positional and their order.\n * Use '...name' prefix to indicate variadic (rest) arguments, matching JS/TS rest syntax.\n *\n * @example\n * ```ts\n * .arguments(schema, {\n * positional: ['source', '...files', 'dest'], // '...files' is variadic\n * })\n * ```\n */\n/**\n * Configuration for reading from stdin and mapping it to an argument field.\n */\nexport type StdinConfig<TObj = Record<string, any>> =\n | (keyof TObj & string)\n | {\n /** The argument field to populate with stdin data. */\n field: keyof TObj & string;\n /**\n * How to consume stdin:\n * - `'text'` (default): read all stdin as a single string.\n * - `'lines'`: read stdin as an array of lines (string[]).\n */\n as?: 'text' | 'lines';\n };\n\nexport interface PadroneArgsSchemaMeta<TObj = Record<string, any>> {\n /**\n * Array of argument names that should be treated as positional arguments.\n * Order in array determines position. Use '...name' prefix for variadic args.\n * @example ['source', '...files', 'dest'] - 'files' captures multiple values\n */\n positional?: PositionalArgs<TObj>[];\n /**\n * Per-argument metadata.\n */\n fields?: { [K in keyof TObj]?: PadroneFieldMeta };\n /**\n * Automatically generate kebab-case aliases for camelCase option names.\n * For example, `dryRun` automatically gets `--dry-run` as an alias.\n * Defaults to `true`. Set to `false` to disable.\n *\n * @default true\n * @example\n * ```ts\n * // Auto-aliases enabled (default): --dry-run → dryRun\n * .arguments(z.object({ dryRun: z.boolean() }))\n *\n * // Disable auto-aliases\n * .arguments(z.object({ dryRun: z.boolean() }), { autoAlias: false })\n * ```\n */\n autoAlias?: boolean;\n /**\n * Read from stdin and inject the data into the specified argument field.\n * Only reads when stdin is piped (not a TTY) and the field wasn't already provided via CLI flags.\n *\n * - `string`: shorthand for `{ field: name, as: 'text' }` — read all stdin as a string.\n * - `{ field, as }`: explicit form. `as: 'text'` reads all stdin as a string,\n * `as: 'lines'` reads stdin as an array of line strings.\n *\n * Precedence: CLI flags > stdin > env vars > config file > schema defaults.\n *\n * @example\n * ```ts\n * // Shorthand: read all stdin as text into 'data' field\n * .arguments(z.object({ data: z.string() }), { stdin: 'data' })\n *\n * // Explicit: read stdin lines into 'lines' field\n * .arguments(z.object({ lines: z.string().array() }), {\n * stdin: { field: 'lines', as: 'lines' },\n * })\n * ```\n */\n stdin?: StdinConfig<TObj>;\n /**\n * Fields to interactively prompt for when their values are missing after CLI/env/config resolution.\n * - `true`: prompt for all required fields that are missing.\n * - `string[]`: prompt for these specific fields if missing.\n *\n * Interactive prompting only occurs in `cli()` when the runtime has `interactive: true`.\n * Setting this makes `parse()` and `cli()` return Promises.\n *\n * @example\n * ```ts\n * .arguments(schema, {\n * interactive: true, // prompt all missing required fields\n * interactive: ['name', 'template'], // prompt only these fields\n * })\n * ```\n */\n interactive?: true | (keyof TObj & string)[];\n /**\n * Optional fields offered after required interactive prompts.\n * Users are shown a multi-select to choose which of these fields to configure.\n * - `true`: offer all optional fields that are missing.\n * - `string[]`: offer these specific fields.\n *\n * @example\n * ```ts\n * .arguments(schema, {\n * interactive: ['name'],\n * optionalInteractive: ['typescript', 'eslint', 'prettier'],\n * })\n * ```\n */\n optionalInteractive?: true | (keyof TObj & string)[];\n}\n\n/**\n * Convert a camelCase string to kebab-case.\n * Returns null if the string has no uppercase letters (no conversion needed).\n */\nexport function camelToKebab(str: string): string | null {\n if (!/[A-Z]/.test(str)) return null;\n return str.replace(/[A-Z]/g, (ch) => `-${ch.toLowerCase()}`);\n}\n\n/**\n * Normalizes stdin config into its explicit form.\n */\nexport function parseStdinConfig(stdin: StdinConfig): { field: string; as: 'text' | 'lines' } {\n if (typeof stdin === 'string') return { field: stdin, as: 'text' };\n return { field: stdin.field as string, as: stdin.as ?? 'text' };\n}\n\n/**\n * Parse positional configuration to extract names and variadic info.\n */\nexport function parsePositionalConfig(positional: string[]): { name: string; variadic: boolean }[] {\n return positional.map((p) => {\n const isVariadic = p.startsWith('...');\n const name = isVariadic ? p.slice(3) : p;\n return { name, variadic: isVariadic };\n });\n}\n\n/**\n * Result type for extractSchemaMetadata function.\n */\ninterface SchemaMetadataResult {\n /** Single-char flags: maps flag char → full arg name (e.g. `{ v: 'verbose' }`) */\n flags: Record<string, string>;\n /** Multi-char aliases: maps alias → full arg name (e.g. `{ 'dry-run': 'dryRun' }`) */\n aliases: Record<string, string>;\n}\n\nfunction addEntries(target: Record<string, string>, key: string, items: string | string[], filter?: (item: string) => boolean) {\n const list = typeof items === 'string' ? [items] : items;\n for (const item of list) {\n if (typeof item === 'string' && item && item !== key && !(item in target) && (!filter || filter(item))) {\n target[item] = key;\n }\n }\n}\n\n/**\n * Extract all arg metadata from schema and meta in a single pass.\n * Returns flags (single-char, stackable) and aliases (multi-char, long names) separately.\n * When `autoAlias` is true (default), camelCase property names automatically get kebab-case aliases.\n */\nexport function extractSchemaMetadata(\n schema: StandardJSONSchemaV1,\n meta?: Record<string, PadroneFieldMeta | undefined>,\n autoAlias?: boolean,\n): SchemaMetadataResult {\n const flags: Record<string, string> = {};\n const aliases: Record<string, string> = {};\n\n // Extract from meta object\n if (meta) {\n for (const [key, value] of Object.entries(meta)) {\n if (!value) continue;\n\n if (value.flags) {\n addEntries(flags, key, value.flags, (item) => item.length === 1);\n }\n if (value.alias) {\n addEntries(aliases, key, value.alias, (item) => item.length > 1);\n }\n }\n }\n\n // Extract from JSON schema properties\n try {\n const jsonSchema = schema['~standard'].jsonSchema.input({ target: 'draft-2020-12' }) as Record<string, any>;\n if (jsonSchema.type === 'object' && jsonSchema.properties) {\n for (const [propertyName, propertySchema] of Object.entries(jsonSchema.properties as Record<string, any>)) {\n if (!propertySchema) continue;\n\n // Extract flags from schema `.meta({ flags: ... })`\n const propFlags = propertySchema.flags;\n if (propFlags) {\n addEntries(flags, propertyName, propFlags, (item) => item.length === 1);\n }\n\n // Extract aliases from schema `.meta({ alias: ... })`\n const propAlias = propertySchema.alias;\n if (propAlias) {\n const list = typeof propAlias === 'string' ? [propAlias] : propAlias;\n if (Array.isArray(list)) {\n addEntries(aliases, propertyName, list, (item) => item.length > 1);\n }\n }\n\n // Auto-generate kebab-case alias for camelCase property names\n if (autoAlias !== false) {\n const kebab = camelToKebab(propertyName);\n if (kebab && !(kebab in aliases)) {\n aliases[kebab] = propertyName;\n }\n }\n }\n }\n } catch {\n // Ignore errors from JSON schema generation\n }\n\n return { flags, aliases };\n}\n\nfunction preprocessMappings(data: Record<string, unknown>, mappings: Record<string, string>): Record<string, unknown> {\n const result = { ...data };\n\n for (const [mappedKey, fullArgName] of Object.entries(mappings)) {\n if (mappedKey in data && mappedKey !== fullArgName) {\n const mappedValue = data[mappedKey];\n // Prefer full arg name if it exists\n if (!(fullArgName in result)) result[fullArgName] = mappedValue;\n delete result[mappedKey];\n }\n }\n\n return result;\n}\n\ninterface ParseArgsContext {\n flags?: Record<string, string>;\n aliases?: Record<string, string>;\n stdinData?: Record<string, unknown>;\n envData?: Record<string, unknown>;\n configData?: Record<string, unknown>;\n}\n\n/**\n * Apply values directly to arguments.\n * CLI values take precedence over the provided values.\n */\nfunction applyValues(data: Record<string, unknown>, values: Record<string, unknown>): Record<string, unknown> {\n const result = { ...data };\n\n for (const [key, value] of Object.entries(values)) {\n // Only apply value if arg wasn't already set\n if (key in result && result[key] !== undefined) continue;\n if (value !== undefined) {\n result[key] = value;\n }\n }\n\n return result;\n}\n\n/**\n * Combined preprocessing of arguments with all features.\n * Precedence order (highest to lowest): CLI args > stdin > env vars > config file\n */\nexport function preprocessArgs(data: Record<string, unknown>, ctx: ParseArgsContext): Record<string, unknown> {\n let result = { ...data };\n\n // 1. Apply flags and aliases first\n if (ctx.flags && Object.keys(ctx.flags).length > 0) {\n result = preprocessMappings(result, ctx.flags);\n }\n if (ctx.aliases && Object.keys(ctx.aliases).length > 0) {\n result = preprocessMappings(result, ctx.aliases);\n }\n\n // 2. Apply stdin data (higher precedence than env)\n // Only applies if CLI didn't set the arg\n if (ctx.stdinData) {\n result = applyValues(result, ctx.stdinData);\n }\n\n // 3. Apply environment variables (higher precedence than config)\n // These only apply if CLI/stdin didn't set the arg\n if (ctx.envData) {\n result = applyValues(result, ctx.envData);\n }\n\n // 4. Apply config file values (lowest precedence)\n // These only apply if neither CLI, stdin, nor env set the arg\n if (ctx.configData) {\n result = applyValues(result, ctx.configData);\n }\n\n return result;\n}\n\n/**\n * Auto-coerce CLI string values to match the expected schema types.\n * Handles: string → number, string → boolean for primitive schema fields.\n * Arrays of primitives are also coerced element-wise.\n */\nexport function coerceArgs(data: Record<string, unknown>, schema: StandardJSONSchemaV1): Record<string, unknown> {\n let properties: Record<string, any>;\n try {\n const jsonSchema = schema['~standard'].jsonSchema.input({ target: 'draft-2020-12' }) as Record<string, any>;\n if (jsonSchema.type !== 'object' || !jsonSchema.properties) return data;\n properties = jsonSchema.properties;\n } catch {\n return data;\n }\n\n const result = { ...data };\n\n for (const [key, value] of Object.entries(result)) {\n const prop = properties[key];\n if (!prop) continue;\n\n const targetType = prop.type as string | undefined;\n\n if (targetType === 'number' || targetType === 'integer') {\n if (typeof value === 'string') {\n const num = Number(value);\n if (!Number.isNaN(num)) result[key] = num;\n }\n } else if (targetType === 'boolean') {\n if (typeof value === 'string') {\n if (value === 'true' || value === '1') result[key] = true;\n else if (value === 'false' || value === '0') result[key] = false;\n }\n } else if (targetType === 'array' && Array.isArray(value)) {\n const itemType = prop.items?.type as string | undefined;\n if (itemType === 'number' || itemType === 'integer') {\n result[key] = value.map((v) => {\n if (typeof v === 'string') {\n const num = Number(v);\n return Number.isNaN(num) ? v : num;\n }\n return v;\n });\n } else if (itemType === 'boolean') {\n result[key] = value.map((v) => {\n if (typeof v === 'string') {\n if (v === 'true' || v === '1') return true;\n if (v === 'false' || v === '0') return false;\n }\n return v;\n });\n }\n }\n }\n\n return result;\n}\n\n/** Keys consumed by the CLI framework that are not user-defined args. */\nconst frameworkReservedKeys = new Set(['config', 'c']);\n\n/**\n * Detect unknown keys in the args that don't match any schema property.\n * Returns an array of { key, suggestion? } for each unknown key.\n * Framework-reserved keys (--config, -c) are always allowed.\n */\nexport function detectUnknownArgs(\n data: Record<string, unknown>,\n schema: StandardJSONSchemaV1,\n flags: Record<string, string>,\n aliases: Record<string, string>,\n suggestFn: (input: string, candidates: string[]) => string,\n): { key: string; suggestion: string }[] {\n let properties: Record<string, any>;\n let isLoose = false;\n try {\n const jsonSchema = schema['~standard'].jsonSchema.input({ target: 'draft-2020-12' }) as Record<string, any>;\n if (jsonSchema.type !== 'object' || !jsonSchema.properties) return [];\n properties = jsonSchema.properties;\n // If additionalProperties is set (true, {}, or a schema), the schema allows extra keys\n if (jsonSchema.additionalProperties !== undefined && jsonSchema.additionalProperties !== false) isLoose = true;\n } catch {\n return [];\n }\n\n if (isLoose) return [];\n\n const knownKeys = new Set<string>([\n ...Object.keys(properties),\n ...Object.keys(flags),\n ...Object.values(flags),\n ...Object.keys(aliases),\n ...Object.values(aliases),\n ]);\n const propertyNames = Object.keys(properties);\n const unknowns: { key: string; suggestion: string }[] = [];\n\n for (const key of Object.keys(data)) {\n if (!knownKeys.has(key) && !frameworkReservedKeys.has(key)) {\n const suggestion = suggestFn(key, propertyNames);\n unknowns.push({ key, suggestion });\n }\n }\n\n return unknowns;\n}\n"],"mappings":"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"}
@@ -1,5 +0,0 @@
1
- import { createRequire } from "node:module";
2
- //#region \0rolldown/runtime.js
3
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
4
- //#endregion
5
- export { __require as t };
@@ -1 +0,0 @@
1
- {"version":3,"file":"formatter-XroimS3Q.d.mts","names":[],"sources":["../src/formatter.ts"],"mappings":";KAGY,UAAA;AAAA,KACA,UAAA;;;;KASA,kBAAA;EACV,IAAA;EACA,WAAA;EACA,QAAA;EACA,OAAA;EACA,IAAA;AAAA;;;;KAMU,gBAAA;EACV,IAAA;EACA,WAAA;EACA,QAAA;EACA,OAAA;EACA,IAAA;EACA,IAAA,aANU;EAQV,KAAA;EAEA,OAAA;EACA,UAAA;EACA,MAAA;EACA,QAAA,cATA;EAWA,GAAA,sBATA;EAWA,QAAA,YAPA;EASA,SAAA,YAPA;EASA,SAAA;AAAA;;;;KAMU,kBAAA;EACV,IAAA;EACA,KAAA;EACA,WAAA;EACA,OAAA;EACA,UAAA;EACA,MAAA;EACA,cAAA;AAAA;;;;KAMU,eAAA;EACV,IAAA;EACA,WAAA;EACA,GAAA;IAAQ,IAAA;IAAc,WAAA;EAAA;AAAA;;;;;KAOZ,QAAA;EAPuB,4DASjC,IAAA,UAFkB;EAIlB,KAAA,WAmBc;EAjBd,WAAA,WAqBY;EAnBZ,OAAA,aAuBiB;EArBjB,UAAA,qBAqByB;EAnBzB,MAAA,YARA;EAUA,KAAA;IACE,OAAA;IACA,cAAA;IACA,cAAA;IACA,YAAA,WAHA;IAKA,UAAA;EAAA,GAFA;EAKF,WAAA,GAAc,kBAAA,IAAd;EAEA,WAAA,GAAc,kBAAA,IAAd;EAEA,SAAA,GAAY,gBAAA,IAAZ;EAEA,QAAA,GAAW,eAAA,IAAX;EAEA,cAAA,GAAiB,QAAA;AAAA"}