bob-core 3.0.0-beta.1 → 3.0.0-beta.11

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 (185) hide show
  1. package/README.md +3 -3
  2. package/dist/cjs/{src/Cli.d.ts → Cli.d.ts} +20 -0
  3. package/dist/cjs/Command.d.ts +91 -0
  4. package/dist/cjs/CommandParser.d.ts +122 -0
  5. package/dist/cjs/{src/CommandRegistry.d.ts → CommandRegistry.d.ts} +12 -0
  6. package/dist/cjs/ExceptionHandler.d.ts +14 -0
  7. package/dist/cjs/HelpFlag.d.ts +25 -0
  8. package/dist/cjs/StringSimilarity.d.ts +31 -0
  9. package/dist/cjs/args/index.d.ts +135 -0
  10. package/dist/{esm/src → cjs}/errors/BadCommandArgument.d.ts +4 -2
  11. package/dist/cjs/{src/errors → errors}/BadCommandFlag.d.ts +4 -2
  12. package/dist/cjs/errors/BobError.d.ts +13 -0
  13. package/dist/cjs/errors/CommandNotFoundError.d.ts +9 -0
  14. package/dist/{esm/src → cjs}/errors/InvalidFlag.d.ts +4 -2
  15. package/dist/cjs/errors/MissingRequiredArgumentValue.d.ts +9 -0
  16. package/dist/cjs/errors/MissingRequiredFlagValue.d.ts +9 -0
  17. package/dist/cjs/errors/TooManyArguments.d.ts +10 -0
  18. package/dist/cjs/errors/ValidationError.d.ts +10 -0
  19. package/dist/cjs/errors/renderError.d.ts +9 -0
  20. package/dist/cjs/flags/boolean.d.ts +18 -0
  21. package/dist/cjs/flags/custom.d.ts +12 -0
  22. package/dist/cjs/flags/directory.d.ts +29 -0
  23. package/dist/cjs/flags/file.d.ts +29 -0
  24. package/dist/cjs/flags/helpers.d.ts +9 -0
  25. package/dist/cjs/flags/index.d.ts +162 -0
  26. package/dist/cjs/flags/number.d.ts +36 -0
  27. package/dist/cjs/flags/option.d.ts +8 -0
  28. package/dist/cjs/flags/string.d.ts +17 -0
  29. package/dist/cjs/flags/url.d.ts +17 -0
  30. package/dist/cjs/{src/index.d.ts → index.d.ts} +0 -1
  31. package/dist/cjs/index.js +10 -0
  32. package/dist/cjs/{src/lib → lib}/helpers.d.ts +1 -1
  33. package/dist/cjs/lib/types.d.ts +97 -0
  34. package/dist/cjs/shared/ask-helpers.d.ts +7 -0
  35. package/dist/cjs/shared/flagsUtils.d.ts +5 -0
  36. package/dist/cjs/ux/askForConfirmation.d.ts +10 -0
  37. package/dist/cjs/{src/ux → ux}/askForToggle.d.ts +5 -1
  38. package/dist/cjs/ux/helpers.d.ts +6 -0
  39. package/dist/cjs/{src/ux → ux}/index.d.ts +30 -2
  40. package/dist/esm/{src/Cli.d.ts → Cli.d.ts} +20 -0
  41. package/dist/esm/Command.d.ts +91 -0
  42. package/dist/esm/CommandParser.d.ts +122 -0
  43. package/dist/esm/{src/CommandRegistry.d.ts → CommandRegistry.d.ts} +12 -0
  44. package/dist/esm/ExceptionHandler.d.ts +14 -0
  45. package/dist/esm/HelpFlag.d.ts +25 -0
  46. package/dist/esm/StringSimilarity.d.ts +31 -0
  47. package/dist/esm/args/index.d.ts +135 -0
  48. package/dist/{cjs/src → esm}/errors/BadCommandArgument.d.ts +4 -2
  49. package/dist/esm/{src/errors → errors}/BadCommandFlag.d.ts +4 -2
  50. package/dist/esm/errors/BobError.d.ts +13 -0
  51. package/dist/esm/errors/CommandNotFoundError.d.ts +9 -0
  52. package/dist/{cjs/src → esm}/errors/InvalidFlag.d.ts +4 -2
  53. package/dist/esm/errors/MissingRequiredArgumentValue.d.ts +9 -0
  54. package/dist/esm/errors/MissingRequiredFlagValue.d.ts +9 -0
  55. package/dist/esm/errors/TooManyArguments.d.ts +10 -0
  56. package/dist/esm/errors/ValidationError.d.ts +10 -0
  57. package/dist/esm/errors/renderError.d.ts +9 -0
  58. package/dist/esm/flags/boolean.d.ts +18 -0
  59. package/dist/esm/flags/custom.d.ts +12 -0
  60. package/dist/esm/flags/directory.d.ts +29 -0
  61. package/dist/esm/flags/file.d.ts +29 -0
  62. package/dist/esm/flags/helpers.d.ts +9 -0
  63. package/dist/esm/flags/index.d.ts +162 -0
  64. package/dist/esm/flags/number.d.ts +36 -0
  65. package/dist/esm/flags/option.d.ts +8 -0
  66. package/dist/esm/flags/string.d.ts +17 -0
  67. package/dist/esm/flags/url.d.ts +17 -0
  68. package/dist/esm/{src/index.d.ts → index.d.ts} +0 -1
  69. package/dist/esm/{src/index.js → index.js} +417 -309
  70. package/dist/esm/{src/lib → lib}/helpers.d.ts +1 -1
  71. package/dist/esm/lib/types.d.ts +97 -0
  72. package/dist/esm/shared/ask-helpers.d.ts +7 -0
  73. package/dist/esm/shared/flagsUtils.d.ts +5 -0
  74. package/dist/esm/ux/askForConfirmation.d.ts +10 -0
  75. package/dist/esm/{src/ux → ux}/askForToggle.d.ts +5 -1
  76. package/dist/esm/ux/helpers.d.ts +6 -0
  77. package/dist/esm/{src/ux → ux}/index.d.ts +30 -2
  78. package/package.json +11 -10
  79. package/dist/cjs/package-supL7Tgp.cjs +0 -1
  80. package/dist/cjs/src/Command.d.ts +0 -48
  81. package/dist/cjs/src/CommandParser.d.ts +0 -110
  82. package/dist/cjs/src/ExceptionHandler.d.ts +0 -6
  83. package/dist/cjs/src/StringSimilarity.d.ts +0 -26
  84. package/dist/cjs/src/args/index.d.ts +0 -42
  85. package/dist/cjs/src/errors/BobError.d.ts +0 -5
  86. package/dist/cjs/src/errors/CommandNotFoundError.d.ts +0 -7
  87. package/dist/cjs/src/errors/MissingRequiredArgumentValue.d.ts +0 -7
  88. package/dist/cjs/src/errors/MissingRequiredFlagValue.d.ts +0 -7
  89. package/dist/cjs/src/errors/TooManyArguments.d.ts +0 -8
  90. package/dist/cjs/src/errors/ValidationError.d.ts +0 -3
  91. package/dist/cjs/src/flags/boolean.d.ts +0 -4
  92. package/dist/cjs/src/flags/custom.d.ts +0 -7
  93. package/dist/cjs/src/flags/directory.d.ts +0 -9
  94. package/dist/cjs/src/flags/file.d.ts +0 -9
  95. package/dist/cjs/src/flags/helpers.d.ts +0 -2
  96. package/dist/cjs/src/flags/index.d.ts +0 -46
  97. package/dist/cjs/src/flags/number.d.ts +0 -12
  98. package/dist/cjs/src/flags/option.d.ts +0 -6
  99. package/dist/cjs/src/flags/string.d.ts +0 -3
  100. package/dist/cjs/src/flags/url.d.ts +0 -3
  101. package/dist/cjs/src/index.js +0 -10
  102. package/dist/cjs/src/lib/types.d.ts +0 -59
  103. package/dist/cjs/src/options/HelpOption.d.ts +0 -9
  104. package/dist/cjs/src/options/index.d.ts +0 -1
  105. package/dist/cjs/src/shared/ask-helpers.d.ts +0 -7
  106. package/dist/cjs/src/ux/askForConfirmation.d.ts +0 -5
  107. package/dist/cjs/src/ux/helpers.d.ts +0 -1
  108. package/dist/esm/package-BNru0kNU.js +0 -59
  109. package/dist/esm/src/Command.d.ts +0 -48
  110. package/dist/esm/src/CommandParser.d.ts +0 -110
  111. package/dist/esm/src/ExceptionHandler.d.ts +0 -6
  112. package/dist/esm/src/StringSimilarity.d.ts +0 -26
  113. package/dist/esm/src/args/index.d.ts +0 -42
  114. package/dist/esm/src/errors/BobError.d.ts +0 -5
  115. package/dist/esm/src/errors/CommandNotFoundError.d.ts +0 -7
  116. package/dist/esm/src/errors/MissingRequiredArgumentValue.d.ts +0 -7
  117. package/dist/esm/src/errors/MissingRequiredFlagValue.d.ts +0 -7
  118. package/dist/esm/src/errors/TooManyArguments.d.ts +0 -8
  119. package/dist/esm/src/errors/ValidationError.d.ts +0 -3
  120. package/dist/esm/src/flags/boolean.d.ts +0 -4
  121. package/dist/esm/src/flags/custom.d.ts +0 -7
  122. package/dist/esm/src/flags/directory.d.ts +0 -9
  123. package/dist/esm/src/flags/file.d.ts +0 -9
  124. package/dist/esm/src/flags/helpers.d.ts +0 -2
  125. package/dist/esm/src/flags/index.d.ts +0 -46
  126. package/dist/esm/src/flags/number.d.ts +0 -12
  127. package/dist/esm/src/flags/option.d.ts +0 -6
  128. package/dist/esm/src/flags/string.d.ts +0 -3
  129. package/dist/esm/src/flags/url.d.ts +0 -3
  130. package/dist/esm/src/lib/types.d.ts +0 -59
  131. package/dist/esm/src/options/HelpOption.d.ts +0 -9
  132. package/dist/esm/src/options/index.d.ts +0 -1
  133. package/dist/esm/src/shared/ask-helpers.d.ts +0 -7
  134. package/dist/esm/src/ux/askForConfirmation.d.ts +0 -5
  135. package/dist/esm/src/ux/helpers.d.ts +0 -1
  136. /package/dist/cjs/{src/CommandSignatureParser.d.ts → CommandSignatureParser.d.ts} +0 -0
  137. /package/dist/cjs/{src/CommandWithSignature.d.ts → CommandWithSignature.d.ts} +0 -0
  138. /package/dist/cjs/{src/Logger.d.ts → Logger.d.ts} +0 -0
  139. /package/dist/cjs/{src/commands → commands}/HelpCommand.d.ts +0 -0
  140. /package/dist/cjs/{src/contracts → contracts}/LoggerContract.d.ts +0 -0
  141. /package/dist/cjs/{src/contracts → contracts}/index.d.ts +0 -0
  142. /package/dist/cjs/{src/errors → errors}/index.d.ts +0 -0
  143. /package/dist/cjs/{src/lib → lib}/string.d.ts +0 -0
  144. /package/dist/cjs/{src/shared → shared}/parsers.d.ts +0 -0
  145. /package/dist/cjs/{src/ux → ux}/askForCheckbox.d.ts +0 -0
  146. /package/dist/cjs/{src/ux → ux}/askForEditor.d.ts +0 -0
  147. /package/dist/cjs/{src/ux → ux}/askForExpand.d.ts +0 -0
  148. /package/dist/cjs/{src/ux → ux}/askForFileSelector.d.ts +0 -0
  149. /package/dist/cjs/{src/ux → ux}/askForInput.d.ts +0 -0
  150. /package/dist/cjs/{src/ux → ux}/askForList.d.ts +0 -0
  151. /package/dist/cjs/{src/ux → ux}/askForNumber.d.ts +0 -0
  152. /package/dist/cjs/{src/ux → ux}/askForPassword.d.ts +0 -0
  153. /package/dist/cjs/{src/ux → ux}/askForRawList.d.ts +0 -0
  154. /package/dist/cjs/{src/ux → ux}/askForSearch.d.ts +0 -0
  155. /package/dist/cjs/{src/ux → ux}/askForSelect.d.ts +0 -0
  156. /package/dist/cjs/{src/ux → ux}/keyValue.d.ts +0 -0
  157. /package/dist/cjs/{src/ux → ux}/loader.d.ts +0 -0
  158. /package/dist/cjs/{src/ux → ux}/progressBar.d.ts +0 -0
  159. /package/dist/cjs/{src/ux → ux}/table.d.ts +0 -0
  160. /package/dist/cjs/{src/ux → ux}/types.d.ts +0 -0
  161. /package/dist/esm/{src/CommandSignatureParser.d.ts → CommandSignatureParser.d.ts} +0 -0
  162. /package/dist/esm/{src/CommandWithSignature.d.ts → CommandWithSignature.d.ts} +0 -0
  163. /package/dist/esm/{src/Logger.d.ts → Logger.d.ts} +0 -0
  164. /package/dist/esm/{src/commands → commands}/HelpCommand.d.ts +0 -0
  165. /package/dist/esm/{src/contracts → contracts}/LoggerContract.d.ts +0 -0
  166. /package/dist/esm/{src/contracts → contracts}/index.d.ts +0 -0
  167. /package/dist/esm/{src/errors → errors}/index.d.ts +0 -0
  168. /package/dist/esm/{src/lib → lib}/string.d.ts +0 -0
  169. /package/dist/esm/{src/shared → shared}/parsers.d.ts +0 -0
  170. /package/dist/esm/{src/ux → ux}/askForCheckbox.d.ts +0 -0
  171. /package/dist/esm/{src/ux → ux}/askForEditor.d.ts +0 -0
  172. /package/dist/esm/{src/ux → ux}/askForExpand.d.ts +0 -0
  173. /package/dist/esm/{src/ux → ux}/askForFileSelector.d.ts +0 -0
  174. /package/dist/esm/{src/ux → ux}/askForInput.d.ts +0 -0
  175. /package/dist/esm/{src/ux → ux}/askForList.d.ts +0 -0
  176. /package/dist/esm/{src/ux → ux}/askForNumber.d.ts +0 -0
  177. /package/dist/esm/{src/ux → ux}/askForPassword.d.ts +0 -0
  178. /package/dist/esm/{src/ux → ux}/askForRawList.d.ts +0 -0
  179. /package/dist/esm/{src/ux → ux}/askForSearch.d.ts +0 -0
  180. /package/dist/esm/{src/ux → ux}/askForSelect.d.ts +0 -0
  181. /package/dist/esm/{src/ux → ux}/keyValue.d.ts +0 -0
  182. /package/dist/esm/{src/ux → ux}/loader.d.ts +0 -0
  183. /package/dist/esm/{src/ux → ux}/progressBar.d.ts +0 -0
  184. /package/dist/esm/{src/ux → ux}/table.d.ts +0 -0
  185. /package/dist/esm/{src/ux → ux}/types.d.ts +0 -0
package/README.md CHANGED
@@ -100,7 +100,7 @@ static flags = {
100
100
  name: Flags.string({ required: true, description: 'Your name' }),
101
101
  count: Flags.number({ min: 1, max: 10, default: 1 }),
102
102
  force: Flags.boolean({ alias: 'f' }),
103
- level: Flags.enum({ options: ['debug', 'info', 'warn', 'error'] as const }),
103
+ level: Flags.option({ options: ['debug', 'info', 'warn', 'error'] as const }),
104
104
  config: Flags.file({ exists: true, description: 'Config file path' }),
105
105
  outDir: Flags.directory({ exists: true }),
106
106
  endpoint: Flags.url({ description: 'API endpoint' }),
@@ -113,13 +113,13 @@ static flags = {
113
113
  | `Flags.string()` | `string` | `secret` |
114
114
  | `Flags.number()` | `number` | `min`, `max` |
115
115
  | `Flags.boolean()` | `boolean` | |
116
- | `Flags.enum()` | union of `options` | `options` (readonly tuple) |
116
+ | `Flags.option()` | union of `options` | `options` (readonly tuple) |
117
117
  | `Flags.file()` | `string` | `exists` |
118
118
  | `Flags.directory()` | `string` | `exists` |
119
119
  | `Flags.url()` | `URL` | |
120
120
  | `Flags.custom<T>()` | `T` | `parse` (required) |
121
121
 
122
- `Args` is an alias for `Flags` -- use it for semantic clarity when defining `static args`.
122
+ `Args` is a separate builder set from `Flags` (it omits `boolean`) -- use it for semantic clarity when defining `static args`.
123
123
 
124
124
  Use `satisfies FlagsSchema` on both `static flags` and `static args` to enable full type inference with `Parsed<typeof YourCommand>`.
125
125
 
@@ -10,6 +10,14 @@ export type CliOptions<C extends ContextDefinition = ContextDefinition> = {
10
10
  version?: string;
11
11
  logger?: Logger;
12
12
  };
13
+ /**
14
+ * CLI host. Wires together a {@link CommandRegistry}, {@link ExceptionHandler},
15
+ * and the built-in {@link HelpCommand}, and provides the entry point used by
16
+ * binaries to dispatch a command.
17
+ *
18
+ * The `C` generic threads a typed application context through to every command
19
+ * registered with the CLI.
20
+ */
13
21
  export declare class Cli<C extends ContextDefinition = ContextDefinition> {
14
22
  private readonly ctx?;
15
23
  private readonly logger;
@@ -22,10 +30,22 @@ export declare class Cli<C extends ContextDefinition = ContextDefinition> {
22
30
  logger: Logger;
23
31
  }): ExceptionHandler;
24
32
  constructor(opts?: CliOptions<C>);
33
+ /** Registers a custom resolver used by `loadCommandsPath` to import command modules. */
25
34
  withCommandResolver(resolver: CommandResolver): this;
35
+ /** Overrides how command files are imported (useful for tests / virtual filesystems). */
26
36
  withFileImporter(importer: FileImporter): this;
37
+ /**
38
+ * Registers commands by class, instance, or directory path. String args are
39
+ * treated as filesystem paths and walked via the registry's resolver.
40
+ */
27
41
  withCommands(...commands: Array<typeof Command<C> | Command<C> | string>): Promise<void>;
42
+ /**
43
+ * Resolves and runs a command. Bob errors are formatted by the
44
+ * {@link ExceptionHandler} and yield a non-zero exit code; non-Bob errors
45
+ * propagate so they remain visible in stack traces. Returns the exit code.
46
+ */
28
47
  runCommand(command: string | typeof Command | Command | undefined, ...args: string[]): Promise<number>;
48
+ /** Convenience entry point that prints help with the registered commands. */
29
49
  runHelpCommand(): Promise<number>;
30
50
  protected registerCommand(command: typeof Command<C>): void;
31
51
  }
@@ -0,0 +1,91 @@
1
+ import { CommandParser } from './CommandParser.js';
2
+ import { Logger } from './Logger.js';
3
+ import { ArgsSchema, ContextDefinition, FlagsSchema, Parsed } from './lib/types.js';
4
+ import { UX } from './ux/index.js';
5
+ export type CommandRunExample = {
6
+ description: string;
7
+ command: string;
8
+ };
9
+ export type CommandRunOption<C = ContextDefinition> = {
10
+ logger: Logger;
11
+ ctx: C;
12
+ } & ({
13
+ args: string[];
14
+ } | {
15
+ args: Record<string, any>;
16
+ flags: Record<string, any>;
17
+ });
18
+ /**
19
+ * Base class for declarative commands.
20
+ *
21
+ * Subclasses set static metadata (`command`, `description`, `args`, `flags`,
22
+ * `examples`, `aliases`, `group`, `hidden`) and implement `handle(ctx, parsed)`.
23
+ * The framework parses argv, validates against `args`/`flags`, optionally
24
+ * prompts for missing required values, then invokes `preHandle` (if defined)
25
+ * and finally `handle`.
26
+ *
27
+ * The `C` generic threads a typed application context through to `handle`.
28
+ */
29
+ export declare abstract class Command<C extends ContextDefinition = ContextDefinition> {
30
+ /** Discriminator used by `isBobCommandClass` for `instanceof`-free checks. */
31
+ static $type: "BobCommand";
32
+ /** Canonical command name typed at the CLI (e.g. `"deploy"`, `"db:migrate"`). */
33
+ static command: string;
34
+ /** One-line description rendered in `help`. */
35
+ static description: string;
36
+ /** Optional grouping label for the help screen — defaults to the prefix before `:` if any. */
37
+ static group?: string;
38
+ /** Positional argument schema (use `Args.*` builders). */
39
+ static args: ArgsSchema;
40
+ /** Named flag schema (use `Flags.*` builders). */
41
+ static flags: FlagsSchema;
42
+ /** Example invocations rendered in `--help`. */
43
+ static examples: CommandRunExample[];
44
+ /** When true, the command is omitted from the help index but still runnable. */
45
+ static hidden: boolean;
46
+ /** Alternative names that resolve to this command. */
47
+ static aliases: string[];
48
+ /** When true, `baseFlags` (including `--help`) are not auto-merged. */
49
+ static disableDefaultOptions: boolean;
50
+ /** When true, missing required values will not trigger interactive prompts. */
51
+ static disablePrompting: boolean;
52
+ /** When true, unknown flags are accepted instead of throwing `InvalidFlag`. */
53
+ static allowUnknownFlags: boolean;
54
+ /** When true, extra positional arguments throw `TooManyArguments`. */
55
+ static strictMode: boolean;
56
+ protected ctx: C;
57
+ protected logger: Logger;
58
+ protected ux: UX;
59
+ protected parser: CommandParser<FlagsSchema, ArgsSchema>;
60
+ /**
61
+ * Optional pre-handler hook. Returning a non-zero number short-circuits
62
+ * execution and is propagated as the command's exit code.
63
+ */
64
+ protected preHandle?(): Promise<void | number>;
65
+ /**
66
+ * Main entry point. Receives the typed context and the parsed flags/args.
67
+ * Returning a number sets the exit code; void/undefined is treated as 0.
68
+ */
69
+ protected abstract handle(ctx: C, parsed: Parsed<any>): Promise<number | void> | number | void;
70
+ /** Flags merged into every command's flag schema (`--help` by default). */
71
+ static baseFlags: FlagsSchema;
72
+ protected newCommandParser(opts: {
73
+ flags: FlagsSchema;
74
+ args: ArgsSchema;
75
+ ctx: ContextDefinition;
76
+ ux: UX;
77
+ cmd: typeof Command;
78
+ }): CommandParser<FlagsSchema, ArgsSchema>;
79
+ protected newUX(): UX;
80
+ /**
81
+ * Runs the command lifecycle. Resolves to the exit code:
82
+ * - `0` — success (or `void` from `handle`)
83
+ * - returned number from `preHandle` / `handle` for early exits
84
+ * - `0` for flag-handler short-circuits like `--help`
85
+ *
86
+ * Either parses raw `args: string[]` or accepts pre-parsed `flags`/`args`
87
+ * objects (used internally to invoke commands programmatically without
88
+ * re-running the parser).
89
+ */
90
+ run(runOpts: CommandRunOption<C>): Promise<number | void>;
91
+ }
@@ -0,0 +1,122 @@
1
+ import { Command } from './Command.js';
2
+ import { ArgsSchema, ContextDefinition, FlagDefinition, FlagReturnType, FlagsObject, FlagsSchema } from './lib/types.js';
3
+ import { UX } from './ux/index.js';
4
+ /**
5
+ * Parses command-line arguments into typed flags and arguments.
6
+ *
7
+ * Lifecycle:
8
+ * 1. `init(argv)` — runs minimist, validates unknown flags, type-converts each
9
+ * value via its definition's `parse` function, and resolves defaults.
10
+ * 2. `validate()` — checks for missing required values; if prompting is
11
+ * enabled and the definition declares an `ask` function, the user is
12
+ * prompted and the response is fed back through `parse`.
13
+ * 3. `flag(name)` / `argument(name)` — typed accessors for the parsed values.
14
+ */
15
+ export declare class CommandParser<Flags extends FlagsSchema, Arguments extends ArgsSchema> {
16
+ protected opts: {
17
+ flags: Flags;
18
+ args: Arguments;
19
+ ctx?: ContextDefinition;
20
+ ux: UX;
21
+ cmd?: typeof Command;
22
+ };
23
+ protected flags: FlagsSchema;
24
+ protected parsedFlags: FlagsObject<Flags> | null;
25
+ protected args: ArgsSchema;
26
+ protected parsedArgs: FlagsObject<Arguments> | null;
27
+ protected ux: UX;
28
+ protected shouldPromptForMissingFlags: boolean;
29
+ protected shouldValidateUnknownFlags: boolean;
30
+ protected shouldRejectExtraArguments: boolean;
31
+ constructor(opts: {
32
+ flags: Flags;
33
+ args: Arguments;
34
+ ctx?: ContextDefinition;
35
+ ux: UX;
36
+ cmd?: typeof Command;
37
+ });
38
+ /**
39
+ * Parses raw command-line arguments into structured flags and arguments.
40
+ *
41
+ * @param args - Raw command line arguments (typically from `process.argv.slice(2)`).
42
+ * @returns Object containing parsed flags and arguments.
43
+ * @throws {InvalidFlag} If an unknown flag is provided and `allowUnknownFlags` is off.
44
+ * @throws {BadCommandFlag} If a flag's value cannot be converted by its `parse` function.
45
+ * @throws {BadCommandArgument} If an argument's value cannot be converted by its `parse` function.
46
+ * @throws {TooManyArguments} If more positional arguments were supplied than declared and strict mode is on.
47
+ */
48
+ init(args: string[]): Promise<{
49
+ flags: FlagsObject<Flags>;
50
+ args: FlagsObject<Arguments>;
51
+ }>;
52
+ /**
53
+ * Validates that all required flags and arguments have a value. Prompts for
54
+ * missing values when prompting is enabled and the definition declares an
55
+ * `ask` function; otherwise throws.
56
+ *
57
+ * @throws {MissingRequiredFlagValue} If a required flag is missing.
58
+ * @throws {MissingRequiredArgumentValue} If a required argument is missing.
59
+ * @throws {BadCommandFlag} / {BadCommandArgument} If a prompted value fails to parse.
60
+ */
61
+ validate(): Promise<void>;
62
+ /**
63
+ * Retrieves a parsed flag value by name. The runtime `defaultValue` is only
64
+ * used when the parsed value is empty (null/undefined/empty string/empty
65
+ * array) — it does not override a real value the user supplied.
66
+ *
67
+ * @throws {Error} If `init()` has not been called yet.
68
+ */
69
+ flag<FlagName extends keyof Flags>(name: FlagName, defaultValue?: FlagReturnType<Flags[FlagName]>): FlagReturnType<Flags[FlagName]>;
70
+ setFlag<FlagName extends keyof Flags>(name: FlagName, value: FlagReturnType<Flags[FlagName]>): Promise<void>;
71
+ /**
72
+ * Retrieves a parsed argument value by name. Same `defaultValue` semantics
73
+ * as {@link flag}.
74
+ *
75
+ * @throws {Error} If `init()` has not been called yet.
76
+ */
77
+ argument<ArgName extends keyof Arguments>(name: ArgName, defaultValue?: FlagReturnType<Arguments[ArgName]>): FlagReturnType<Arguments[ArgName]>;
78
+ setArgument<ArgName extends keyof Arguments>(name: ArgName, value: FlagReturnType<Arguments[ArgName]>): Promise<void>;
79
+ /**
80
+ * "Empty" for runtime accessor / required-prompt purposes: null, undefined,
81
+ * an all-whitespace string, or an empty array. Whitespace strings are
82
+ * intentionally included so a user typing `--name=" "` is still treated as
83
+ * not having satisfied a required flag (and so accessor defaults still kick
84
+ * in for blank values).
85
+ *
86
+ * Use {@link isMissing} when you only care whether the user *omitted* a
87
+ * value — that's the right check for "should I substitute the schema's
88
+ * default?"
89
+ */
90
+ private isEmptyValue;
91
+ /**
92
+ * "Missing" for default-substitution purposes: the user did not supply
93
+ * anything. An empty/whitespace string is *not* missing — the user typed it
94
+ * and the schema's `parse` should be allowed to accept or reject it.
95
+ */
96
+ private isMissing;
97
+ private validateUnknownFlags;
98
+ private handleOptions;
99
+ private handleArguments;
100
+ private resolveFlagValue;
101
+ private parseValue;
102
+ private buildOpts;
103
+ /**
104
+ * Wraps a definition's `parse` and converts user-input failures into
105
+ * {@link BadCommandFlag}/{@link BadCommandArgument}. Programmer bugs (any
106
+ * error that isn't a {@link ValidationError}) propagate unchanged so they
107
+ * surface as real stack traces instead of being misreported as "flag value
108
+ * is invalid".
109
+ */
110
+ private safeParse;
111
+ private validateSchema;
112
+ /** Disables prompting for missing flag and argument values — useful for non-interactive environments. */
113
+ disablePrompting(): this;
114
+ allowUnknownFlags(): this;
115
+ strictMode(): this;
116
+ /**
117
+ * Prompts the user for a missing value via the definition's `ask` function.
118
+ * Returns `null` if no `ask` is registered or the user cancels — callers
119
+ * are responsible for translating that into a `MissingRequired*` error.
120
+ */
121
+ protected promptFor(name: string, definition: FlagDefinition): Promise<string | number | string[] | boolean | null>;
122
+ }
@@ -26,7 +26,19 @@ export declare class CommandRegistry {
26
26
  registerCommand(command: typeof Command<any>, force?: boolean): void;
27
27
  loadCommandsPath(commandsPath: string): Promise<void>;
28
28
  runCommand(ctx: ContextDefinition, command: string | typeof Command | Command, ...args: string[]): Promise<number>;
29
+ /**
30
+ * Looks for a similarly-named command and offers it to the user via prompts.
31
+ * Returns the resolved command name, or `null` for both "no match" and
32
+ * "user cancelled / declined the suggestion" — the caller throws
33
+ * {@link CommandNotFoundError} on `null`. Cancellation is logged at debug
34
+ * level so it's still distinguishable from "no match" in verbose output.
35
+ */
29
36
  private suggestCommand;
30
37
  private askRunSimilarCommand;
38
+ /**
39
+ * Recursively yields every importable command file under `basePath`. Errors
40
+ * from `readdir` are wrapped with the offending path so partial loads
41
+ * surface a clear cause instead of a bare "ENOENT" / "EACCES".
42
+ */
31
43
  private listCommandsFiles;
32
44
  }
@@ -0,0 +1,14 @@
1
+ import { LoggerContract } from './contracts/index.js';
2
+ /**
3
+ * Default error dispatcher used by {@link Cli.runCommand}.
4
+ *
5
+ * Renders {@link BobError}s through their `pretty` method and returns `-1` so
6
+ * the caller can use the value as a process exit code. Any other error type
7
+ * propagates unchanged — these typically represent programmer bugs and should
8
+ * not be silently formatted as user-facing errors.
9
+ */
10
+ export declare class ExceptionHandler {
11
+ private readonly logger;
12
+ constructor(logger: LoggerContract);
13
+ handle(err: Error): number;
14
+ }
@@ -0,0 +1,25 @@
1
+ import { FlagDefinition, FlagOpts } from './lib/types.js';
2
+ export declare const HelpCommandFlag: {
3
+ [x: string]: unknown;
4
+ } & {
5
+ parse: (input: any, opts: FlagOpts<boolean, import('./lib/types.js').CustomOptions, any>) => boolean;
6
+ type?: import('./lib/types.js').FlagKind;
7
+ ask?: ((opts: FlagOpts<boolean, import('./lib/types.js').CustomOptions, any>) => Promise<any>) | undefined;
8
+ description?: string;
9
+ required?: boolean;
10
+ default?: boolean | boolean[] | (() => boolean | boolean[] | null) | (() => Promise<boolean | boolean[] | null>) | null | undefined;
11
+ multiple?: boolean;
12
+ help?: string;
13
+ alias?: string | readonly string[];
14
+ handler?: ((value: boolean, opts: FlagOpts<boolean, import('./lib/types.js').CustomOptions, any>) => {
15
+ shouldStop: boolean;
16
+ } | void) | undefined;
17
+ } & Partial<FlagDefinition<boolean, import('./lib/types.js').CustomOptions, any>> & {
18
+ readonly alias: readonly ["h"];
19
+ readonly description: "Displays help information about the command";
20
+ readonly handler: (value: boolean, opts: FlagOpts) => {
21
+ shouldStop: false;
22
+ } | {
23
+ shouldStop: true;
24
+ };
25
+ };
@@ -0,0 +1,31 @@
1
+ export interface SimilarityResult {
2
+ rating: number;
3
+ target: string;
4
+ }
5
+ export interface BestMatchResult {
6
+ bestMatch: SimilarityResult;
7
+ bestMatchIndex: number;
8
+ ratings: SimilarityResult[];
9
+ }
10
+ /**
11
+ * String similarity calculator using the Jaro-Winkler distance.
12
+ *
13
+ * Jaro-Winkler favors strings that share a common prefix, which matches the
14
+ * shape of CLI typos ("migrat" → "migrate", "user:lis" → "user:list") better
15
+ * than bigram-based metrics like Dice's Coefficient.
16
+ */
17
+ export declare class StringSimilarity {
18
+ /**
19
+ * Calculate Jaro-Winkler similarity between two strings (0-1 scale).
20
+ *
21
+ * A length-ratio guard scales the score down when the inputs differ
22
+ * significantly in length, so that a short query cannot incidentally match
23
+ * a much longer candidate just because a few characters line up.
24
+ */
25
+ calculateSimilarity(str1: string, str2: string): number;
26
+ private jaro;
27
+ /**
28
+ * Find best matching string and ratings for all candidates
29
+ */
30
+ findBestMatch(target: string, candidates: string[]): BestMatchResult;
31
+ }
@@ -0,0 +1,135 @@
1
+ import { custom } from '../flags/custom.js';
2
+ import { optionFlag } from '../flags/option.js';
3
+ /**
4
+ * Builders for positional arguments (`static args = { ... }`).
5
+ *
6
+ * Same surface as {@link Flags} minus `boolean` — booleans don't make sense as
7
+ * positional inputs and the `ArgsSchema` type rejects them at compile time.
8
+ */
9
+ export declare const Args: {
10
+ string: <Ctx extends unknown = any, const O extends Partial<import('../index.js').FlagDefinition<string, import('../index.js').CustomOptions, Ctx>> = Partial<import('../index.js').FlagDefinition<string, import('../index.js').CustomOptions, Ctx>>>(overrides?: O | undefined) => {
11
+ [x: string]: unknown;
12
+ } & {
13
+ parse: (input: any, opts: import('../index.js').FlagOpts<string, import('../index.js').CustomOptions, Ctx>) => string;
14
+ type?: import('../index.js').FlagKind;
15
+ ask?: ((opts: import('../index.js').FlagOpts<string, import('../index.js').CustomOptions, Ctx>) => Promise<any>) | undefined;
16
+ description?: string;
17
+ required?: boolean;
18
+ default?: string | string[] | (() => string | string[] | null) | (() => Promise<string | string[] | null>) | null | undefined;
19
+ multiple?: boolean;
20
+ help?: string;
21
+ alias?: string | readonly string[];
22
+ handler?: ((value: string, opts: import('../index.js').FlagOpts<string, import('../index.js').CustomOptions, Ctx>) => {
23
+ shouldStop: boolean;
24
+ } | void) | undefined;
25
+ } & Partial<import('../index.js').FlagDefinition<string, import('../index.js').CustomOptions, any>> & O;
26
+ number: <Ctx extends unknown = any, const O extends Partial<import('../index.js').FlagDefinition<number, {
27
+ min?: number;
28
+ max?: number;
29
+ }, Ctx>> = Partial<import('../index.js').FlagDefinition<number, {
30
+ min?: number;
31
+ max?: number;
32
+ }, Ctx>>>(overrides?: O | undefined) => {
33
+ min?: number | undefined;
34
+ max?: number | undefined;
35
+ } & {
36
+ parse: (input: any, opts: import('../index.js').FlagOpts<number, {
37
+ min?: number;
38
+ max?: number;
39
+ }, Ctx>) => number;
40
+ type?: import('../index.js').FlagKind;
41
+ ask?: ((opts: import('../index.js').FlagOpts<number, {
42
+ min?: number;
43
+ max?: number;
44
+ }, Ctx>) => Promise<any>) | undefined;
45
+ description?: string;
46
+ required?: boolean;
47
+ default?: number | number[] | (() => number | number[] | null) | (() => Promise<number | number[] | null>) | null | undefined;
48
+ multiple?: boolean;
49
+ help?: string;
50
+ alias?: string | readonly string[];
51
+ handler?: ((value: number, opts: import('../index.js').FlagOpts<number, {
52
+ min?: number;
53
+ max?: number;
54
+ }, Ctx>) => {
55
+ shouldStop: boolean;
56
+ } | void) | undefined;
57
+ } & Partial<import('../index.js').FlagDefinition<number, {
58
+ min?: number;
59
+ max?: number;
60
+ }, any>> & O;
61
+ option: typeof optionFlag;
62
+ file: <Ctx extends unknown = any, const O extends Partial<import('../index.js').FlagDefinition<string, {
63
+ exists?: boolean;
64
+ }, Ctx>> = Partial<import('../index.js').FlagDefinition<string, {
65
+ exists?: boolean;
66
+ }, Ctx>>>(overrides?: O | undefined) => {
67
+ exists?: boolean | undefined;
68
+ } & {
69
+ parse: (input: any, opts: import('../index.js').FlagOpts<string, {
70
+ exists?: boolean;
71
+ }, Ctx>) => string;
72
+ type?: import('../index.js').FlagKind;
73
+ ask?: ((opts: import('../index.js').FlagOpts<string, {
74
+ exists?: boolean;
75
+ }, Ctx>) => Promise<any>) | undefined;
76
+ description?: string;
77
+ required?: boolean;
78
+ default?: string | string[] | (() => string | string[] | null) | (() => Promise<string | string[] | null>) | null | undefined;
79
+ multiple?: boolean;
80
+ help?: string;
81
+ alias?: string | readonly string[];
82
+ handler?: ((value: string, opts: import('../index.js').FlagOpts<string, {
83
+ exists?: boolean;
84
+ }, Ctx>) => {
85
+ shouldStop: boolean;
86
+ } | void) | undefined;
87
+ } & Partial<import('../index.js').FlagDefinition<string, {
88
+ exists?: boolean;
89
+ }, any>> & O;
90
+ directory: <Ctx extends unknown = any, const O extends Partial<import('../index.js').FlagDefinition<string, {
91
+ exists?: boolean;
92
+ }, Ctx>> = Partial<import('../index.js').FlagDefinition<string, {
93
+ exists?: boolean;
94
+ }, Ctx>>>(overrides?: O | undefined) => {
95
+ exists?: boolean | undefined;
96
+ } & {
97
+ parse: (input: any, opts: import('../index.js').FlagOpts<string, {
98
+ exists?: boolean;
99
+ }, Ctx>) => string;
100
+ type?: import('../index.js').FlagKind;
101
+ ask?: ((opts: import('../index.js').FlagOpts<string, {
102
+ exists?: boolean;
103
+ }, Ctx>) => Promise<any>) | undefined;
104
+ description?: string;
105
+ required?: boolean;
106
+ default?: string | string[] | (() => string | string[] | null) | (() => Promise<string | string[] | null>) | null | undefined;
107
+ multiple?: boolean;
108
+ help?: string;
109
+ alias?: string | readonly string[];
110
+ handler?: ((value: string, opts: import('../index.js').FlagOpts<string, {
111
+ exists?: boolean;
112
+ }, Ctx>) => {
113
+ shouldStop: boolean;
114
+ } | void) | undefined;
115
+ } & Partial<import('../index.js').FlagDefinition<string, {
116
+ exists?: boolean;
117
+ }, any>> & O;
118
+ url: <Ctx extends unknown = any, const O extends Partial<import('../index.js').FlagDefinition<URL, import('../index.js').CustomOptions, Ctx>> = Partial<import('../index.js').FlagDefinition<URL, import('../index.js').CustomOptions, Ctx>>>(overrides?: O | undefined) => {
119
+ [x: string]: unknown;
120
+ } & {
121
+ parse: (input: any, opts: import('../index.js').FlagOpts<URL, import('../index.js').CustomOptions, Ctx>) => URL;
122
+ type?: import('../index.js').FlagKind;
123
+ ask?: ((opts: import('../index.js').FlagOpts<URL, import('../index.js').CustomOptions, Ctx>) => Promise<any>) | undefined;
124
+ description?: string;
125
+ required?: boolean;
126
+ default?: URL | URL[] | (() => URL | URL[] | null) | (() => Promise<URL | URL[] | null>) | null | undefined;
127
+ multiple?: boolean;
128
+ help?: string;
129
+ alias?: string | readonly string[];
130
+ handler?: ((value: URL, opts: import('../index.js').FlagOpts<URL, import('../index.js').CustomOptions, Ctx>) => {
131
+ shouldStop: boolean;
132
+ } | void) | undefined;
133
+ } & Partial<import('../index.js').FlagDefinition<URL, import('../index.js').CustomOptions, any>> & O;
134
+ custom: typeof custom;
135
+ };
@@ -1,4 +1,4 @@
1
- import { Logger } from '../Logger.js';
1
+ import { LoggerContract } from '../contracts/index.js';
2
2
  import { BobError } from './BobError.js';
3
3
  import { FlagDefinition } from '../lib/types.js';
4
4
  export type ArgumentProps = {
@@ -6,9 +6,11 @@ export type ArgumentProps = {
6
6
  value?: any;
7
7
  reason?: string;
8
8
  };
9
+ /** Thrown when a positional argument's value cannot be converted by its `parse` function. */
9
10
  export declare class BadCommandArgument extends BobError {
10
11
  readonly detail: ArgumentProps;
11
12
  readonly argDefinition?: FlagDefinition | undefined;
13
+ readonly $type: "BadCommandArgument";
12
14
  constructor(detail: ArgumentProps, argDefinition?: FlagDefinition | undefined);
13
- pretty(logger: Logger): void;
15
+ pretty(logger: LoggerContract): void;
14
16
  }
@@ -1,4 +1,4 @@
1
- import { Logger } from '../Logger.js';
1
+ import { LoggerContract } from '../contracts/index.js';
2
2
  import { BobError } from './BobError.js';
3
3
  import { FlagDefinition } from '../lib/types.js';
4
4
  export type BadFlagParams = {
@@ -6,9 +6,11 @@ export type BadFlagParams = {
6
6
  value?: any;
7
7
  reason?: string;
8
8
  };
9
+ /** Thrown when a flag's value cannot be converted by its `parse` function (validation failure, type mismatch, …). */
9
10
  export declare class BadCommandFlag extends BobError {
10
11
  readonly param: BadFlagParams;
11
12
  readonly flagDefinition?: FlagDefinition | undefined;
13
+ readonly $type: "BadCommandFlag";
12
14
  constructor(param: BadFlagParams, flagDefinition?: FlagDefinition | undefined);
13
- pretty(logger: Logger): void;
15
+ pretty(logger: LoggerContract): void;
14
16
  }
@@ -0,0 +1,13 @@
1
+ import { LoggerContract } from '../contracts/index.js';
2
+ /**
3
+ * Base class for every framework-recognised error.
4
+ *
5
+ * Subclasses are expected to override `$type` with their own literal so the
6
+ * field doubles as a discriminator (useful for telemetry and structured logs).
7
+ * `pretty` renders the error to a {@link LoggerContract}; the dispatch is wired
8
+ * up in {@link ExceptionHandler}.
9
+ */
10
+ export declare abstract class BobError extends Error {
11
+ abstract readonly $type: string;
12
+ abstract pretty(logger: LoggerContract): void;
13
+ }
@@ -0,0 +1,9 @@
1
+ import { LoggerContract } from '../contracts/index.js';
2
+ import { BobError } from './BobError.js';
3
+ /** Thrown by {@link CommandRegistry} when a requested command does not exist and no suggestion was accepted. */
4
+ export declare class CommandNotFoundError extends BobError {
5
+ readonly command: string;
6
+ readonly $type: "CommandNotFoundError";
7
+ constructor(command: string);
8
+ pretty(logger: LoggerContract): void;
9
+ }
@@ -1,9 +1,11 @@
1
- import { Logger } from '../Logger.js';
1
+ import { LoggerContract } from '../contracts/index.js';
2
2
  import { BobError } from './BobError.js';
3
3
  import { FlagsSchema } from '../lib/types.js';
4
+ /** Thrown when an unknown flag is supplied and `allowUnknownFlags` is off. */
4
5
  export declare class InvalidFlag extends BobError {
5
6
  private flag;
6
7
  private flagsSchema;
8
+ readonly $type: "InvalidFlag";
7
9
  constructor(flag: string, flagsSchema?: FlagsSchema);
8
- pretty(logger: Logger): void;
10
+ pretty(logger: LoggerContract): void;
9
11
  }
@@ -0,0 +1,9 @@
1
+ import { LoggerContract } from '../contracts/index.js';
2
+ import { BobError } from './BobError.js';
3
+ /** Thrown when a required positional argument was not provided and no value could be obtained. */
4
+ export declare class MissingRequiredArgumentValue extends BobError {
5
+ readonly argument: string;
6
+ readonly $type: "MissingRequiredArgumentValue";
7
+ constructor(argument: string);
8
+ pretty(logger: LoggerContract): void;
9
+ }
@@ -0,0 +1,9 @@
1
+ import { LoggerContract } from '../contracts/index.js';
2
+ import { BobError } from './BobError.js';
3
+ /** Thrown when a required flag was not provided and no value could be obtained (prompt cancelled or disabled). */
4
+ export declare class MissingRequiredFlagValue extends BobError {
5
+ readonly flag: string;
6
+ readonly $type: "MissingRequiredFlagValue";
7
+ constructor(flag: string);
8
+ pretty(logger: LoggerContract): void;
9
+ }
@@ -0,0 +1,10 @@
1
+ import { LoggerContract } from '../contracts/index.js';
2
+ import { BobError } from './BobError.js';
3
+ /** Thrown in strict mode when more positional arguments were supplied than the schema declares. */
4
+ export declare class TooManyArguments extends BobError {
5
+ readonly expected: number;
6
+ readonly received: number;
7
+ readonly $type: "TooManyArguments";
8
+ constructor(expected: number, received: number);
9
+ pretty(logger: LoggerContract): void;
10
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Raised by `parse`/`ask` validators to signal user-facing input problems.
3
+ *
4
+ * `safeParse` in {@link CommandParser} catches this specifically (and re-wraps
5
+ * it as {@link BadCommandFlag} or {@link BadCommandArgument}) — anything else
6
+ * is treated as a programmer bug and propagates unchanged.
7
+ */
8
+ export declare class ValidationError extends Error {
9
+ constructor(message: string);
10
+ }
@@ -0,0 +1,9 @@
1
+ import { LoggerContract } from '../contracts/index.js';
2
+ export type ErrorDetail = [label: string, value: string];
3
+ export type RenderErrorOptions = {
4
+ title: string;
5
+ details?: ErrorDetail[];
6
+ hint?: string;
7
+ };
8
+ export declare function quote(name: string): string;
9
+ export declare function renderError(logger: LoggerContract, opts: RenderErrorOptions): void;